|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32base.h> |
|
20 #include <f32file.h> |
|
21 |
|
22 #include <hash.h> // CryptoHW (md5hash) |
|
23 |
|
24 #include "T_DataVerify.h" |
|
25 |
|
26 |
|
27 |
|
28 /*@{*/ |
|
29 //Command LIT's |
|
30 _LIT(KCmdVerifyData, "VerifyData"); |
|
31 /*@}*/ |
|
32 |
|
33 /*@{*/ |
|
34 //LIT's for reading params from ini file |
|
35 _LIT( KDataVerifyType, "VerifyType" ); |
|
36 _LIT( KDataVerifyFile, "VerifyFile" ); |
|
37 _LIT( KChecksum, "Checksum" ); |
|
38 _LIT( KMD5Type, "MD5" ); // Use MD5 with data verify |
|
39 /*@}*/ |
|
40 |
|
41 |
|
42 namespace DataVerify |
|
43 { |
|
44 const TInt KMD5Size = 32; |
|
45 const TInt KMD5length = 32; |
|
46 const TInt KBufsize = 512; |
|
47 const TInt KCharlength = 2; |
|
48 } |
|
49 |
|
50 typedef TBuf8<DataVerify::KMD5length> THashBuf; |
|
51 |
|
52 CT_DataVerify::CT_DataVerify(): |
|
53 iMD5(NULL) |
|
54 { |
|
55 } |
|
56 |
|
57 CT_DataVerify* CT_DataVerify::NewL() |
|
58 { |
|
59 CT_DataVerify* ret = new (ELeave) CT_DataVerify(); |
|
60 CleanupStack::PushL(ret); |
|
61 ret->ConstructL(); |
|
62 CleanupStack::Pop(ret); |
|
63 return ret; |
|
64 } |
|
65 |
|
66 CT_DataVerify::~CT_DataVerify() |
|
67 { |
|
68 iFs.Close(); |
|
69 if(iMD5) |
|
70 { |
|
71 delete iMD5; |
|
72 iMD5 = NULL; |
|
73 } |
|
74 } |
|
75 |
|
76 void CT_DataVerify::ConstructL() |
|
77 { |
|
78 User::LeaveIfError( iFs.Connect() ); |
|
79 iMD5 = CMD5::NewL(); |
|
80 } |
|
81 |
|
82 TAny* CT_DataVerify::GetObject() |
|
83 { |
|
84 return NULL; |
|
85 } |
|
86 |
|
87 TBool CT_DataVerify::DoCommandL(const TTEFFunction& aCommand, const TTEFSectionName& aSection, const TInt /*aAsyncErrorIndex*/) |
|
88 { |
|
89 TBool retVal=ETrue; |
|
90 |
|
91 if (aCommand==KCmdVerifyData) |
|
92 { |
|
93 DoCmdVerifyData(aSection); |
|
94 } |
|
95 else |
|
96 { |
|
97 ERR_PRINTF1(_L("Unknown command")); |
|
98 retVal=EFalse; |
|
99 } |
|
100 |
|
101 return retVal; |
|
102 } |
|
103 |
|
104 |
|
105 /** |
|
106 * Verifies that the downloaded file is not corrupted by using a previously calculated checksum. |
|
107 * @param aSection - The section in config file to look for the Data Verify Type, the file to verify and the checksum. |
|
108 * @return error - Error code. KErrNone if checksum is equal. |
|
109 */ |
|
110 void CT_DataVerify::DoCmdVerifyData(const TTEFSectionName& aSection) |
|
111 { |
|
112 INFO_PRINTF1(_L("*START* CT_TransferData::DoCmdVerifyData")); |
|
113 |
|
114 TBool dataOk =ETrue; |
|
115 TPtrC type; |
|
116 if(!GetStringFromConfig(aSection, KDataVerifyType, type )) |
|
117 { |
|
118 ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KDataVerifyType); |
|
119 SetBlockResult(EFail); |
|
120 dataOk = EFalse; |
|
121 } |
|
122 |
|
123 TPtrC filename; |
|
124 if(!GetStringFromConfig(aSection, KDataVerifyFile, filename )) |
|
125 { |
|
126 ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KDataVerifyFile); |
|
127 SetBlockResult(EFail); |
|
128 dataOk = EFalse; |
|
129 } |
|
130 |
|
131 TPtrC checksumParameter; |
|
132 if(!GetStringFromConfig(aSection, KChecksum, checksumParameter )) |
|
133 { |
|
134 ERR_PRINTF2(_L("Error in getting parameter %S from INI file"), &KChecksum); |
|
135 SetBlockResult(EFail); |
|
136 dataOk = EFalse; |
|
137 } |
|
138 if(dataOk) |
|
139 { |
|
140 TBuf8<DataVerify::KMD5Size> checksum; |
|
141 checksum.Append(checksumParameter); |
|
142 |
|
143 if (type == KMD5Type) |
|
144 { |
|
145 INFO_PRINTF1(_L("MD5 selected")); |
|
146 TRAPD(error, VerifyChecksumL(checksum, filename)); |
|
147 if (error == KErrNone) |
|
148 { |
|
149 INFO_PRINTF1(_L("Data verify succeeded")); |
|
150 } |
|
151 else |
|
152 { |
|
153 ERR_PRINTF2(_L("VerifyData failed [%d]"), error); |
|
154 SetError(error); |
|
155 } |
|
156 } |
|
157 } |
|
158 |
|
159 |
|
160 INFO_PRINTF1(_L("*END* CT_TransferData::DoCmdVerifyData")); |
|
161 } |
|
162 |
|
163 |
|
164 /** |
|
165 * Verify Data integrity |
|
166 * |
|
167 * @param aMethod The verification method |
|
168 * @param aFileName File to verify |
|
169 * @param aChecksum Checksum |
|
170 * |
|
171 * @return N/A |
|
172 * |
|
173 * @leave System wide error |
|
174 */ |
|
175 void CT_DataVerify::VerifyData( const TDataVerifyMethod aMethod, const TFileName& aFileName, const TDesC& aChecksum ) |
|
176 { |
|
177 TBool dataOk = ETrue; |
|
178 |
|
179 if( aFileName.Length() > KMaxFileName) |
|
180 { |
|
181 ERR_PRINTF2(_L("Illegal filename: %S"), &aFileName); |
|
182 SetBlockResult(EFail); |
|
183 dataOk = EFalse; |
|
184 } |
|
185 if(dataOk) |
|
186 { |
|
187 THashBuf checksum; |
|
188 checksum.Append( aChecksum ); |
|
189 |
|
190 // Use MD5 to verify file |
|
191 if( aMethod == EDataVerifyMethodMD5 ) |
|
192 { |
|
193 // MD5 selected |
|
194 TRAPD(error, VerifyChecksumL( checksum, aFileName )); |
|
195 if(error == KErrNone) |
|
196 { |
|
197 INFO_PRINTF1(_L("Data verify succeeded.")); |
|
198 } |
|
199 else |
|
200 { |
|
201 ERR_PRINTF2(_L("Checksum verification left with error %d"), error); |
|
202 SetBlockResult(EFail); |
|
203 } |
|
204 } |
|
205 else |
|
206 { |
|
207 ERR_PRINTF1(_L("Verification method not supported")); |
|
208 SetBlockResult(EFail); |
|
209 } |
|
210 } |
|
211 } |
|
212 |
|
213 /** |
|
214 * Verify File integrity |
|
215 * |
|
216 * @param aReferenceFileName Reference file against to verify integrity |
|
217 * @param aDataFileName File to verify |
|
218 * |
|
219 * @return N/A |
|
220 * |
|
221 * @leave System wide error |
|
222 */ |
|
223 void CT_DataVerify::VerifyFileL( const TFileName& aReferenceFileName, const TFileName& aDataFileName ) |
|
224 { |
|
225 THashBuf refHash; |
|
226 |
|
227 // hash the first file |
|
228 HashFileL( aReferenceFileName, refHash ); |
|
229 |
|
230 THashBuf dataHash; |
|
231 // hash the second file |
|
232 HashFileL( aDataFileName, dataHash ); |
|
233 |
|
234 // compare hashes together |
|
235 if( !CompareBuffers( refHash, dataHash ) ) |
|
236 { |
|
237 // Data was corrupted |
|
238 User::Leave( KErrCorrupt ); |
|
239 } |
|
240 } |
|
241 |
|
242 /** |
|
243 * Verify Buffer integrity |
|
244 * |
|
245 * @param aReferenceFileName Reference file against to verify integrity |
|
246 * @param aData Buffer to verify |
|
247 * |
|
248 * @return N/A |
|
249 * |
|
250 * @leave System wide error |
|
251 */ |
|
252 void CT_DataVerify::VerifyBufferL( const TFileName& aReferenceFileName, const TDesC8& aData ) |
|
253 { |
|
254 HBufC8* refdata = 0; |
|
255 TPtr8 ptr = refdata->Des(); |
|
256 // read file into buffer, file must fit into HBufC8 |
|
257 ReadFileL( aReferenceFileName, ptr ); |
|
258 |
|
259 // compare read file with given buffer |
|
260 if( !CompareBuffers( refdata->Des(), aData ) ) |
|
261 { |
|
262 // Data was corrupted |
|
263 User::Leave( KErrCorrupt ); |
|
264 } |
|
265 } |
|
266 |
|
267 /** |
|
268 * Verify Buffer integrity |
|
269 * |
|
270 * @param aReferenceBuffer Reference buffer against to verify integrity |
|
271 * @param aData Buffer to verify |
|
272 * |
|
273 * @return N/A |
|
274 * |
|
275 * @leave System wide error |
|
276 */ |
|
277 void CT_DataVerify::VerifyBufferL( const TDesC8& aReferenceData, const TDesC8& aData ) |
|
278 { |
|
279 // Compare buffers |
|
280 if ( !CompareBuffers( aReferenceData, aData ) ) |
|
281 { |
|
282 // Data was corrupted |
|
283 User::Leave( KErrCorrupt ); |
|
284 } |
|
285 } |
|
286 |
|
287 /** |
|
288 * Verify Checksum integrity |
|
289 * |
|
290 * @param aReferenceMD5Checksum Reference checksum |
|
291 * @param aDataFileName File to verify |
|
292 * |
|
293 * @return N/A |
|
294 * |
|
295 * @leave System wide error |
|
296 */ |
|
297 void CT_DataVerify::VerifyChecksumL( const TDesC8& aReferenceMD5Checksum, const TFileName& aDataFileName ) |
|
298 { |
|
299 // MD5 checksum is always 128 bit (32 char) long |
|
300 if( aReferenceMD5Checksum.Length() != DataVerify::KMD5length ) |
|
301 { |
|
302 User::Leave( KErrBadDescriptor ); |
|
303 } |
|
304 |
|
305 THashBuf hash; |
|
306 // hash file |
|
307 HashFileL( aDataFileName, hash ); |
|
308 |
|
309 // converting MD5 checksum to binary is necessary because Hash() function |
|
310 // returns hash in binary format and reference checksum given in parameter |
|
311 // is a 32 character long string |
|
312 THashBuf conversion; |
|
313 ConvertString2HexL( aReferenceMD5Checksum, conversion ); |
|
314 |
|
315 if( !CompareBuffers( conversion, hash ) ) |
|
316 { |
|
317 // Data was corrupted |
|
318 User::Leave( KErrCorrupt ); |
|
319 } |
|
320 } |
|
321 |
|
322 /** |
|
323 * Verify Checksum integrity |
|
324 * |
|
325 * @param aReferenceMD5Checksum Reference checksum |
|
326 * @param aData Data to verify |
|
327 * |
|
328 * @return N/A |
|
329 * |
|
330 * @leave System wide error |
|
331 */ |
|
332 void CT_DataVerify::VerifyChecksumL( const TDesC8& aReferenceMD5Checksum, const TDesC8& aData ) |
|
333 { |
|
334 // MD5 checksum is always 128 bit (32 char) long |
|
335 if( aReferenceMD5Checksum.Length() != DataVerify::KMD5length ) |
|
336 { |
|
337 // MD5 Checksum was not correct length (32 characters) |
|
338 User::Leave( KErrBadDescriptor ); |
|
339 } |
|
340 |
|
341 // hash the given buffer |
|
342 TPtrC8 hash = iMD5->Hash(aData); |
|
343 |
|
344 // converting MD5 checksum to binary is necessary because Hash() function |
|
345 // returns hash in binary format and reference checksum given in parameter |
|
346 // is a 32 character long string |
|
347 THashBuf conversion; |
|
348 ConvertString2HexL( aReferenceMD5Checksum, conversion ); |
|
349 |
|
350 // Compare hashs together |
|
351 if( !CompareBuffers( conversion, hash ) ) |
|
352 { |
|
353 // Data was corrupted |
|
354 User::Leave( KErrCorrupt ); |
|
355 } |
|
356 } |
|
357 |
|
358 /** |
|
359 * Compare Buffers |
|
360 * |
|
361 * @param aReferenceBuffer Reference buffer |
|
362 * @param aDataBuffer Buffer to compare |
|
363 * |
|
364 * @return ETrue if buffer contents match |
|
365 */ |
|
366 TBool CT_DataVerify::CompareBuffers( const TDesC8& aReferenceBuffer, const TDesC8& aDataBuffer ) |
|
367 { |
|
368 TBool res = EFalse; |
|
369 TInt result = aReferenceBuffer.Compare( aDataBuffer ); |
|
370 |
|
371 if( result == 0 ) |
|
372 { |
|
373 // Buffer contents match |
|
374 res = ETrue; |
|
375 } |
|
376 return res; |
|
377 } |
|
378 |
|
379 /** |
|
380 * Read File |
|
381 * |
|
382 * @param aFileName File name to read |
|
383 * @param aBuf Buffer to read file content |
|
384 * |
|
385 * @return N/A |
|
386 * |
|
387 * @leave System wide error |
|
388 */ |
|
389 void CT_DataVerify::ReadFileL(const TFileName& aFileName, TDes8& aBuf) |
|
390 { |
|
391 RFile file; |
|
392 User::LeaveIfError( file.Open( iFs, aFileName, EFileRead ) ); |
|
393 CleanupClosePushL( file ); |
|
394 |
|
395 // Get the file size |
|
396 TInt size; |
|
397 User::LeaveIfError( file.Size( size ) ); |
|
398 |
|
399 // allocate memory from heap for file content |
|
400 HBufC8* buf = HBufC8::NewLC( size ); |
|
401 aBuf = buf->Des(); |
|
402 |
|
403 // read file content into buffer, file may be too big for HBufC8 |
|
404 User::LeaveIfError( file.Read( aBuf ) ); |
|
405 |
|
406 CleanupStack::Pop( buf ); |
|
407 CleanupStack::PopAndDestroy( &file ); // file.Close |
|
408 } |
|
409 |
|
410 /** |
|
411 * Hash file in pieces |
|
412 * |
|
413 * @param aFileName File name to be hashed |
|
414 * @param aDes Hash value |
|
415 * |
|
416 * @return N/A |
|
417 * |
|
418 * @leave System wide error |
|
419 */ |
|
420 void CT_DataVerify::HashFileL( const TFileName& aFileName, TDes8& aDes ) |
|
421 { |
|
422 RFile file; |
|
423 User::LeaveIfError( file.Open( iFs, aFileName, EFileRead ) ); |
|
424 CleanupClosePushL( file ); |
|
425 |
|
426 TBuf8<DataVerify::KBufsize> buf; |
|
427 |
|
428 TInt error = KErrNone; |
|
429 iMD5->Reset(); |
|
430 // File can be hashed in pieces |
|
431 while( error == KErrNone ) // loop until something goes wrong |
|
432 { |
|
433 error = file.Read( buf, DataVerify::KBufsize ); |
|
434 if( buf.Length() != 0 ) |
|
435 { |
|
436 // MD5 checksum is calculated in pieces |
|
437 iMD5->Update(buf); |
|
438 } |
|
439 else |
|
440 { |
|
441 // file ended, end loop |
|
442 break; |
|
443 } |
|
444 } |
|
445 // Return calculated MD5 checksum |
|
446 aDes = iMD5->Final(); |
|
447 |
|
448 CleanupStack::PopAndDestroy(&file); // file.Close |
|
449 } |
|
450 |
|
451 /** |
|
452 * Write File |
|
453 * |
|
454 * @param aFileName File name |
|
455 * @param aData Data to be written into file name. |
|
456 * |
|
457 * @return N/A |
|
458 * |
|
459 * @leave System wide error |
|
460 */ |
|
461 void CT_DataVerify::WriteFileL( const TFileName& aFileName, const TDesC8& aData ) |
|
462 { |
|
463 RFile file; |
|
464 // Create file, replace if exists |
|
465 User::LeaveIfError( file.Replace( iFs, aFileName, EFileWrite|EFileStream ) ); |
|
466 CleanupClosePushL( file ); |
|
467 // Write data into file |
|
468 User::LeaveIfError( file.Write( aData ) ); |
|
469 // Commit write |
|
470 User::LeaveIfError( file.Flush() ); |
|
471 |
|
472 CleanupStack::PopAndDestroy( &file ); // file.Close |
|
473 } |
|
474 |
|
475 /** |
|
476 * Convert a string to Hexadecimal |
|
477 * |
|
478 * @param aData String descriptor |
|
479 * @param aDes Descriptor where Hex value is stored |
|
480 * |
|
481 * @return N/A |
|
482 * |
|
483 * @leave System wide error |
|
484 */ |
|
485 void CT_DataVerify::ConvertString2HexL( const TDesC8& aData, TDes8& aDes ) |
|
486 { |
|
487 TBuf8<DataVerify::KCharlength> charBuf; |
|
488 |
|
489 // Check that buffer is even number |
|
490 if( ( aData.Length() % DataVerify::KCharlength ) != 0 ) |
|
491 { |
|
492 User::Leave( KErrBadDescriptor ); |
|
493 } |
|
494 |
|
495 // Go through the data and convert it two characters at a time |
|
496 // buffer overflow does not occur because buffer is checked to be even number first |
|
497 for( TInt i = 0, limit = aData.Length()-DataVerify::KCharlength; i <= limit; i+=DataVerify::KCharlength ) |
|
498 { |
|
499 // Clean char buffer first |
|
500 charBuf.Delete( 0, charBuf.Length() ); |
|
501 |
|
502 // Add KCharlength characters into buffer |
|
503 for ( TInt j = 0; j < DataVerify::KCharlength; j++ ) |
|
504 { |
|
505 charBuf.Append( aData[i+j] ); |
|
506 } |
|
507 |
|
508 TUint number; |
|
509 TLex8 converter = TLex8( charBuf ); |
|
510 // Two characters together represent a hex number in MD5 checksum |
|
511 User::LeaveIfError( converter.Val( number, EHex ) ); |
|
512 |
|
513 aDes.Append( number ); |
|
514 } |
|
515 } |
|
516 |