diff options
Diffstat (limited to 'b2sum.c')
-rw-r--r-- | b2sum.c | 295 |
1 files changed, 295 insertions, 0 deletions
@@ -0,0 +1,295 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +const char *argv0 = "b2sum"; + +static int flag_check = 0; +static int flag_binary = 0; +static int flag_lower = 0; +static int flag_upper = 0; +static int flag_small = 0; +static int flag_extended = 0; +static int flag_hex = 0; +static int flag_zero = 0; +static int length = 0; +static long long int xlength = 0; + +static size_t hashlen; + +static void +usage(void) +{ + /* TODO add support for key, salt, and personalization */ + /* TODO add support for parallel versions */ + fprintf(stderr, "usage: %s [-l bits | -X bits] [-c | -B | -L | -U] [-sxz] [file] ...", argv0); + exit(2); +} + +static int +hash_fd_blake2bs(int fd, const char *fname, int decode_hex, unsigned char hash[]) +{ + struct libblake_blake2b_state state2b; + struct libblake_blake2b_params params2b; + struct libblake_blake2s_state state2s; + struct libblake_blake2s_params params2s; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + size_t off = 0; + size_t req; + ssize_t r; + int ok; + if (flag_small) { + memset(¶ms2s, 0, sizeof(params2s)); + params2s.digest_len = (uint_least8_t)length; + params2s.fanout = 1; + params2s.depth = 1; + libblake_blake2s_init(&state2s, ¶ms2s, NULL); + } else { + memset(¶ms2b, 0, sizeof(params2b)); + params2b.digest_len = (uint_least8_t)length; + params2b.fanout = 1; + params2b.depth = 1; + libblake_blake2b_init(&state2b, ¶ms2b, NULL); + } + for (;;) { + if (len == size) + buf = erealloc(buf, size += 8 << 10); + r = read(fd, &buf[len], size - len); + if (r <= 0) { + if (!r) + break; + if (errno == EINTR) + continue; + fprintf(stderr, "%s: %s: %s\n", argv0, fname, strerror(errno)); + free(buf); + return -1; + } + len += (size_t)r; + if (!decode_hex) { + if (flag_small) + off += libblake_blake2s_update(&state2s, &buf[off], len - off); + else + off += libblake_blake2b_update(&state2b, &buf[off], len - off); + if (off == len) + off = 0; + } + } + if (off) + memmove(&buf[0], &buf[off], len -= off); + if (decode_hex) { + len = libblake_decode_hex(buf, len, buf, &ok); + if (!ok) { + fprintf(stderr, "%s: %s: %s\n", argv0, fname, "invalid hexadecimal input"); + free(buf); + return -1; + } + } + if (flag_small) + req = libblake_blake2s_digest_get_required_input_size(len); + else + req = libblake_blake2b_digest_get_required_input_size(len); + if (req > size) + buf = erealloc(buf, size); + if (flag_small) + libblake_blake2s_digest(&state2s, buf, len, 0, hashlen / 8, hash); + else + libblake_blake2b_digest(&state2b, buf, len, 0, hashlen / 8, hash); + free(buf); + return 0; +} + +static int +hash_fd_blake2bsx(int fd, const char *fname, int decode_hex, unsigned char hash[]) +{ + struct libblake_blake2xb_state state2xb; + struct libblake_blake2xb_params params2xb; + struct libblake_blake2xs_state state2xs; + struct libblake_blake2xs_params params2xs; + char *buf = NULL; + size_t size = 0; + size_t len = 0; + size_t off = 0; + size_t req; + size_t i, n; + ssize_t r; + int ok; + if (flag_small) { + memset(¶ms2xs, 0, sizeof(params2xs)); + params2xs.digest_len = (uint_least8_t)length; + params2xs.fanout = 1; + params2xs.depth = 1; + params2xs.xof_len = (uint_least16_t)xlength; + libblake_blake2xs_init(&state2xs, ¶ms2xs, NULL); + } else { + memset(¶ms2xb, 0, sizeof(params2xb)); + params2xb.digest_len = (uint_least8_t)length; + params2xb.fanout = 1; + params2xb.depth = 1; + params2xb.xof_len = (uint_least32_t)xlength; + libblake_blake2xb_init(&state2xb, ¶ms2xb, NULL); + } + for (;;) { + if (len == size) + buf = erealloc(buf, size += 8 << 10); + r = read(fd, &buf[len], size - len); + if (r <= 0) { + if (!r) + break; + if (errno == EINTR) + continue; + fprintf(stderr, "%s: %s: %s\n", argv0, fname, strerror(errno)); + free(buf); + return -1; + } + len += (size_t)r; + if (!decode_hex) { + if (flag_small) + off += libblake_blake2xs_update(&state2xs, &buf[off], len - off); + else + off += libblake_blake2xb_update(&state2xb, &buf[off], len - off); + if (off == len) + off = 0; + } + } + if (off) + memmove(&buf[0], &buf[off], len -= off); + if (decode_hex) { + len = libblake_decode_hex(buf, len, buf, &ok); + if (!ok) { + fprintf(stderr, "%s: %s: %s\n", argv0, fname, "invalid hexadecimal input"); + free(buf); + return -1; + } + } + if (flag_small) + req = libblake_blake2xs_predigest_get_required_input_size(&state2xs); + else + req = libblake_blake2xb_predigest_get_required_input_size(&state2xb); + if (req > size) + buf = erealloc(buf, size); + if (flag_small) + libblake_blake2xs_predigest(&state2xs, buf, len, 0); + else + libblake_blake2xb_predigest(&state2xb, buf, len, 0); + if (flag_small) { + for (i = 0; i * 32 < hashlen / 8; i++) { /* TODO this could be done parallel (also below) */ + n = (i + 1) * 32 > hashlen / 8 ? hashlen / 8 - i * 32 : 32; + libblake_blake2xs_digest(&state2xs, (uint_least32_t)i, (uint_least8_t)n, &hash[i * 32]); + } + } else { + for (i = 0; i * 64 < hashlen / 8; i++) { + n = (i + 1) * 64 > hashlen / 8 ? hashlen / 8 - i * 64 : 64; + libblake_blake2xb_digest(&state2xb, (uint_least32_t)i, (uint_least8_t)n, &hash[i * 64]); + } + } + free(buf); + return 0; +} + +int +hash_fd(int fd, const char *fname, int decode_hex, unsigned char hash[]) +{ + int ret; + + if (flag_extended) + ret = hash_fd_blake2bsx(fd, fname, decode_hex, hash); + else + ret = hash_fd_blake2bs(fd, fname, decode_hex, hash); + + return ret; +} + +int +main(int argc, char *argv[]) +{ + int status = 0; + int output_case; + char newline; + + ARGBEGIN { + case 'c': + flag_check = 1; + break; + case 'B': + flag_binary = 1; + break; + case 'L': + flag_lower = 1; + flag_upper = 0; + break; + case 'U': + flag_upper = 1; + flag_lower = 0; + break; + case 's': + flag_small = 1; + break; + case 'x': + flag_hex = 1; + break; + case 'z': + flag_zero = 1; + break; + case 'l': + if (length) + usage(); + length = atoi(ARG()); + if (length & 7 || !length || length > 512) { + fprintf(stderr, "%s: valid arguments for -l\n", argv0); + return 2; + } + break; + case 'X': + if (flag_extended) + usage(); + flag_extended = 1; + xlength = atoll(ARG()); + if (xlength & 7 || !xlength || xlength > 34359738360LL) { + fprintf(stderr, "%s: valid arguments for -X\n", argv0); + return 2; + } + break; + default: + usage(); + } ARGEND; + + if (flag_check + flag_binary + flag_lower + flag_upper > 1 || + (length && flag_extended)) + usage(); + + if (!length) + length = flag_small ? 256 : 512; + else if (flag_small && length > 256) + fprintf(stderr, "%s: valid arguments for -l\n", argv0); + else if (flag_small && xlength > 524280LL) + fprintf(stderr, "%s: valid arguments for -X\n", argv0); + + hashlen = flag_extended ? (size_t)xlength : (size_t)length; + length /= 8; + xlength /= 8; + + newline = flag_zero ? '\0' : '\n'; + if (flag_check) { + if (!argc) { + status |= -check_and_print("-", hashlen, flag_hex, newline); + } else { + for (; *argv; argv++) + status |= -check_and_print(*argv, hashlen, flag_hex, newline); + } + } else { + output_case = flag_binary ? -1 : flag_upper; + if (!argc) { + status |= -hash_and_print("-", hashlen, flag_hex, newline, output_case); + } else { + for (; *argv; argv++) + status |= -hash_and_print(*argv, hashlen, flag_hex, newline, output_case); + } + } + + if (fflush(stdout) || ferror(stdout) || fclose(stdout)) { + fprintf(stderr, "%s: %s\n", argv0, strerror(errno)); + return 2; + } + return status; +} |