/* sha1.c - Interfaces to SHA-1 hash for the notmuch mail system * * Copyright © 2009 Carl Worth * * 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 3 of the License, 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, see http://www.gnu.org/licenses/ . * * Author: Carl Worth */ #include "notmuch-private.h" #include /* Just some simple interfaces on top of libgcrypt */ static char * _hex_of_sha1_digest (gcry_md_hd_t c) { char *result, *r; unsigned char *digest; int i; int digest_size; digest_size = gcry_md_get_algo_dlen(gcry_md_get_algo(c)); digest = gcry_md_read(c, 0); result = xcalloc (digest_size * 2 + 1, 1); for (r = result, i = 0; i < digest_size; r += 2, i++) { sprintf (r, "%02x", digest[i]); } return result; } /* Create a hexadecimal string version of the SHA-1 digest of 'str' * (including its null terminating character). * * This function returns a newly allocated string which the caller * should free() when finished. */ char * notmuch_sha1_of_string (const char *str) { char *result; gcry_md_hd_t c; gcry_md_open (&c, GCRY_MD_SHA1, 0); gcry_md_write (c, str, strlen (str) + 1); gcry_md_final (c); result = _hex_of_sha1_digest (c); gcry_md_close (c); return result; } /* Create a hexadecimal string version of the SHA-1 digest of the * contents of the named file. * * This function returns a newly allocated string which the caller * should free() when finished. * * If any error occurs while reading the file, (permission denied, * file not found, etc.), this function returns NULL. */ char * notmuch_sha1_of_file (const char *filename) { FILE *file; #define BLOCK_SIZE 4096 unsigned char block[BLOCK_SIZE]; size_t bytes_read; gcry_md_hd_t c; char *result; file = fopen (filename, "r"); if (file == NULL) return NULL; gcry_md_open(&c, GCRY_MD_SHA1, 0); while (1) { bytes_read = fread (block, 1, 4096, file); if (bytes_read == 0) { if (feof (file)) { break; } else if (ferror (file)) { fclose (file); return NULL; } } else { gcry_md_write (c, block, bytes_read); } } gcry_md_final (c); result = _hex_of_sha1_digest (c); gcry_md_close (c); fclose (file); return result; }