diff options
-rw-r--r-- | README | 66 | ||||
-rw-r--r-- | b224sum.1 | 4 | ||||
-rw-r--r-- | b256sum.1 | 4 | ||||
-rw-r--r-- | b2sum.1 | 66 | ||||
-rw-r--r-- | b2sum.c | 89 | ||||
-rw-r--r-- | b384sum.1 | 4 | ||||
-rw-r--r-- | b512sum.1 | 4 | ||||
-rw-r--r-- | bsum.1 | 8 | ||||
-rw-r--r-- | bsum.c | 2 | ||||
-rw-r--r-- | common.c | 74 | ||||
-rw-r--r-- | common.h | 2 | ||||
-rw-r--r-- | test.c | 2 |
12 files changed, 292 insertions, 33 deletions
@@ -2,12 +2,13 @@ NAME blakesum - Checksum utilities for the BLAKE-family of hashing functions SYNOPSIS - bsum [-l bits] [-c | -B | -L | -U] [-xz] [file] ... - b224sum [-c | -B | -L | -U] [-xz] [file] ... - b256sum [-c | -B | -L | -U] [-xz] [file] ... - b384sum [-c | -B | -L | -U] [-xz] [file] ... - b512sum [-c | -B | -L | -U] [-xz] [file] ... - b2sum [-l bits | -X bits] [-c | -B | -L | -U] [-sxz] [file] ... + bsum [-l bits] [-S salt] [-c | -B | -L | -U] [-xz] [file] ... + b224sum [-S salt] [-c | -B | -L | -U] [-xz] [file] ... + b256sum [-S salt] [-c | -B | -L | -U] [-xz] [file] ... + b384sum [-S salt] [-c | -B | -L | -U] [-xz] [file] ... + b512sum [-S salt] [-c | -B | -L | -U] [-xz] [file] ... + b2sum [-l bits | -X bits] [-K key] [-P pepper] [-S salt] \ + [-c | -B | -L | -U] [-sxz] [file] ... DESCRIPTION Print or check BLAKE, BLAKE2, or BLAKE2X checksums. @@ -38,6 +39,21 @@ OPTIONS or <tab>, or if they contain a <newline>, unless the -z option is also used. + -K key + (Only available in b2sum) + Specify a key (which is used for MAC and PRF), that is + up to 32 bytes (if the -s option is used) or 64 bytes + (otherwise) long, that the algorithm shall use. The + key shall be expressed in hexadecimal: each byte in the + key shall be expressed, from left to right, as a pairs + of hexadecimal digits where highest bits in each byte + is stored in the left digit in its pair and the lowest + bits in each byte is stored in the right digit in its + pair. No delimiters are used, so for a 4 byte key where + each byte's value is its index, the key is expessed as + 00010203, however each letter may be either small or + capital. The key may not be empty. + -L Output checksums in lower-case hexadecimal representation. (Default) @@ -52,6 +68,44 @@ OPTIONS the -s option is used between 8 and 256, inclusively. (Default is maximum.) + -P pepper + (Only available in b2sum) + Specify an 8-byte (if the -s option is used) or 16-byte + pepper ("personalisation") (otherwise) that the algorithm + shall use. This pepper shall be expressed in full length + hexadecimal: 16 (for 8-byte) or 32 (for 16-byte) + hexadecimal digits, or rather 8 or 16 pairs of hexadecimal + digits, ordered from left to right to specify the values + from index 0 to the last byte. In each pair, the left + digit stores the high bits of the byte, and the right + digit stores the low bits of the byte. For example, the + digit pair 80 represents a byte with the decimal value + 128, whereas the digit pair 08 represents a byte with + the decimal value 8. The pairs are joined without any + delimiters, and no byte may be omitted. So, for a 8 byte + pepper where each byte's value is its index, the pepper + is expressed as 0001020304050607, however each letter + may be either small or capital. If no pepper is specified, + an all-zeroes pepper is used. + + -S salt + Specify a salt that the algorithm shall use. The + size of the salt depends on which algorithm used. + This salt shall be expressed in full length hexadecimal. + The decimal digits are logically groupped in pairs that + are ordered from left to right to specify the values + from index 0 to the last byte. In each pair, the left + digit stores the high bits of the byte, and the right + digit stores the low bits of the byte. For example, + the digit pair 80 represents a byte with the decimal + value 128, whereas the digit pair 08 represents a byte + with the decimal value 8. The pairs are joined without + any delimiters, and no byte may be omitted. So, for a + 16 byte salt where each byte's value is its index, the + salt is expressed as 000102030405060708090a0b0c0d0e0f, + however each letter may be either small or capital. If + no salt is specified, an all-zeroes salt is used. + -s (Only available in b2sum) Use BLAKE2s instead of BLAKE2b. @@ -3,7 +3,7 @@ b224sum - Compute and check BLAKE-224 message digests .SH SYNOPSIS .B b224sum -[-c | -B | -L | -U] [-S salt] [-xz] +[-S salt] [-c | -B | -L | -U] [-xz] .RI [ file "] ..." .SH DESCRIPTION Print or check BLAKE-224 checksums. @@ -49,7 +49,7 @@ digit pair represents a byte with the decimal value 8. The pairs are joined without any delimiters, and no byte may be omitted. So, for a salt where each byte's value is its -index, the salt is expressed as, +index, the salt is expressed as .BR 000102030405060708090a0b0c0d0e0f , however each letter may be either small or capital. If no salt is specified, an all-zeroes salt is used. @@ -3,7 +3,7 @@ b256sum - Compute and check BLAKE-256 message digests .SH SYNOPSIS .B b256sum -[-c | -B | -L | -U] [-S salt] [-xz] +[-S salt] [-c | -B | -L | -U] [-xz] .RI [ file "] ..." .SH DESCRIPTION Print or check BLAKE-256 checksums. @@ -49,7 +49,7 @@ digit pair represents a byte with the decimal value 8. The pairs are joined without any delimiters, and no byte may be omitted. So, for a salt where each byte's value is its -index, the salt is expressed as, +index, the salt is expressed as .BR 000102030405060708090a0b0c0d0e0f , however each letter may be either small or capital. If no salt is specified, an all-zeroes salt is used. @@ -3,7 +3,7 @@ b2sum - Compute and check BLAKE2 message digests .SH SYNOPSIS .B b2sum -[-l bits | -X bits] [-c | -B | -L | -U] [-sxz] +[-l bits | -X bits] [-K key] [-P pepper] [-S salt] [-c | -B | -L | -U] [-sxz] .RI [ file "] ..." .SH DESCRIPTION Print or check BLAKE2 checksums, using BLAKE2b by default. @@ -31,6 +31,22 @@ contain a <newline>, unless the .B -z option is also used. .TP +.BI "-K " key +Specify a key (which is used for MAC and PRF), that is +up to 32 bytes (if the +.B -s +option is used) or 64 bytes (otherwise) long, that the +algorithm shall use. The key shall be expressed in +hexadecimal: each byte in the key shall be expressed, from +left to right, as a pairs of hexadecimal digits where highest +bits in each byte is stored in the left digit in its pair and +the lowest bits in each byte is stored in the right digit in +its pair. No delimiters are used, so for a 4 byte key where +each byte's value is its index, the key is expessed as +.BR 00010203 , +however each letter may be either small or capital. +The key may not be empty. +.TP .B -L Output checksums in lower-case hexadecimal representation. (Default) .TP @@ -41,6 +57,54 @@ between 8 and 512, inclusively, or if the option is used between 8 and 256, inclusively. (Default is maximum.) .TP +.BI "-P " pepper +Specify an 8-byte (if the +.B -s +option is used) or 16-byte pepper (\(dqpersonalisation\(dq) +(otherwise) that the algorithm shall use. This pepper shall +be expressed in full length hexadecimal: 16 (for 8-byte) or 32 +(for 16-byte) hexadecimal digits, or rather 8 or 16 pairs +of hexadecimal digits, ordered from left to right to specify +the values from index 0 to the last byte. In each pair, +the left digit stores the high bits of the byte, and the +right digit stores the low bits of the byte. For example, +the digit pair +.B 80 +represents a byte with the decimal value 128, whereas the +digit pair +.B 08 +represents a byte with the decimal value 8. The pairs +are joined without any delimiters, and no byte may be +omitted. So, for a 8 byte pepper where each byte's value +is its index, the pepper is expressed as +.BR 0001020304050607 , +however each letter may be either small or capital. +If no pepper is specified, an all-zeroes pepper is used. +.TP +.BI "-S " salt +Specify a 8-byte (if the +.B -s +option is used) or 16-byte salt +(otherwise) that the algorithm shall use. This salt shall +be expressed in full length hexadecimal: 16 (for 8-byte) or 32 +(for 16-byte) hexadecimal digits, or rather 8 or 16 pairs +of hexadecimal digits, ordered from left to right to specify +the values from index 0 to the last byte. In each pair, +the left digit stores the high bits of the byte, and the +right digit stores the low bits of the byte. For example, +the digit pair +.B 80 +represents a byte with the decimal value 128, whereas the +digit pair +.B 08 +represents a byte with the decimal value 8. The pairs +are joined without any delimiters, and no byte may be +omitted. So, for a 8 byte salt where each byte's value +is its index, the salt is expressed as +.BR 0001020304050607 , +however each letter may be either small or capital. +If no salt is specified, an all-zeroes salt is used. +.TP .B -s Use BLAKE2s instead of BLAKE2b. .TP @@ -13,16 +13,20 @@ static int flag_hex = 0; static int flag_zero = 0; static int length = 0; static long long int xlength = 0; +static void *key = NULL; +static size_t key_len = 0; +static void *salt = NULL; +static void *pepper = NULL; static size_t hashlen; static void usage(void) { - /* TODO add support for key (-K), salt (-S), and personalization (-P) */ /* TODO add support for parallel versions */ /* TODO add support for tree hashing */ - fprintf(stderr, "usage: %s [-l bits | -X bits] [-c | -B | -L | -U] [-sxz] [file] ...", argv0); + fprintf(stderr, "usage: %s [-l bits | -X bits] [-K key] [-P pepper] [-S salt]" + " [-c | -B | -L | -U] [-sxz] [file] ...\n", argv0); exit(2); } @@ -43,15 +47,37 @@ hash_fd_blake2bs(int fd, const char *fname, int decode_hex, unsigned char hash[] if (flag_small) { memset(¶ms2s, 0, sizeof(params2s)); params2s.digest_len = (uint_least8_t)length; + params2s.key_len = (uint_least8_t)key_len; params2s.fanout = 1; params2s.depth = 1; + if (salt) + memcpy(params2s.salt, salt, sizeof(params2s.salt)); + if (pepper) + memcpy(params2s.pepper, pepper, sizeof(params2s.pepper)); libblake_blake2s_init(&state2s, ¶ms2s); + if (key) { + buf = erealloc(buf, size = 8 << 10); + len = 64; + memcpy(buf, key, len); + off += libblake_blake2s_update(&state2s, key, len); + } } else { memset(¶ms2b, 0, sizeof(params2b)); params2b.digest_len = (uint_least8_t)length; + params2b.key_len = (uint_least8_t)key_len; params2b.fanout = 1; params2b.depth = 1; + if (salt) + memcpy(params2b.salt, salt, sizeof(params2b.salt)); + if (pepper) + memcpy(params2b.pepper, pepper, sizeof(params2b.pepper)); libblake_blake2b_init(&state2b, ¶ms2b); + if (key) { + buf = erealloc(buf, size = 8 << 10); + len = 128; + memcpy(buf, key, len); + off += libblake_blake2b_update(&state2b, key, len); + } } for (;;) { if (len == size) @@ -118,17 +144,39 @@ hash_fd_blake2xbs(int fd, const char *fname, int decode_hex, unsigned char hash[ if (flag_small) { memset(¶ms2xs, 0, sizeof(params2xs)); params2xs.digest_len = (uint_least8_t)length; + params2xs.key_len = (uint_least8_t)key_len; params2xs.fanout = 1; params2xs.depth = 1; params2xs.xof_len = (uint_least16_t)xlength; + if (salt) + memcpy(params2xs.salt, salt, sizeof(params2xs.salt)); + if (pepper) + memcpy(params2xs.pepper, pepper, sizeof(params2xs.pepper)); libblake_blake2xs_init(&state2xs, ¶ms2xs); + if (key) { + buf = erealloc(buf, size = 8 << 10); + len = 64; + memcpy(buf, key, len); + off += libblake_blake2xs_update(&state2xs, key, len); + } } else { memset(¶ms2xb, 0, sizeof(params2xb)); params2xb.digest_len = (uint_least8_t)length; + params2xb.key_len = (uint_least8_t)key_len; params2xb.fanout = 1; params2xb.depth = 1; params2xb.xof_len = (uint_least32_t)xlength; + if (salt) + memcpy(params2xb.salt, salt, sizeof(params2xb.salt)); + if (pepper) + memcpy(params2xb.pepper, pepper, sizeof(params2xb.pepper)); libblake_blake2xb_init(&state2xb, ¶ms2xb); + if (key) { + buf = erealloc(buf, size = 8 << 10); + len = 128; + memcpy(buf, key, len); + off += libblake_blake2xb_update(&state2xb, key, len); + } } for (;;) { if (len == size) @@ -204,6 +252,12 @@ hash_fd(int fd, const char *fname, int decode_hex, unsigned char hash[]) int main(int argc, char *argv[]) { + const char *key_str = NULL; + uint_least8_t key_buf[128]; + const char *salt_str = NULL; + uint_least8_t salt_buf[16]; + const char *pepper_str = NULL; + uint_least8_t pepper_buf[16]; int status = 0; int output_case; char newline; @@ -223,6 +277,21 @@ main(int argc, char *argv[]) flag_upper = 1; flag_lower = 0; break; + case 'K': + if (key_str) + usage(); + key_str = ARG(); + break; + case 'S': + if (salt_str) + usage(); + salt_str = ARG(); + break; + case 'P': + if (pepper_str) + usage(); + pepper_str = ARG(); + break; case 's': flag_small = 1; break; @@ -266,6 +335,22 @@ main(int argc, char *argv[]) else if (flag_small && xlength > 524280LL) fprintf(stderr, "%s: valid arguments for -X\n", argv0); + if (key_str) { + memset(key_buf, 0, sizeof(key_buf)); + key_len = parse_key(key_buf, key_str, flag_small ? 32 : 64); + key = key_buf; + } + + if (pepper_str) { + parse_pepper(pepper_buf, pepper_str, flag_small ? 8 : 16); + pepper = pepper_buf; + } + + if (salt_str) { + parse_salt(salt_buf, salt_str, flag_small ? 8 : 16); + salt = salt_buf; + } + hashlen = flag_extended ? (size_t)xlength : (size_t)length; length /= 8; xlength /= 8; @@ -3,7 +3,7 @@ b384sum - Compute and check BLAKE-384 message digests .SH SYNOPSIS .B b384sum -[-c | -B | -L | -U] [-S salt] [-xz] +[-S salt] [-c | -B | -L | -U] [-xz] .RI [ file "] ..." .SH DESCRIPTION Print or check BLAKE-384 checksums. @@ -49,7 +49,7 @@ digit pair represents a byte with the decimal value 8. The pairs are joined without any delimiters, and no byte may be omitted. So, for a salt where each byte's value is its -index, the salt is expressed as, +index, the salt is expressed as .BR 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f , however each letter may be either small or capital. If no salt is specified, an all-zeroes salt is used. @@ -3,7 +3,7 @@ b512sum - Compute and check BLAKE-512 message digests .SH SYNOPSIS .B b512sum -[-c | -B | -L | -U] [-S salt] [-xz] +[-S salt] [-c | -B | -L | -U] [-xz] .RI [ file "] ..." .SH DESCRIPTION Print or check BLAKE-512 checksums. @@ -49,7 +49,7 @@ digit pair represents a byte with the decimal value 8. The pairs are joined without any delimiters, and no byte may be omitted. So, for a salt where each byte's value is its -index, the salt is expressed as, +index, the salt is expressed as .BR 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f , however each letter may be either small or capital. If no salt is specified, an all-zeroes salt is used. @@ -3,7 +3,7 @@ bsum - Compute and check BLAKE message digests .SH SYNOPSIS .B bsum -[-l bits] [-c | -B | -L | -U] [-S salt] [-xz] +[-l bits] [-S salt] [-c | -B | -L | -U] [-xz] .RI [ file "] ..." .SH DESCRIPTION Print or check BLAKE checksums. @@ -42,8 +42,8 @@ are 224 (default), 256, 384, and 512. Specify a 16-byte (for the 224 and 256 bit versions) or 32-byte salt (for the 384 and 512 bit versions) that the BLAKE algorithm shall use. This salt shall be expressed -in full length hexadecimal: 32 (for 16-bytes) or 64 -(for 32-bytes) hexadecimal digits, or rather 16 or 32 pairs +in full length hexadecimal: 32 (for 16-byte) or 64 +(for 32-byte) hexadecimal digits, or rather 16 or 32 pairs of hexadecimal digits, ordered from left to right to specify the values from index 0 to the last byte. In each pair, the left digit stores the high bits of the byte, and the @@ -56,7 +56,7 @@ digit pair represents a byte with the decimal value 8. The pairs are joined without any delimiters, and no byte may be omitted. So, for a 16 byte salt where each byte's value -is its index, the salt is expressed as, +is its index, the salt is expressed as .BR 000102030405060708090a0b0c0d0e0f , however each letter may be either small or capital. If no salt is specified, an all-zeroes salt is used. @@ -17,7 +17,7 @@ static void *salt = NULL; static void usage(void) { - fprintf(stderr, "usage: %s%s [-c | -B | -L | -U] [-S salt] [-xz] [file] ...", + fprintf(stderr, "usage: %s%s [-S salt] [-c | -B | -L | -U] [-xz] [file] ...\n", argv0, lenght_by_command_name ? "" : " [-l bits]"); exit(2); } @@ -227,9 +227,8 @@ hash_and_print(const char *path, size_t hashlen, int decode_hex, char newline, i return 0; } - -void -parse_salt(uint_least8_t *salt, const char *s, size_t required_length) +static void +parse_salt_or_pepper(uint_least8_t *out, const char *s, size_t required_length, const char *type) { size_t i; @@ -239,8 +238,8 @@ parse_salt(uint_least8_t *salt, const char *s, size_t required_length) if (!isxdigit(s[0]) || !isxdigit(s[1])) goto not_hexadecimal; - salt[i] = (uint_least8_t)((((s[0] & 15) + (s[0] > '9' ? 9 : 0)) << 4) | - (s[1] & 15) + (s[1] > '9' ? 9 : 0)); + out[i] = (uint_least8_t)((((s[0] & 15) + (s[0] > '9' ? 9 : 0)) << 4) | + (s[1] & 15) + (s[1] > '9' ? 9 : 0)); } if (*s) @@ -249,16 +248,71 @@ parse_salt(uint_least8_t *salt, const char *s, size_t required_length) return; not_hexadecimal: - fprintf(stderr, "%s: specified salt contains non-hexadecimal-digit character\n", argv0); + fprintf(stderr, "%s: specified %s contains non-hexadecimal-digit character\n", argv0, type); exit(2); too_short: - fprintf(stderr, "%s: specified salt is shorter than expected, should be %zu hexadecimal digits\n", - argv0, required_length * 2); + fprintf(stderr, "%s: specified %s is shorter than expected, should be %zu hexadecimal digits\n", + argv0, type, required_length * 2); + exit(2); + +too_long: + fprintf(stderr, "%s: specified %s is longer than expected, should be %zu hexadecimal digits\n", + argv0, type, required_length * 2); + exit(2); +} + +void +parse_salt(uint_least8_t *salt, const char *s, size_t required_length) +{ + parse_salt_or_pepper(salt, s, required_length, "salt"); +} + +void +parse_pepper(uint_least8_t *pepper, const char *s, size_t required_length) +{ + parse_salt_or_pepper(pepper, s, required_length, "pepper"); +} + +size_t +parse_key(uint_least8_t *key, const char *s, size_t maximum_length) +{ + size_t i; + + if (!*s) + goto empty_key; + + for (i = 0; i < maximum_length; i++, s = &s[2]) { + if (!s[0]) + break; + if (!s[1]) + goto odd_length; + if (!isxdigit(s[0]) || !isxdigit(s[1])) + goto not_hexadecimal; + + key[i] = (uint_least8_t)((((s[0] & 15) + (s[0] > '9' ? 9 : 0)) << 4) | + (s[1] & 15) + (s[1] > '9' ? 9 : 0)); + } + + if (*s) + goto too_long; + + return i; + +empty_key: + fprintf(stderr, "%s: specified key is empty\n", argv0); + exit(2); + +odd_length: + fprintf(stderr, "%s: specified key contains an odd number of hexadecimal digits\n", argv0); + exit(2); + +not_hexadecimal: + fprintf(stderr, "%s: specified key contains non-hexadecimal-digit character\n", argv0); exit(2); too_long: - fprintf(stderr, "%s: specified salt is longer than expected, should be %zu hexadecimal digits\n", - argv0, required_length * 2); + fprintf(stderr, "%s: specified key is longer than allowed, should be at most %zu hexadecimal digits\n", + argv0, maximum_length * 2); exit(2); } @@ -20,6 +20,8 @@ int open_file(const char *path, int *closep); int check_and_print(const char *path, size_t hashlen, int decode_hex, char newline); int hash_and_print(const char *path, size_t hashlen, int decode_hex, char newline, int output_case); void parse_salt(uint_least8_t *salt, const char *s, size_t required_length); +void parse_pepper(uint_least8_t *pepper, const char *s, size_t required_length); +size_t parse_key(uint_least8_t *key, const char *s, size_t maximum_length); /* *sum.c */ int hash_fd(int fd, const char *fname, int decode_hex, unsigned char hash[]); @@ -363,7 +363,7 @@ main(void) failed |= check_kat_file("kat/blake2b", "BLAKE2b", &hash_blake2b); failed |= check_kat_file("kat/blake2xs", "BLAKE2Xs", &hash_blake2xs); failed |= check_kat_file("kat/blake2xb", "BLAKE2Xb", &hash_blake2xb); - /* TODO test b2sum -cLUxz, implicit -L, restrictions on -l/-X, and file operand */ + /* TODO test b2sum -cLUxzSPK, implicit -L, restrictions on -l/-X, and file operand */ return failed; } |