gwenhywfar 4.0.3
|
00001 /*************************************************************************** 00002 begin : Wed Mar 16 2005 00003 copyright : (C) 2005-2010 by Martin Preuss 00004 email : martin@libchipcard.de 00005 00006 *************************************************************************** 00007 * Please see toplevel file COPYING for license details * 00008 ***************************************************************************/ 00009 00010 #ifdef HAVE_CONFIG_H 00011 # include <config.h> 00012 #endif 00013 00014 #define DISABLE_DEBUGLOG 00015 00016 00017 #include "mdigest_p.h" 00018 #include "i18n_l.h" 00019 00020 #include <gwenhywfar/misc.h> 00021 #include <gwenhywfar/debug.h> 00022 #include <gwenhywfar/directory.h> 00023 #include <gwenhywfar/text.h> 00024 #include <gwenhywfar/syncio.h> 00025 #include <gwenhywfar/syncio_file.h> 00026 #include <gwenhywfar/gui.h> 00027 00028 00029 00030 00031 GWEN_INHERIT_FUNCTIONS(GWEN_MDIGEST) 00032 GWEN_LIST_FUNCTIONS(GWEN_MDIGEST, GWEN_MDigest) 00033 GWEN_LIST2_FUNCTIONS(GWEN_MDIGEST, GWEN_MDigest) 00034 00035 00036 00037 00038 00039 GWEN_MDIGEST *GWEN_MDigest_new(GWEN_CRYPT_HASHALGOID a) { 00040 GWEN_MDIGEST *md; 00041 00042 GWEN_NEW_OBJECT(GWEN_MDIGEST, md) 00043 md->refCount=1; 00044 GWEN_INHERIT_INIT(GWEN_MDIGEST, md) 00045 GWEN_LIST_INIT(GWEN_MDIGEST, md) 00046 00047 md->hashAlgoId=a; 00048 return md; 00049 } 00050 00051 00052 00053 void GWEN_MDigest_free(GWEN_MDIGEST *md) { 00054 if (md) { 00055 assert(md->refCount); 00056 if (md->refCount==1) { 00057 free(md->pDigest); 00058 md->refCount=0; 00059 GWEN_FREE_OBJECT(md); 00060 } 00061 else 00062 md->refCount--; 00063 } 00064 } 00065 00066 00067 00068 GWEN_CRYPT_HASHALGOID GWEN_MDigest_GetHashAlgoId(const GWEN_MDIGEST *md) { 00069 assert(md); 00070 assert(md->refCount); 00071 return md->hashAlgoId; 00072 } 00073 00074 00075 00076 uint8_t *GWEN_MDigest_GetDigestPtr(GWEN_MDIGEST *md) { 00077 assert(md); 00078 assert(md->refCount); 00079 return md->pDigest; 00080 } 00081 00082 00083 00084 unsigned int GWEN_MDigest_GetDigestSize(GWEN_MDIGEST *md) { 00085 assert(md); 00086 assert(md->refCount); 00087 return md->lDigest; 00088 } 00089 00090 00091 00092 void GWEN_MDigest_SetDigestBuffer(GWEN_MDIGEST *md, uint8_t *buf, unsigned int l) { 00093 assert(md); 00094 assert(md->refCount); 00095 00096 if (l) { 00097 assert(buf); 00098 } 00099 00100 if (md->pDigest && md->lDigest) 00101 free(md->pDigest); 00102 md->pDigest=buf; 00103 md->lDigest=l; 00104 } 00105 00106 00107 00108 void GWEN_MDigest_SetDigestLen(GWEN_MDIGEST *md, unsigned int l) { 00109 assert(md); 00110 assert(md->refCount); 00111 00112 if (md->pDigest && md->lDigest) 00113 free(md->pDigest); 00114 md->pDigest=NULL; 00115 md->lDigest=l; 00116 } 00117 00118 00119 00120 int GWEN_MDigest_Begin(GWEN_MDIGEST *md) { 00121 assert(md); 00122 assert(md->refCount); 00123 if (md->beginFn) 00124 return md->beginFn(md); 00125 else 00126 return GWEN_ERROR_NOT_IMPLEMENTED; 00127 } 00128 00129 00130 00131 int GWEN_MDigest_End(GWEN_MDIGEST *md) { 00132 assert(md); 00133 assert(md->refCount); 00134 if (md->endFn) 00135 return md->endFn(md); 00136 else 00137 return GWEN_ERROR_NOT_IMPLEMENTED; 00138 } 00139 00140 00141 00142 int GWEN_MDigest_Update(GWEN_MDIGEST *md, const uint8_t *buf, unsigned int l) { 00143 assert(md); 00144 assert(md->refCount); 00145 if (md->updateFn) 00146 return md->updateFn(md, buf, l); 00147 else 00148 return GWEN_ERROR_NOT_IMPLEMENTED; 00149 } 00150 00151 00152 00153 GWEN_MDIGEST_BEGIN_FN GWEN_MDigest_SetBeginFn(GWEN_MDIGEST *md, GWEN_MDIGEST_BEGIN_FN f) { 00154 GWEN_MDIGEST_BEGIN_FN of; 00155 00156 assert(md); 00157 assert(md->refCount); 00158 of=md->beginFn; 00159 md->beginFn=f; 00160 00161 return of; 00162 } 00163 00164 00165 00166 GWEN_MDIGEST_END_FN GWEN_MDigest_SetEndFn(GWEN_MDIGEST *md, GWEN_MDIGEST_END_FN f) { 00167 GWEN_MDIGEST_END_FN of; 00168 00169 assert(md); 00170 assert(md->refCount); 00171 of=md->endFn; 00172 md->endFn=f; 00173 00174 return of; 00175 } 00176 00177 00178 00179 GWEN_MDIGEST_UPDATE_FN GWEN_MDigest_SetUpdateFn(GWEN_MDIGEST *md, GWEN_MDIGEST_UPDATE_FN f) { 00180 GWEN_MDIGEST_UPDATE_FN of; 00181 00182 assert(md); 00183 assert(md->refCount); 00184 of=md->updateFn; 00185 md->updateFn=f; 00186 00187 return of; 00188 } 00189 00190 00191 00192 int GWEN_MDigest_PBKDF2(GWEN_MDIGEST *md, 00193 const char *password, 00194 const uint8_t *pSalt, 00195 uint32_t lSalt, 00196 uint8_t *pKey, 00197 uint32_t lKey, 00198 uint32_t iterations) { 00199 int rv; 00200 uint8_t hash[128]; 00201 uint32_t hsize; 00202 uint32_t i; 00203 00204 hsize=GWEN_MDigest_GetDigestSize(md); 00205 if (lKey>hsize || lKey>sizeof(hash)) { 00206 DBG_ERROR(GWEN_LOGDOMAIN, "Derived key too long"); 00207 return GWEN_ERROR_INVALID; 00208 } 00209 00210 rv=GWEN_MDigest_Begin(md); 00211 if (rv<0) { 00212 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00213 GWEN_MDigest_End(md); 00214 return rv; 00215 } 00216 00217 /* hash password */ 00218 rv=GWEN_MDigest_Update(md, (const uint8_t*) password, strlen(password)); 00219 if (rv<0) { 00220 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00221 GWEN_MDigest_End(md); 00222 return rv; 00223 } 00224 00225 /* hash salt */ 00226 rv=GWEN_MDigest_Update(md, pSalt, lSalt); 00227 if (rv<0) { 00228 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00229 GWEN_MDigest_End(md); 00230 return rv; 00231 } 00232 00233 rv=GWEN_MDigest_End(md); 00234 if (rv<0) { 00235 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00236 GWEN_MDigest_End(md); 00237 return rv; 00238 } 00239 00240 /* use that hash now for the iterations */ 00241 memmove(hash, GWEN_MDigest_GetDigestPtr(md), hsize); 00242 00243 for (i=2; i<iterations; i++) { 00244 rv=GWEN_MDigest_Begin(md); 00245 if (rv<0) { 00246 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00247 GWEN_MDigest_End(md); 00248 return rv; 00249 } 00250 rv=GWEN_MDigest_Update(md, hash, hsize); 00251 if (rv<0) { 00252 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00253 GWEN_MDigest_End(md); 00254 return rv; 00255 } 00256 00257 rv=GWEN_MDigest_End(md); 00258 if (rv<0) { 00259 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00260 GWEN_MDigest_End(md); 00261 return rv; 00262 } 00263 00264 /* use that hash now for the next iteration */ 00265 memmove(hash, GWEN_MDigest_GetDigestPtr(md), hsize); 00266 } 00267 00268 /* done, copy key */ 00269 memmove(pKey, hash, lKey); 00270 memset(hash, 0, sizeof(hash)); 00271 00272 return 0; 00273 } 00274 00275 00276 00277 static int GWEN_MDigest__HashFile(GWEN_MDIGEST *md, 00278 const char *fname, 00279 GWEN_BUFFER *hbuf) { 00280 GWEN_SYNCIO *sio; 00281 int rv; 00282 uint8_t buffer[1024]; 00283 00284 sio=GWEN_SyncIo_File_new(fname, GWEN_SyncIo_File_CreationMode_OpenExisting); 00285 GWEN_SyncIo_SetFlags(sio, GWEN_SYNCIO_FILE_FLAGS_READ); 00286 rv=GWEN_SyncIo_Connect(sio); 00287 if (rv<0) { 00288 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00289 GWEN_SyncIo_free(sio); 00290 return rv; 00291 } 00292 00293 rv=GWEN_MDigest_Begin(md); 00294 if (rv<0) { 00295 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00296 GWEN_SyncIo_Disconnect(sio); 00297 GWEN_SyncIo_free(sio); 00298 return rv; 00299 } 00300 00301 while(1) { 00302 rv=GWEN_SyncIo_Read(sio, buffer, sizeof(buffer)); 00303 if (rv<0) { 00304 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00305 GWEN_SyncIo_Disconnect(sio); 00306 GWEN_SyncIo_free(sio); 00307 return rv; 00308 } 00309 else if (rv==0) 00310 break; 00311 else { 00312 rv=GWEN_MDigest_Update(md, (const uint8_t*) buffer, rv); 00313 if (rv<0) { 00314 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00315 GWEN_SyncIo_Disconnect(sio); 00316 GWEN_SyncIo_free(sio); 00317 return rv; 00318 } 00319 } 00320 } 00321 00322 rv=GWEN_MDigest_End(md); 00323 if (rv<0) { 00324 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00325 GWEN_SyncIo_Disconnect(sio); 00326 GWEN_SyncIo_free(sio); 00327 return rv; 00328 } 00329 00330 GWEN_SyncIo_Disconnect(sio); 00331 GWEN_SyncIo_free(sio); 00332 00333 rv=GWEN_Text_ToHexBuffer((const char*) GWEN_MDigest_GetDigestPtr(md), 00334 GWEN_MDigest_GetDigestSize(md), 00335 hbuf, 0, 0, 0); 00336 if (rv<0) { 00337 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00338 return rv; 00339 } 00340 00341 return 0; 00342 } 00343 00344 00345 00346 static int GWEN_MDigest__HashFileTree(GWEN_MDIGEST *md, 00347 const char *baseFolder, 00348 const char *relFolder, 00349 const char *ignoreFile, 00350 GWEN_STRINGLIST *sl) { 00351 GWEN_STRINGLIST *files; 00352 GWEN_STRINGLISTENTRY *se; 00353 GWEN_BUFFER *pbuf; 00354 uint32_t ppos; 00355 uint32_t rpos; 00356 int rv; 00357 00358 files=GWEN_StringList_new(); 00359 pbuf=GWEN_Buffer_new(0, 256, 0, 1); 00360 GWEN_Buffer_AppendString(pbuf, baseFolder); 00361 GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S); 00362 rpos=GWEN_Buffer_GetPos(pbuf); 00363 if (relFolder) { 00364 GWEN_Buffer_AppendString(pbuf, relFolder); 00365 GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S); 00366 } 00367 ppos=GWEN_Buffer_GetPos(pbuf); 00368 00369 rv=GWEN_Directory_GetFileEntriesWithType(GWEN_Buffer_GetStart(pbuf), files, NULL); 00370 if (rv<0) { 00371 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00372 GWEN_Buffer_free(pbuf); 00373 GWEN_StringList_free(files); 00374 return rv; 00375 } 00376 00377 se=GWEN_StringList_FirstEntry(files); 00378 while(se) { 00379 const char *s; 00380 00381 s=GWEN_StringListEntry_Data(se); 00382 if (s && *s) { 00383 GWEN_Buffer_AppendString(pbuf, s+1); 00384 if (*s=='d') { 00385 if (strcasecmp(s+1, ".")!=0 && strcasecmp(s+1, "..")!=0) { 00386 rv=GWEN_MDigest__HashFileTree(md, 00387 baseFolder, 00388 GWEN_Buffer_GetStart(pbuf)+rpos, 00389 ignoreFile, 00390 sl); 00391 if (rv<0) { 00392 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00393 GWEN_Buffer_free(pbuf); 00394 GWEN_StringList_free(files); 00395 return rv; 00396 } 00397 } 00398 } 00399 else if (*s=='f') { 00400 if (!(ignoreFile && strcasecmp(ignoreFile, s+1)==0)) { 00401 GWEN_BUFFER *tbuf; 00402 00403 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00404 00405 /* add relative path to line buffer */ 00406 GWEN_Buffer_AppendString(tbuf, "F"); 00407 rv=GWEN_Text_EscapeToBuffer(GWEN_Buffer_GetStart(pbuf)+rpos, tbuf); 00408 if (rv<0) { 00409 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00410 GWEN_Buffer_free(tbuf); 00411 GWEN_Buffer_free(pbuf); 00412 GWEN_StringList_free(files); 00413 return rv; 00414 } 00415 GWEN_Buffer_AppendString(tbuf, ":"); 00416 00417 /* hash file */ 00418 rv=GWEN_MDigest__HashFile(md, GWEN_Buffer_GetStart(pbuf), tbuf); 00419 if (rv<0) { 00420 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00421 GWEN_Buffer_free(tbuf); 00422 GWEN_Buffer_free(pbuf); 00423 GWEN_StringList_free(files); 00424 return rv; 00425 } 00426 00427 /* append line to stringlist */ 00428 GWEN_StringList_AppendString(sl, GWEN_Buffer_GetStart(tbuf), 0, 0); 00429 GWEN_Buffer_free(tbuf); 00430 } 00431 } 00432 else { 00433 DBG_INFO(GWEN_LOGDOMAIN, "Unknown file type in [%s]", s); 00434 } 00435 GWEN_Buffer_Crop(pbuf, 0, ppos); 00436 } 00437 se=GWEN_StringListEntry_Next(se); 00438 } 00439 00440 GWEN_Buffer_free(pbuf); 00441 GWEN_StringList_free(files); 00442 return 0; 00443 } 00444 00445 00446 00447 int GWEN_MDigest_HashFileTree(GWEN_MDIGEST *md, 00448 const char *folder, 00449 const char *ignoreFile, 00450 GWEN_STRINGLIST *sl) { 00451 int rv; 00452 00453 rv=GWEN_MDigest__HashFileTree(md, folder, NULL, ignoreFile, sl); 00454 if (rv<0) { 00455 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00456 return rv; 00457 } 00458 00459 return 0; 00460 } 00461 00462 00463 00464 int GWEN_MDigest_CheckFileTree(GWEN_MDIGEST *md, 00465 const char *folder, 00466 const char *checksumFile, 00467 int strictCheck, 00468 uint32_t pid) { 00469 GWEN_STRINGLIST *sl; 00470 GWEN_STRINGLIST *savedList; 00471 GWEN_BUFFER *tbuf; 00472 GWEN_STRINGLISTENTRY *se; 00473 int rv; 00474 int allHashesOk=1; 00475 int validLines=0; 00476 00477 sl=GWEN_StringList_new(); 00478 00479 /* generate hash list */ 00480 rv=GWEN_MDigest_HashFileTree(md, folder, checksumFile, sl); 00481 if (rv<0) { 00482 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error, 00483 I18N("Error unpacking program (%d)"), rv); 00484 GWEN_StringList_free(sl); 00485 return rv; 00486 } 00487 00488 savedList=GWEN_StringList_new(); 00489 00490 /* read checksums from file */ 00491 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00492 GWEN_Buffer_AppendString(tbuf, folder); 00493 GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S); 00494 GWEN_Buffer_AppendString(tbuf, checksumFile); 00495 rv=GWEN_SyncIo_Helper_ReadFileToStringList(GWEN_Buffer_GetStart(tbuf), 00496 -1, 00497 savedList); 00498 if (rv<0) { 00499 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error, 00500 I18N("Error loading checksum file (%d)"), rv); 00501 GWEN_Buffer_free(tbuf); 00502 GWEN_StringList_free(savedList); 00503 GWEN_StringList_free(sl); 00504 return rv; 00505 } 00506 GWEN_Buffer_free(tbuf); 00507 00508 /* check checksums */ 00509 se=GWEN_StringList_FirstEntry(savedList); 00510 while(se) { 00511 const char *s; 00512 00513 s=GWEN_StringListEntry_Data(se); 00514 if (s && *s) { 00515 validLines++; 00516 if (0==GWEN_StringList_RemoveString(sl, s)) { 00517 DBG_ERROR(0, "Hash not found: %s", s); 00518 allHashesOk=0; 00519 } 00520 } 00521 se=GWEN_StringListEntry_Next(se); 00522 } 00523 00524 if (validLines==0) { 00525 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error, 00526 I18N("Checksum file does not contain valid lines")); 00527 GWEN_StringList_free(savedList); 00528 GWEN_StringList_free(sl); 00529 return GWEN_ERROR_VERIFY; 00530 } 00531 00532 if (allHashesOk==0) { 00533 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error, 00534 I18N("Integrity check on folder failed")); 00535 GWEN_StringList_free(savedList); 00536 GWEN_StringList_free(sl); 00537 return GWEN_ERROR_VERIFY; 00538 } 00539 00540 /* check for additional files */ 00541 if (GWEN_StringList_Count(sl)) { 00542 if (strictCheck) { 00543 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error, 00544 I18N("Folder contains %d files without checksum"), 00545 GWEN_StringList_Count(sl)); 00546 GWEN_StringList_free(savedList); 00547 GWEN_StringList_free(sl); 00548 } 00549 else 00550 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Warning, 00551 I18N("Folder contains %d files without checksum"), 00552 GWEN_StringList_Count(sl)); 00553 } 00554 GWEN_StringList_free(savedList); 00555 GWEN_StringList_free(sl); 00556 00557 return 0; 00558 } 00559 00560 00561 00562 00563 00564