%% options copyright owner = Dirk Krause copyright year = 2011-xxxx license = bsd %% header #include "dk3conf.h" #include "dk3types.h" #ifdef __cplusplus extern "C" { #endif /** Get checksum type for a given name. @param n Message digest name ("MD5", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512", or "RIPEMD-160"). @param app Application structure for diagnostics, may be NULL. @return Integer representation (see @ref mdtypes) on success, -1 on error. */ int dk3checksum_get_type_app(dkChar const *n, dk3_app_t *app); /** Build checksum for a file. @param db Destination buffer. @param sz Size of destination buffer. @param fn File name to process. @param cst Checksum type (message digest type, see @ref mdtypes). @param cse Binary to text encoding for message digest (see @ref dataencoding). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3checksum_build_app( char *db, size_t sz, dkChar const *fn, int cst, int cse, dk3_app_t *app ); /** Get string length produced for a message digest and encoding type. @param cst Message digest type, see @ref mdtypes. @param cse Binary to text encoding, see @ref dataencoding. @return Number of characters produced. */ size_t dk3checksum_length(int cst, int cse); /** Get name for message digest type. @param tp Digest type, see @ref mdtypes. @return Name for digest type. */ dkChar const * dk3checksum_get_type_name(int tp); #ifdef __cplusplus } #endif %% module #include "dk3all.h" #if DK3_HAVE_OPENSSL_MD5_H #include #endif #if DK3_HAVE_OPENSSL_SHA_H #include #endif #if DK3_HAVE_OPENSSL_RIPEMD_H #include #endif $!trace-include /** Names of message digest algorithms. Order here must match order of DK3_MD_TYPE_xxx in dk3const.h. */ static dkChar const * const dk3_checksum_type_names[] = { /* 0 */ dkT("MD5"), /* 1 */ dkT("SHA-1"), /* 2 */ dkT("SHA-224"), /* 3 */ dkT("SHA-256"), /* 4 */ dkT("SHA-384"), /* 5 */ dkT("SHA-512"), /* 6 */ dkT("RIPEMD-160"), NULL }; /** String constants. */ static dkChar const * const kw[] = { #if DK3_ON_WINDOWS /* 0 */ dkT("rb"), /* File mode, read binary. */ #else /* 0 */ dkT("r"), /* no difference on non-Windows. */ #endif }; int dk3checksum_get_type_app(dkChar const *n, dk3_app_t *app) { int back = -1; if(n) { back = dk3str_array_index(dk3_checksum_type_names, n, 0); if(back == -1) { if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 127, 128, n); } } else { back++; } } return back; } /** Convert length of binary message digest to length of encoded string. @param l Number of binary bytes to encode. @param cse Message digest encoding. @return Number of text characters produced by encoding. */ static size_t dk3chksum_conv_length(size_t l, int cse) { size_t back = 0; $? "+ dk3chksum_conv_length %lu %d", (unsigned long)l, cse switch(cse) { case DK3_DATA_ENCODING_HEX: { back = dk3enc_size_bin_to_hex(l); } break; default: { back = dk3enc_size_bin_to_a85(l); } break; } $? "- dk3chksum_conv_length %lu", (unsigned long)back return back; } /** Get length of binary message digest. @param cst Message digest type. @return Number of binary bytes produced. */ static size_t dk3chksum_min_length(int cst) { size_t back = 0; switch(cst) { case DK3_MD_TYPE_MD5: back = 16; break; case DK3_MD_TYPE_SHA_1: back = 20; break; case DK3_MD_TYPE_SHA_224: back = 28; break; case DK3_MD_TYPE_SHA_256: back = 32; break; case DK3_MD_TYPE_SHA_384: back = 48; break; case DK3_MD_TYPE_SHA_512: back = 64; break; case DK3_MD_TYPE_RIPEMD_160: back = 20; break; } return back; } /** Build binary checksum from file. @param db Destination buffer. @param sz Size of \a db. @param fipo File pointer for read access. @param cst Checksum type. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3checksum_binary(char *db, size_t sz, FILE *fipo, int cst, dk3_app_t *app) { int back = 0; #if DK3_HAVE_OPENSSL_SHA_H SHA_CTX sha_ctx; /* SHA-1 context. */ #if DK3_HAVE_SHA224 || DK3_HAVE_SHA256 SHA256_CTX sha256_ctx; /* SHA-256 context. */ #endif #if DK3_HAVE_SHA384 || DK3_HAVE_SHA512 SHA512_CTX sha512_ctx; /* SHA-512 context. */ #endif #endif #if DK3_HAVE_OPENSSL_MD5_H MD5_CTX md5_ctx; /* MD5 context. */ #endif #if DK3_HAVE_OPENSSL_RIPEMD_H RIPEMD160_CTX ripemd160_ctx; /* RIPEMD-160 context. */ #endif char buffer[4096]; /* Buffer for input. */ size_t rb = 0; /* Number of bytes read. */ switch(cst) { case DK3_MD_TYPE_MD5: { #if DK3_HAVE_OPENSSL_MD5_H MD5_Init(&md5_ctx); while((rb = dk3sf_fread_app(buffer,1,sizeof(buffer),fipo,app)) > 0) { MD5_Update(&md5_ctx, buffer, rb); } MD5_Final((unsigned char *)db, &md5_ctx); back = 1; #else if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 156, 157, dk3_checksum_type_names[0]); } #endif } break; case DK3_MD_TYPE_SHA_1: { #if DK3_HAVE_OPENSSL_SHA_H SHA1_Init(&sha_ctx); while((rb = dk3sf_fread_app(buffer,1,sizeof(buffer),fipo,app)) > 0) { SHA1_Update(&sha_ctx, buffer, rb); } SHA1_Final((unsigned char *)db, &sha_ctx); back = 1; #else if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 156, 157, dk3_checksum_type_names[1]); } #endif } break; case DK3_MD_TYPE_SHA_224: { #if DK3_HAVE_OPENSSL_SHA_H && DK3_HAVE_SHA224 SHA224_Init(&sha256_ctx); while((rb = dk3sf_fread_app(buffer,1,sizeof(buffer),fipo,app)) > 0) { SHA224_Update(&sha256_ctx, buffer, rb); } SHA224_Final((unsigned char *)db, &sha256_ctx); back = 1; #else if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 156, 157, dk3_checksum_type_names[2]); } #endif } break; case DK3_MD_TYPE_SHA_256: { #if DK3_HAVE_OPENSSL_SHA_H && DK3_HAVE_SHA256 SHA256_Init(&sha256_ctx); while((rb = dk3sf_fread_app(buffer,1,sizeof(buffer),fipo,app)) > 0) { SHA256_Update(&sha256_ctx, buffer, rb); } SHA256_Final((unsigned char *)db, &sha256_ctx); back = 1; #else if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 156, 157, dk3_checksum_type_names[3]); } #endif } break; case DK3_MD_TYPE_SHA_384: { #if DK3_HAVE_OPENSSL_SHA_H && DK3_HAVE_SHA384 SHA384_Init(&sha512_ctx); while((rb = dk3sf_fread_app(buffer,1,sizeof(buffer),fipo,app)) > 0) { SHA384_Update(&sha512_ctx, buffer, rb); } SHA384_Final((unsigned char *)db, &sha512_ctx); back = 1; #else if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 156, 157, dk3_checksum_type_names[4]); } #endif } break; case DK3_MD_TYPE_SHA_512: { #if DK3_HAVE_OPENSSL_SHA_H && DK3_HAVE_SHA512 SHA512_Init(&sha512_ctx); while((rb = dk3sf_fread_app(buffer,1,sizeof(buffer),fipo,app)) > 0) { SHA512_Update(&sha512_ctx, buffer, rb); } SHA512_Final((unsigned char *)db, &sha512_ctx); back = 1; #else if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 156, 157, dk3_checksum_type_names[5]); } #endif } break; case DK3_MD_TYPE_RIPEMD_160 : { #if DK3_HAVE_OPENSSL_RIPEMD_H RIPEMD160_Init(&ripemd160_ctx); while((rb = dk3sf_fread_app(buffer,1,sizeof(buffer),fipo,app)) > 0) { RIPEMD160_Update(&ripemd160_ctx, buffer, rb); } RIPEMD160_Final((unsigned char *)db, &ripemd160_ctx); back = 1; #else if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 156, 157, dk3_checksum_type_names[6]); } #endif } break; default: { if(app) { /* ERROR: Unknown message digest type. */ dk3app_log_i1(app, DK3_LL_ERROR, 158); } } break; } return back; } size_t dk3checksum_length(int cst, int cse) { size_t back; back = dk3chksum_conv_length(dk3chksum_min_length(cst), cse); return back; } int dk3checksum_build_app( char *db, size_t sz, dkChar const *fn, int cst, int cse, dk3_app_t *app ) { int back = 0; size_t minlgt = 0; /* Length of binary message digest. */ size_t convlgt = 0; /* Length of digest converted to text. */ size_t i = 0; /* Used to write zeroes. */ dk3_stat_t stb; /* Test for existance. */ char mybuffer[256]; /* ASCII text version of digest. */ FILE *fipo = NULL; /* Input file. */ if(db) { *db = '\0'; } if((db) && (sz) && (fn)) { if((cst > 0) && (cst <= DK3_MD_TYPE_MAX)) { if((cse >= 0) && (cse <= DK3_DATA_ENCODING_MAX)) { minlgt = dk3chksum_min_length(cst); convlgt = dk3chksum_conv_length(minlgt, cse); if(sz > convlgt) { for(i = 0; i < convlgt; i++) { db[i] = '-'; } db[convlgt] = '\0'; if(dk3sf_stat_app(&stb, fn, app)) { if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_REGULAR) { fipo = dk3sf_fopen_app(fn, kw[0], app); if(fipo) { if(dk3checksum_binary(mybuffer,sizeof(mybuffer),fipo, cst,app)) { switch(cse) { case DK3_DATA_ENCODING_HEX: { back = dk3enc_bin_to_hex_app(db,sz,mybuffer,minlgt,app); } break; case DK3_DATA_ENCODING_ASCII85: { back = dk3enc_bin_to_a85_app(db,sz,mybuffer,minlgt,app); } break; case DK3_DATA_ENCODING_REVERSE_ASCII85: { back = dk3enc_bin_to_ra85_app(db,sz,mybuffer,minlgt,app); } break; default: { /* Illegal encoding type! */ dk3app_log_i1(app, DK3_LL_ERROR, 158); } break; } } fclose(fipo); } } else { if(app) { /* ERROR: Checksumming for regular files only .*/ dk3app_log_i1(app, DK3_LL_ERROR, 159); } } } } else { if(app) { /* ERROR: Destination buffer too small */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } else { if(app) { /* ERROR: Illegal encoding number. */ dk3app_log_i1(app, DK3_LL_ERROR, 158); } } } else { if(app) { /* ERROR: Illegal digest type. */ dk3app_log_i1(app, DK3_LL_ERROR, 158); } } } return back; } dkChar const * dk3checksum_get_type_name(int tp) { dkChar const *back = NULL; if((tp > 0) && (tp <= DK3_MD_TYPE_MAX)) { back = dk3_checksum_type_names[tp - 1]; } return back; } /* vim: set ai sw=2 : */