/* $Id: hash.c,v 1.4 2005/05/14 23:20:30 harbourn Exp $ * dcfldd - The Enhanced Forensic DD * By Nicholas Harbour */ /* Copyright (C) 85, 90, 91, 1995-2001, 2005 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* GNU dd originally written by Paul Rubin, David MacKenzie, and Stuart Kemp. */ #include "dcfldd.h" #include #include #include #include "md5.h" #include "sha1.h" #include "sha2.h" #include "hash.h" #include "log.h" hashflag_t hashflags = 0; /* Md5 global data */ MD5_CTX MD5_total_context; MD5_CTX MD5_window_context; MD5_CTX MD5_vtotal_context; MD5_CTX MD5_vwindow_context; char MD5_hashstr[MD5_DIGEST_STRING_LENGTH + 1] = {'\0'}; /* SHA1 global data */ SHA1Context SHA1_total_context; SHA1Context SHA1_window_context; SHA1Context SHA1_vtotal_context; SHA1Context SHA1_vwindow_context; char SHA1_hashstr[SHA1_DIGEST_STRING_LENGTH + 1] = {'\0'}; /* SHA256 global data */ SHA256_CTX SHA256_total_context; SHA256_CTX SHA256_window_context; SHA256_CTX SHA256_vtotal_context; SHA256_CTX SHA256_vwindow_context; char SHA256_hashstr[SHA256_DIGEST_STRING_LENGTH + 1] = {'\0'}; /* SHA384 global data */ SHA384_CTX SHA384_total_context; SHA384_CTX SHA384_window_context; SHA384_CTX SHA384_vtotal_context; SHA384_CTX SHA384_vwindow_context; char SHA384_hashstr[SHA384_DIGEST_STRING_LENGTH + 1] = {'\0'}; /* SHA512 global data */ SHA512_CTX SHA512_total_context; SHA512_CTX SHA512_window_context; SHA512_CTX SHA512_vtotal_context; SHA512_CTX SHA512_vwindow_context; char SHA512_hashstr[SHA512_DIGEST_STRING_LENGTH + 1] = {'\0'}; off_t hash_windowlen = 0; off_t window_beginning = 0; off_t bytes_in_window = 0; off_t bytes_in_total = 0; void (*hashinit)(void *); void (*hashupdate)(void *, const void *, size_t); void (*hashfinal)(void *, void *); void *hashstr_buf; size_t hashstr_buf_size; FILE *hash_log; /* Hash algorithms */ hashlist_t *ihashlist; hashtype_t hashops[] = { {"md5", 1, &MD5_window_context, &MD5_total_context, &MD5_vwindow_context, &MD5_vtotal_context, (void (*)(void *)) MD5Init, (void (*)(void *, const void *, size_t)) MD5Update, (void (*)(void *, void *)) MD5Final, &MD5_hashstr[0], sizeof (MD5_hashstr), NULL}, {"sha1", 1<<1, &SHA1_window_context, &SHA1_total_context, &SHA1_vwindow_context, &SHA1_vtotal_context, (void (*)(void *)) SHA1Init, (void (*)(void *, const void *, size_t)) SHA1Update, (void (*)(void *, void *)) SHA1End, &SHA1_hashstr[0], sizeof (SHA1_hashstr), NULL}, {"sha256", 1<<2, &SHA256_window_context, &SHA256_total_context, &SHA256_vwindow_context, &SHA256_vtotal_context, (void (*)(void *)) SHA256_Init, (void (*)(void *, const void *, size_t)) SHA256_Update, (void (*)(void *, void *)) SHA256_End, SHA256_hashstr, sizeof (SHA256_hashstr), NULL}, {"sha384", 1<<3, &SHA384_window_context, &SHA384_total_context, &SHA384_vwindow_context, &SHA384_vtotal_context, (void (*)(void *)) SHA384_Init, (void (*)(void *, const void *, size_t)) SHA384_Update, (void (*)(void *, void *)) SHA384_End, &SHA384_hashstr[0], sizeof (SHA384_hashstr), NULL}, {"sha512", 1<<4, &SHA512_window_context, &SHA512_total_context, &SHA512_vwindow_context, &SHA512_vtotal_context, (void (*)(void *)) SHA512_Init, (void (*)(void *, const void *, size_t)) SHA512_Update, (void (*)(void *, void *)) SHA512_End, &SHA512_hashstr[0], sizeof (SHA512_hashstr), NULL}, {NULL, 0, NULL, NULL, NULL, NULL, (void (*)(void *)) NULL, (void (*)(void *, const void *, size_t)) NULL, (void (*)(void *, void *)) NULL, NULL, 0, NULL} }; static void add_hash(hashlist_t **hashlist, int hash) { hashlist_t *hlptr = *hashlist; int i; if (hlptr == NULL) { hlptr = malloc(sizeof (hashlist_t)); *hashlist = hlptr; } else { for ( ; hlptr->next != NULL; hlptr = hlptr->next) ; hlptr->next = malloc(sizeof (hashlist_t)); hlptr = hlptr->next; } hlptr->next = NULL; hlptr->hash = &hashops[hash]; } /* add all the appropriate hashops according to the flags */ void init_hashlist(hashlist_t **hashlist, hashflag_t flags) { int i; for (i = 0; hashops[i].name != NULL; i++) if (hashops[i].flag & flags) add_hash(hashlist, i); } /* not to be confused with init_hashlist, this function calls * the hashtype specific init function for each hash type in * the list */ void hashl_init(hashlist_t *hashlist, int context) { hashlist_t *hptr; for (hptr = hashlist; hptr != NULL; hptr = hptr->next) { void *ctx; switch (context) { case WINDOW_CTX: ctx = hptr->hash->window_context; break; case TOTAL_CTX: ctx = hptr->hash->total_context; break; case VWINDOW_CTX: ctx = hptr->hash->vwindow_context; break; case VTOTAL_CTX: ctx = hptr->hash->vtotal_context; break; default: internal_error("unreachable branch encountered in hashl_init()"); break; } (hptr->hash->init)(ctx); } } void hashl_update(hashlist_t *hashlist, int context, const void *buf, size_t len) { hashlist_t *hptr; for (hptr = hashlist; hptr != NULL; hptr = hptr->next) { void *ctx; switch (context) { case WINDOW_CTX: ctx = hptr->hash->window_context; break; case TOTAL_CTX: ctx = hptr->hash->total_context; break; case VWINDOW_CTX: ctx = hptr->hash->vwindow_context; break; case VTOTAL_CTX: ctx = hptr->hash->vtotal_context; break; default: internal_error("unreachable branch encountered in hashl_update()"); break; } (hptr->hash->update)(ctx, buf, len); } } void hashl_final(hashlist_t *hashlist, int context) { hashlist_t *hptr; for (hptr = hashlist; hptr != NULL; hptr = hptr->next) { void *ctx; switch (context) { case WINDOW_CTX: ctx = hptr->hash->window_context; break; case TOTAL_CTX: ctx = hptr->hash->total_context; break; case VWINDOW_CTX: ctx = hptr->hash->vwindow_context; break; case VTOTAL_CTX: ctx = hptr->hash->vtotal_context; break; default: internal_error("unreachable branch encountered in hashl_final()"); break; } /* note that this writes the hash string to the global buffer * for the specific hashtype, when calling this multiple times * (i.e. like in verify) copy that buffer out before finalizing * another list */ (hptr->hash->final)(ctx, hptr->hash->hashstr_buf); } } void hash_update_buf(hashlist_t *hashlist, int winctx, int ttlctx, void *buf, size_t len) { if (hash_windowlen != 0) { hashl_update(hashlist, winctx, buf, len); if (winctx == WINDOW_CTX) /* don't do this for verify or you'll get double */ bytes_in_window += len; } hashl_update(hashlist, ttlctx, buf, len); if(ttlctx == TOTAL_CTX) bytes_in_total += len; } void hash_update(hashlist_t *hashlist, void *buf, size_t len) { size_t left_in_window = hash_windowlen - bytes_in_window; if (bytes_in_total == 0) hashl_init(hashlist, TOTAL_CTX); if (hash_windowlen == 0) hash_update_buf(hashlist, WINDOW_CTX, TOTAL_CTX, buf, len); else { if (bytes_in_window == 0) hashl_init(hashlist, WINDOW_CTX); if (len >= left_in_window) { hash_update_buf(hashlist, WINDOW_CTX, TOTAL_CTX, buf, left_in_window); hashl_final(hashlist, WINDOW_CTX); display_windowhash(hashlist, hash_windowlen); window_beginning += hash_windowlen; bytes_in_window = 0; hash_update(hashlist, buf + left_in_window, len - left_in_window); } else hash_update_buf(hashlist, WINDOW_CTX, TOTAL_CTX, buf, len); } } void display_windowhash(hashlist_t *hashlist, off_t windowlen) { hashlist_t *hptr; for (hptr = hashlist; hptr != NULL; hptr = hptr->next) log_hashwindow(hptr->hash, window_beginning, (window_beginning + windowlen), input_blocksize, hptr->hash->hashstr_buf); } void display_totalhash(hashlist_t *hashlist, int ttlctx) { hashlist_t *hptr; hashl_final(hashlist, ttlctx); for (hptr = hashlist; hptr != NULL; hptr = hptr->next) log_hashtotal(hptr->hash, 0, 0, input_blocksize, hptr->hash->hashstr_buf); } void hash_remainder(hashlist_t *hashlist, int winctx) { if (hash_windowlen > 0 && bytes_in_window > 0) { hashl_final(hashlist, winctx); display_windowhash(hashlist, bytes_in_window); } }