00001
00002
00003
00004
00005
00006
00007
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
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
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
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
00265 memmove(hash, GWEN_MDigest_GetDigestPtr(md), hsize);
00266 }
00267
00268
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 GWEN_BUFFER *xbuf;
00403 char *p;
00404
00405 xbuf=GWEN_Buffer_new(0, 256, 0, 1);
00406 GWEN_Buffer_AppendString(xbuf, GWEN_Buffer_GetStart(pbuf)+rpos);
00407 p=GWEN_Buffer_GetStart(xbuf);
00408 while(*p) {
00409 if (*p=='\\')
00410 *p='/';
00411 p++;
00412 }
00413
00414 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00415
00416
00417 GWEN_Buffer_AppendString(tbuf, "F");
00418 rv=GWEN_Text_EscapeToBuffer(GWEN_Buffer_GetStart(xbuf), tbuf);
00419 GWEN_Buffer_free(xbuf);
00420 if (rv<0) {
00421 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00422 GWEN_Buffer_free(tbuf);
00423 GWEN_Buffer_free(pbuf);
00424 GWEN_StringList_free(files);
00425 return rv;
00426 }
00427 GWEN_Buffer_AppendString(tbuf, ":");
00428
00429
00430 rv=GWEN_MDigest__HashFile(md, GWEN_Buffer_GetStart(pbuf), tbuf);
00431 if (rv<0) {
00432 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00433 GWEN_Buffer_free(tbuf);
00434 GWEN_Buffer_free(pbuf);
00435 GWEN_StringList_free(files);
00436 return rv;
00437 }
00438
00439
00440 GWEN_StringList_AppendString(sl, GWEN_Buffer_GetStart(tbuf), 0, 0);
00441 GWEN_Buffer_free(tbuf);
00442 }
00443 }
00444 else {
00445 DBG_INFO(GWEN_LOGDOMAIN, "Unknown file type in [%s]", s);
00446 }
00447 GWEN_Buffer_Crop(pbuf, 0, ppos);
00448 }
00449 se=GWEN_StringListEntry_Next(se);
00450 }
00451
00452 GWEN_Buffer_free(pbuf);
00453 GWEN_StringList_free(files);
00454 return 0;
00455 }
00456
00457
00458
00459 int GWEN_MDigest_HashFileTree(GWEN_MDIGEST *md,
00460 const char *folder,
00461 const char *ignoreFile,
00462 GWEN_STRINGLIST *sl) {
00463 int rv;
00464
00465 rv=GWEN_MDigest__HashFileTree(md, folder, NULL, ignoreFile, sl);
00466 if (rv<0) {
00467 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00468 return rv;
00469 }
00470
00471 return 0;
00472 }
00473
00474
00475
00476 int GWEN_MDigest_CheckFileTree(GWEN_MDIGEST *md,
00477 const char *folder,
00478 const char *checksumFile,
00479 int strictCheck,
00480 uint32_t pid) {
00481 GWEN_STRINGLIST *sl;
00482 GWEN_STRINGLIST *savedList;
00483 GWEN_BUFFER *tbuf;
00484 GWEN_STRINGLISTENTRY *se;
00485 int rv;
00486 int allHashesOk=1;
00487 int validLines=0;
00488
00489 sl=GWEN_StringList_new();
00490
00491
00492 rv=GWEN_MDigest_HashFileTree(md, folder, checksumFile, sl);
00493 if (rv<0) {
00494 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00495 I18N("Error unpacking program (%d)"), rv);
00496 GWEN_StringList_free(sl);
00497 return rv;
00498 }
00499
00500 savedList=GWEN_StringList_new();
00501
00502
00503 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00504 GWEN_Buffer_AppendString(tbuf, folder);
00505 GWEN_Buffer_AppendString(tbuf, GWEN_DIR_SEPARATOR_S);
00506 GWEN_Buffer_AppendString(tbuf, checksumFile);
00507 rv=GWEN_SyncIo_Helper_ReadFileToStringList(GWEN_Buffer_GetStart(tbuf),
00508 -1,
00509 savedList);
00510 if (rv<0) {
00511 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00512 I18N("Error loading checksum file (%d)"), rv);
00513 GWEN_Buffer_free(tbuf);
00514 GWEN_StringList_free(savedList);
00515 GWEN_StringList_free(sl);
00516 return rv;
00517 }
00518 GWEN_Buffer_free(tbuf);
00519
00520
00521 se=GWEN_StringList_FirstEntry(savedList);
00522 while(se) {
00523 const char *s;
00524
00525 s=GWEN_StringListEntry_Data(se);
00526 if (s && *s) {
00527 validLines++;
00528 if (0==GWEN_StringList_RemoveString(sl, s)) {
00529 DBG_ERROR(0, "Hash not found: %s", s);
00530 allHashesOk=0;
00531 }
00532 }
00533 se=GWEN_StringListEntry_Next(se);
00534 }
00535
00536 if (validLines==0) {
00537 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00538 I18N("Checksum file does not contain valid lines"));
00539 GWEN_StringList_free(savedList);
00540 GWEN_StringList_free(sl);
00541 return GWEN_ERROR_VERIFY;
00542 }
00543
00544 if (allHashesOk==0) {
00545 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00546 I18N("Integrity check on folder failed"));
00547 GWEN_StringList_free(savedList);
00548 GWEN_StringList_free(sl);
00549 return GWEN_ERROR_VERIFY;
00550 }
00551
00552
00553 if (GWEN_StringList_Count(sl)) {
00554 if (strictCheck) {
00555 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Error,
00556 I18N("Folder contains %d files without checksum"),
00557 GWEN_StringList_Count(sl));
00558 GWEN_StringList_free(savedList);
00559 GWEN_StringList_free(sl);
00560 }
00561 else
00562 GWEN_Gui_ProgressLog2(pid, GWEN_LoggerLevel_Warning,
00563 I18N("Folder contains %d files without checksum"),
00564 GWEN_StringList_Count(sl));
00565 }
00566 GWEN_StringList_free(savedList);
00567 GWEN_StringList_free(sl);
00568
00569 return 0;
00570 }
00571
00572
00573
00574
00575
00576