>From 03009bdf1f8ca5e45f87505173a50f3f85cf6caf Mon Sep 17 00:00:00 2001 From: Daniel Santos Date: Thu, 20 Dec 2012 02:47:58 -0600 Subject: piping support --- lib/digest.h | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/md2.c | 77 ++++------------------------ lib/md2.h | 2 +- lib/md5.c | 77 ++++------------------------ lib/md5.h | 2 +- lib/sha1.c | 77 ++++------------------------ lib/sha1.h | 2 +- lib/sha256.c | 151 +++++++---------------------------------------------- lib/sha256.h | 4 +- lib/sha512.c | 151 +++++++---------------------------------------------- lib/sha512.h | 4 +- 11 files changed, 239 insertions(+), 472 deletions(-) create mode 100644 lib/digest.h diff --git a/lib/digest.h b/lib/digest.h new file mode 100644 index 0000000..0983a07 --- /dev/null +++ b/lib/digest.h @@ -0,0 +1,164 @@ +/* Functions to compute MD5 message digest of files or memory blocks. + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995-1997, 1999-2001, 2005-2006, 2008-2012 Free Software + Foundation, Inc. + This file is part of the GNU C Library. + + 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, see . */ + + +#include + +#include "full-write.h" + +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +#ifdef __GNUC__ +# define likely(exp) __builtin_expect((exp), 1) +# define unlikely(exp) __builtin_expect((exp), 0) + +# if __GNUC__ >= 4 +# ifndef __always_inline +# define __always_inline inline __attribute__((always_inline)) +# endif + +# if __GNUC_MINOR__ >= 1 && !(__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ == 0) +# define __flatten __attribute__((flatten)) +# endif + +# endif +#endif + +#ifndef likely +# define likely(exp) (exp) +#endif +#ifndef unlikely +# define unlikely(exp) (exp) +#endif +#ifndef __always_inline +# define __always_inline inline +#endif +#ifndef __flatten +# define __flatten +#endif + +typedef void (*digest_init_ctx_fn) (void *ctx); +typedef void (*digest_process_data_fn) (const void *buffer, size_t len, void *ctx); +typedef void *(*digest_finish_ctx_fn) (void *ctx, void *resbuf); + +struct digest_funcs { + const digest_init_ctx_fn init_ctx; + const digest_process_data_fn process_block; + const digest_process_data_fn process_bytes; + const digest_finish_ctx_fn finish_ctx; +}; + +/* TODO: Add configure value to make smaller code and encapsulate usage of + * __flatten and __always_inline */ + +enum digest_stream_result { + DIGEST_STREAM_SUCCESS, + DIGEST_STREAM_READ_ERROR, + DIGEST_STREAM_WRITE_ERROR +}; + +/* Compute message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +static __always_inline int +digest_stream (FILE *instream, FILE *outstream, void *resblock, void *ctx, + const struct digest_funcs *funcs) +{ + size_t sum; + + /* zero is actually stdin, which we will never write to, but this can + * save a register */ + int outfd = outstream ? fileno(outstream) : 0; + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + /* Initialize the computation context. */ + funcs->init_ctx (ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + char *start = buffer + sum; + size_t size = BLOCKSIZE - sum; + + n = fread (start, 1, size, instream); + + /* keep writes going smoothly, even if we've chosen a blocksize + * that's too large to work well on the arch or I/O devices */ + if (outfd && n && unlikely(full_write (outfd, start, size) != size)) + { + free (buffer); + return DIGEST_STREAM_WRITE_ERROR; + } + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (unlikely(ferror (instream))) + { + free (buffer); + return DIGEST_STREAM_READ_ERROR; + } + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (instream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + funcs->process_block (buffer, BLOCKSIZE, ctx); + } + +process_partial_block: + + /* Process any remaining bytes. */ + if (sum > 0) + funcs->process_bytes (buffer, sum, ctx); + + /* Construct result in desired memory. */ + funcs->finish_ctx (ctx, resblock); + free (buffer); + return 0; +} diff --git a/lib/md2.c b/lib/md2.c index 1d181f9..5f64175 100644 --- a/lib/md2.c +++ b/lib/md2.c @@ -34,9 +34,7 @@ #endif #define BLOCKSIZE 32768 -#if BLOCKSIZE % 64 != 0 -# error "invalid BLOCKSIZE" -#endif +#include "digest.h" static void md2_update_chksum (struct md2_ctx *md); static void md2_compress (struct md2_ctx *md); @@ -90,74 +88,19 @@ md2_finish_ctx (struct md2_ctx *ctx, void *resbuf) /* Compute MD2 message digest for bytes read from STREAM. The resulting message digest number will be written into the 16 bytes beginning at RESBLOCK. */ -int -md2_stream (FILE *stream, void *resblock) +int __flatten +md2_stream (FILE *instream, FILE *outstream, void *resblock) { struct md2_ctx ctx; - size_t sum; - - char *buffer = malloc (BLOCKSIZE + 72); - if (!buffer) - return 1; - - /* Initialize the computation context. */ - md2_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - { - free (buffer); - return 1; - } - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - md2_process_block (buffer, BLOCKSIZE, &ctx); - } - -process_partial_block:; - /* Process any remaining bytes. */ - if (sum > 0) - md2_process_bytes (buffer, sum, &ctx); + struct digest_funcs funcs = { + .init_ctx = (digest_init_ctx_fn) md2_init_ctx; + .process_block = (digest_process_block_fn) md2_process_block; + .process_bytes = (digest_process_bytes_fn) md2_process_bytes; + .finish_ctx; = (digest_finish_fn) md2_finish_ctx; + }; - /* Construct result in desired memory. */ - md2_finish_ctx (&ctx, resblock); - free (buffer); - return 0; + return digest_stream(instream, outstream, resblock, &funcs); } /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The diff --git a/lib/md2.h b/lib/md2.h index fd14155..6cb7e8b 100644 --- a/lib/md2.h +++ b/lib/md2.h @@ -69,7 +69,7 @@ extern void *md2_read_ctx (const struct md2_ctx *ctx, void *resbuf); /* Compute MD2 message digest for bytes read from STREAM. The resulting message digest number will be written into the 16 bytes beginning at RESBLOCK. */ -extern int md2_stream (FILE *stream, void *resblock); +extern int md2_stream (FILE *instream, FILE *outstream, void *resblock); /* Compute MD2 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise diff --git a/lib/md5.c b/lib/md5.c index 66ede23..ad817e2 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -57,9 +57,7 @@ #endif #define BLOCKSIZE 32768 -#if BLOCKSIZE % 64 != 0 -# error "invalid BLOCKSIZE" -#endif +#include "digest.h" /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (RFC 1321, 3.1: Step 1) */ @@ -132,74 +130,19 @@ md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) /* Compute MD5 message digest for bytes read from STREAM. The resulting message digest number will be written into the 16 bytes beginning at RESBLOCK. */ -int -md5_stream (FILE *stream, void *resblock) +int __flatten +md5_stream (FILE *instream, FILE *outstream, void *resblock) { struct md5_ctx ctx; - size_t sum; - - char *buffer = malloc (BLOCKSIZE + 72); - if (!buffer) - return 1; - - /* Initialize the computation context. */ - md5_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - { - free (buffer); - return 1; - } - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - md5_process_block (buffer, BLOCKSIZE, &ctx); - } - -process_partial_block: - /* Process any remaining bytes. */ - if (sum > 0) - md5_process_bytes (buffer, sum, &ctx); + struct digest_funcs funcs = { + .init_ctx = (digest_init_ctx_fn) md5_init_ctx, + .process_block = (digest_process_data_fn) md5_process_block, + .process_bytes = (digest_process_data_fn) md5_process_bytes, + .finish_ctx = (digest_finish_ctx_fn) md5_finish_ctx + }; - /* Construct result in desired memory. */ - md5_finish_ctx (&ctx, resblock); - free (buffer); - return 0; + return digest_stream(instream, outstream, resblock, &ctx, &funcs); } /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The diff --git a/lib/md5.h b/lib/md5.h index f571a70..419f922 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -109,7 +109,7 @@ extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW; /* Compute MD5 message digest for bytes read from STREAM. The resulting message digest number will be written into the 16 bytes beginning at RESBLOCK. */ -extern int __md5_stream (FILE *stream, void *resblock) __THROW; +extern int __md5_stream (FILE *instream, FILE *outstream, void *resblock) __THROW; /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise diff --git a/lib/sha1.c b/lib/sha1.c index db4ab42..8dcc21d 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -42,9 +42,7 @@ #endif #define BLOCKSIZE 32768 -#if BLOCKSIZE % 64 != 0 -# error "invalid BLOCKSIZE" -#endif +#include "digest.h" /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (RFC 1321, 3.1: Step 1) */ @@ -120,74 +118,19 @@ sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) /* Compute SHA1 message digest for bytes read from STREAM. The resulting message digest number will be written into the 16 bytes beginning at RESBLOCK. */ -int -sha1_stream (FILE *stream, void *resblock) +int __flatten +sha1_stream (FILE *instream, FILE *outstream, void *resblock) { struct sha1_ctx ctx; - size_t sum; - - char *buffer = malloc (BLOCKSIZE + 72); - if (!buffer) - return 1; - - /* Initialize the computation context. */ - sha1_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - { - free (buffer); - return 1; - } - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - sha1_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - /* Process any remaining bytes. */ - if (sum > 0) - sha1_process_bytes (buffer, sum, &ctx); + struct digest_funcs funcs = { + .init_ctx = (digest_init_ctx_fn) sha1_init_ctx, + .process_block = (digest_process_data_fn) sha1_process_block, + .process_bytes = (digest_process_data_fn) sha1_process_bytes, + .finish_ctx = (digest_finish_ctx_fn) sha1_finish_ctx + }; - /* Construct result in desired memory. */ - sha1_finish_ctx (&ctx, resblock); - free (buffer); - return 0; + return digest_stream(instream, outstream, resblock, &ctx, &funcs); } /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The diff --git a/lib/sha1.h b/lib/sha1.h index 4e55430..502cd3a 100644 --- a/lib/sha1.h +++ b/lib/sha1.h @@ -76,7 +76,7 @@ extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); /* Compute SHA1 message digest for bytes read from STREAM. The resulting message digest number will be written into the 20 bytes beginning at RESBLOCK. */ -extern int sha1_stream (FILE *stream, void *resblock); +extern int sha1_stream (FILE *instream, FILE *outstream, void *resblock); /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise diff --git a/lib/sha256.c b/lib/sha256.c index a8d29da..cc1ac3f 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -41,9 +41,7 @@ #endif #define BLOCKSIZE 32768 -#if BLOCKSIZE % 64 != 0 -# error "invalid BLOCKSIZE" -#endif +#include "digest.h" /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. */ @@ -167,145 +165,34 @@ sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) /* Compute SHA256 message digest for bytes read from STREAM. The resulting message digest number will be written into the 32 bytes beginning at RESBLOCK. */ -int -sha256_stream (FILE *stream, void *resblock) +int __flatten +sha256_stream (FILE *instream, FILE *outstream, void *resblock) { struct sha256_ctx ctx; - size_t sum; - - char *buffer = malloc (BLOCKSIZE + 72); - if (!buffer) - return 1; - - /* Initialize the computation context. */ - sha256_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - { - free (buffer); - return 1; - } - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - sha256_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - /* Process any remaining bytes. */ - if (sum > 0) - sha256_process_bytes (buffer, sum, &ctx); + struct digest_funcs funcs = { + .init_ctx = (digest_init_ctx_fn) sha256_init_ctx, + .process_block = (digest_process_data_fn) sha256_process_block, + .process_bytes = (digest_process_data_fn) sha256_process_bytes, + .finish_ctx = (digest_finish_ctx_fn) sha256_finish_ctx + }; - /* Construct result in desired memory. */ - sha256_finish_ctx (&ctx, resblock); - free (buffer); - return 0; + return digest_stream(instream, outstream, resblock, &ctx, &funcs); } -/* FIXME: Avoid code duplication */ -int -sha224_stream (FILE *stream, void *resblock) +int __flatten +sha224_stream (FILE *instream, FILE *outstream, void *resblock) { struct sha256_ctx ctx; - size_t sum; - - char *buffer = malloc (BLOCKSIZE + 72); - if (!buffer) - return 1; - - /* Initialize the computation context. */ - sha224_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - { - free (buffer); - return 1; - } - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - sha256_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - /* Process any remaining bytes. */ - if (sum > 0) - sha256_process_bytes (buffer, sum, &ctx); + struct digest_funcs funcs = { + .init_ctx = (digest_init_ctx_fn) sha224_init_ctx, + .process_block = (digest_process_data_fn) sha256_process_block, + .process_bytes = (digest_process_data_fn) sha256_process_bytes, + .finish_ctx = (digest_finish_ctx_fn) sha224_finish_ctx + }; - /* Construct result in desired memory. */ - sha224_finish_ctx (&ctx, resblock); - free (buffer); - return 0; + return digest_stream(instream, outstream, resblock, &ctx, &funcs); } /* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The diff --git a/lib/sha256.h b/lib/sha256.h index d69b83f..005cf86 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -74,8 +74,8 @@ extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); /* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The resulting message digest number will be written into the 32 (28) bytes beginning at RESBLOCK. */ -extern int sha256_stream (FILE *stream, void *resblock); -extern int sha224_stream (FILE *stream, void *resblock); +extern int sha256_stream (FILE *instream, FILE *outstream, void *resblock); +extern int sha224_stream (FILE *instream, FILE *outstream, void *resblock); /* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise diff --git a/lib/sha512.c b/lib/sha512.c index cf62f20..836a600 100644 --- a/lib/sha512.c +++ b/lib/sha512.c @@ -48,9 +48,7 @@ #endif #define BLOCKSIZE 32768 -#if BLOCKSIZE % 128 != 0 -# error "invalid BLOCKSIZE" -#endif +#include "digest.h" /* This array contains the bytes used to pad the buffer to the next 128-byte boundary. */ @@ -175,145 +173,34 @@ sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf) /* Compute SHA512 message digest for bytes read from STREAM. The resulting message digest number will be written into the 64 bytes beginning at RESBLOCK. */ -int -sha512_stream (FILE *stream, void *resblock) +int __flatten +sha512_stream (FILE *instream, FILE *outstream, void *resblock) { struct sha512_ctx ctx; - size_t sum; - - char *buffer = malloc (BLOCKSIZE + 72); - if (!buffer) - return 1; - - /* Initialize the computation context. */ - sha512_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - { - free (buffer); - return 1; - } - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 128 == 0 - */ - sha512_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - /* Process any remaining bytes. */ - if (sum > 0) - sha512_process_bytes (buffer, sum, &ctx); + struct digest_funcs funcs = { + .init_ctx = (digest_init_ctx_fn) sha512_init_ctx, + .process_block = (digest_process_data_fn) sha512_process_block, + .process_bytes = (digest_process_data_fn) sha512_process_bytes, + .finish_ctx = (digest_finish_ctx_fn) sha512_finish_ctx + }; - /* Construct result in desired memory. */ - sha512_finish_ctx (&ctx, resblock); - free (buffer); - return 0; + return digest_stream(instream, outstream, resblock, &ctx, &funcs); } -/* FIXME: Avoid code duplication */ -int -sha384_stream (FILE *stream, void *resblock) +int __flatten +sha384_stream (FILE *instream, FILE *outstream, void *resblock) { struct sha512_ctx ctx; - size_t sum; - - char *buffer = malloc (BLOCKSIZE + 72); - if (!buffer) - return 1; - - /* Initialize the computation context. */ - sha384_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - { - free (buffer); - return 1; - } - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 128 == 0 - */ - sha512_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - /* Process any remaining bytes. */ - if (sum > 0) - sha512_process_bytes (buffer, sum, &ctx); + struct digest_funcs funcs = { + .init_ctx = (digest_init_ctx_fn) sha384_init_ctx, + .process_block = (digest_process_data_fn) sha512_process_block, + .process_bytes = (digest_process_data_fn) sha512_process_bytes, + .finish_ctx = (digest_finish_ctx_fn) sha384_finish_ctx + }; - /* Construct result in desired memory. */ - sha384_finish_ctx (&ctx, resblock); - free (buffer); - return 0; + return digest_stream(instream, outstream, resblock, &ctx, &funcs); } /* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The diff --git a/lib/sha512.h b/lib/sha512.h index ddf91d6..d1fb835 100644 --- a/lib/sha512.h +++ b/lib/sha512.h @@ -78,8 +78,8 @@ extern void *sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf); /* Compute SHA512 (SHA384) message digest for bytes read from STREAM. The resulting message digest number will be written into the 64 (48) bytes beginning at RESBLOCK. */ -extern int sha512_stream (FILE *stream, void *resblock); -extern int sha384_stream (FILE *stream, void *resblock); +extern int sha512_stream (FILE *instream, FILE *outstream, void *resblock); +extern int sha384_stream (FILE *instream, FILE *outstream, void *resblock); /* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise -- 1.7.8.6