gwenhywfar 4.0.3

mdigest.c

Go to the documentation of this file.
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