diff options
author | Mattias Andrée <maandree@kth.se> | 2024-09-01 16:34:46 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2024-09-01 16:34:46 +0200 |
commit | d737d34b436f673173695c4c772f0ddef9fe7837 (patch) | |
tree | f6bf400809124d411eaff38fe2c9d24842c8d23a /libhashsum | |
parent | m fix (diff) | |
download | libhashsum-d737d34b436f673173695c4c772f0ddef9fe7837.tar.gz libhashsum-d737d34b436f673173695c4c772f0ddef9fe7837.tar.bz2 libhashsum-d737d34b436f673173695c4c772f0ddef9fe7837.tar.xz |
Add support for BLAKE2 (but not tree-hashing)
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r-- | libhashsum.7 | 5 | ||||
-rw-r--r-- | libhashsum.h | 77 | ||||
-rw-r--r-- | libhashsum/internal.h | 16 | ||||
-rw-r--r-- | libhashsum_get_algorithm_from_string.3 | 18 | ||||
-rw-r--r-- | libhashsum_get_algorithm_from_string.c | 4 | ||||
-rw-r--r-- | libhashsum_init_blake2b_hasher.c | 202 | ||||
-rw-r--r-- | libhashsum_init_blake2s_hasher.c | 201 | ||||
-rw-r--r-- | libhashsum_init_hasher.3 | 12 | ||||
-rw-r--r-- | libhashsum_init_hasher.c | 4 | ||||
-rw-r--r-- | libhashsum_init_hasher_from_string.3 | 2 | ||||
-rw-r--r-- | libhashsum_init_hasher_from_string.c | 172 |
11 files changed, 675 insertions, 38 deletions
diff --git a/libhashsum.7 b/libhashsum.7 index 1945b99..ec8dcb1 100644 --- a/libhashsum.7 +++ b/libhashsum.7 @@ -20,7 +20,7 @@ Link with (unless support for Keccak, SHA-3, SHAKE, and RawSHAKE was excluded) .br .I -lblake -(unless support for BLAKE was excluded). +(unless support for BLAKE and BLAKE2 was excluded). .SH DESCRIPTION The @@ -46,6 +46,9 @@ RawSHAKE128, RawSHAKE256, RawSHAKE512 .TP Via libblake>=1.1 BLAKE224, BLAKE256, BLAKE384, BLAKE512 +.TP +Via libblake>=3.0 +BLAKE2s, BLAKE2b .PP For each hash function, .B libhashsum diff --git a/libhashsum.h b/libhashsum.h index 780b567..777176b 100644 --- a/libhashsum.h +++ b/libhashsum.h @@ -186,6 +186,7 @@ /** * The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHAKE256` + * (using default hash size) * * @since 1.0 */ @@ -193,6 +194,7 @@ /** * The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHAKE512` + * (using default hash size) * * @since 1.0 */ @@ -200,6 +202,7 @@ /** * The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_RAWSHAKE128` + * (using default hash size) * * @since 1.0 */ @@ -207,6 +210,7 @@ /** * The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_RAWSHAKE256` + * (using default hash size) * * @since 1.0 */ @@ -214,6 +218,7 @@ /** * The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_RAWSHAKE512` + * (using default hash size) * * @since 1.0 */ @@ -247,6 +252,22 @@ */ #define LIBHASHSUM_BLAKE512_HASH_SIZE 64 +/** + * The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_BLAKE2S` + * (using default/maximium hash size) + * + * @since 1.0 + */ +#define LIBHASHSUM_BLAKE2S_HASH_SIZE 32 + +/** + * The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_BLAKE2B` + * (using default/maximium hash size) + * + * @since 1.0 + */ +#define LIBHASHSUM_BLAKE2B_HASH_SIZE 64 + #if defined(__GNUC__) # pragma GCC diagnostic push @@ -297,7 +318,9 @@ enum libhashsum_algorithm { LIBHASHSUM_BLAKE224, /**< BLAKE224 (BLAKE, BLAKEs) */ LIBHASHSUM_BLAKE256, /**< BLAKE256 (BLAKE, BLAKEs) */ LIBHASHSUM_BLAKE384, /**< BLAKE384 (BLAKE, BLAKEb) */ - LIBHASHSUM_BLAKE512 /**< BLAKE512 (BLAKE, BLAKEb) */ + LIBHASHSUM_BLAKE512, /**< BLAKE512 (BLAKE, BLAKEb) */ + LIBHASHSUM_BLAKE2S, /**< BLAKE2s (BLAKE2) */ + LIBHASHSUM_BLAKE2B /**< BLAKE2b (BLAKE2) */ }; @@ -1214,5 +1237,57 @@ int libhashsum_init_blakeb_hasher(struct libhashsum_hasher *this, size_t hashbit LIBHASHSUM_1_NONNULL_ int libhashsum_init_blake_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, size_t saltbytes); +/** + * Create an initialised state for BLAKE2s (BLAKE2) + * hashing and return hash functions and details + * + * @param this The output parameter for the functions, details, and state + * @param hashbits Hash output size in bits, must be an multiple of 8 between + * 8 and 256 (inclusively), or 0 for the maximum size + * @param salt `NULL` (for all zeroes) or a 8-byte salt + * @param pepper `NULL` (for all zeroes) or a 8-byte pepper + * @param key Key or `NULL` for unkeyed mode, + * @param keybits The number of byts in `key` (0 if `key` is `NULL`), + * which must be a multiple of 8 no greater than 256 + * @return 0 on success, -1 on failure + * + * @throws EINVAL `hashbits` is greater than 256 + * @throws EINVAL `hashbits` is not a multiple of 8 + * @throws EINVAL `keybits` is greater than 256 + * @throws EINVAL `keybits` is not a multiple of 8 + * @throws ENOSYS Support was excluded at compile time + * + * @since 1.0 + */ +LIBHASHSUM_1_NONNULL_ +int libhashsum_init_blake2s_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, /* TODO man, test */ + const void *pepper, const void *key, size_t keybits); + +/** + * Create an initialised state for BLAKE2b (BLAKE2) + * hashing and return hash functions and details + * + * @param this The output parameter for the functions, details, and state + * @param hashbits Hash output size in bits, must be an multiple of 8 between + * 8 and 512 (inclusively), or 0 for the maximum size + * @param salt `NULL` (for all zeroes) or a 16-byte salt + * @param pepper `NULL` (for all zeroes) or a 16-byte pepper + * @param key Key or `NULL` for unkeyed mode, + * @param keybits The number of byts in `key` (0 if `key` is `NULL`), + * which must be a multiple of 8 no greater than 512 + * @return 0 on success, -1 on failure + * + * @throws EINVAL `hashbits` is greater than 512 + * @throws EINVAL `hashbits` is not a multiple of 8 + * @throws EINVAL `keybits` is greater than 512 + * @throws EINVAL `keybits` is not a multiple of 8 + * @throws ENOSYS Support was excluded at compile time + * + * @since 1.0 + */ +LIBHASHSUM_1_NONNULL_ +int libhashsum_init_blake2b_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, /* TODO man, test */ + const void *pepper, const void *key, size_t keybits); + #endif diff --git a/libhashsum/internal.h b/libhashsum/internal.h index b75cdd9..e02a417 100644 --- a/libhashsum/internal.h +++ b/libhashsum/internal.h @@ -155,9 +155,23 @@ union libhashsum_state { uint8_t buf[256]; char algostr[81]; } blake512; /* size = 449 */ + + struct { + struct libblake_blake2s_state s; + char algostr[130]; + unsigned char buf[64]; + unsigned char keybytes; + } blake2s; /* size = 243 */ + + struct { + struct libblake_blake2b_state s; + char algostr[226]; + unsigned char buf[128]; + unsigned char keybytes; + } blake2b; /* size = 451 */ #endif - /* libblake: 48(2s), 96(2b), 144(2Xs), 276(2Xb) */ + /* libblake: 144(2Xs), 276(2Xb) */ char max_size[1648]; #define libhashsum_init_hasher libhashsum_init_hasher__1648 diff --git a/libhashsum_get_algorithm_from_string.3 b/libhashsum_get_algorithm_from_string.3 index c039da6..b01d1c7 100644 --- a/libhashsum_get_algorithm_from_string.3 +++ b/libhashsum_get_algorithm_from_string.3 @@ -301,6 +301,23 @@ is .RB \(dq BLAKE-512 \(dq or .RB \(dq B512 \(dq. +.TP +.B LIBHASHSUM_BLAKE2S +BLAKE2s (BLAKE2) + +.I algorithm +is +.RB \(dq BLAKE2s \(dq +or +.RB \(dq B2s \(dq. +.TP +BLAKE2b (BLAKE2) + +.I algorithm +is +.RB \(dq BLAKE2b \(dq +or +.RB \(dq B2b \(dq. .PP The function is case-insensitive, and tolerates skipping dashes @@ -309,6 +326,7 @@ that are not immediately after a digit. Additionally, it will ignore the substring .RB \(dq sum \(dq if it is added to the end of the function name. + .PP The function .I does not diff --git a/libhashsum_get_algorithm_from_string.c b/libhashsum_get_algorithm_from_string.c index 9740510..07d97e5 100644 --- a/libhashsum_get_algorithm_from_string.c +++ b/libhashsum_get_algorithm_from_string.c @@ -97,6 +97,10 @@ libhashsum_get_algorithm_from_string(enum libhashsum_algorithm *algorithm_out, c *algorithm_out = LIBHASHSUM_BLAKE384; else if (equiv(algorithm, "BLAKE-512[]") || equiv(algorithm, "B512[]")) *algorithm_out = LIBHASHSUM_BLAKE512; + else if (equiv(algorithm, "BLAKE-2s[]") || equiv(algorithm, "B2s[]")) + *algorithm_out = LIBHASHSUM_BLAKE2S; + else if (equiv(algorithm, "BLAKE-2b[]") || equiv(algorithm, "B2b[]")) + *algorithm_out = LIBHASHSUM_BLAKE2B; else return 0; return 1; diff --git a/libhashsum_init_blake2b_hasher.c b/libhashsum_init_blake2b_hasher.c new file mode 100644 index 0000000..57be6fe --- /dev/null +++ b/libhashsum_init_blake2b_hasher.c @@ -0,0 +1,202 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifdef SUPPORT_BLAKE2B + + +#define BLAKE2B_BLOCK_SIZE 128U + + +LIBHASHSUM_1_NONNULL_ +static size_t +process(struct libhashsum_hasher *this, const void *data, size_t bytes) +{ + if (this->state.blake2b.keybytes && bytes) { + libblake_blake2b_force_update(&this->state.blake2b.s, this->state.blake2b.buf, BLAKE2B_BLOCK_SIZE); + this->state.blake2b.keybytes = 0; + memset(this->state.blake2b.buf, 0, (size_t)this->state.blake2b.keybytes); + } + return libblake_blake2b_update(&this->state.blake2b.s, data, bytes); +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise_const(struct libhashsum_hasher *this, const void *data, size_t bytes, unsigned extra_bits) +{ + const unsigned char *m = data; + size_t r; + + if (extra_bits) { + errno = EINVAL; + return -1; + } + + r = process(this, data, bytes); + m = &m[r]; + bytes -= r; + + if (!this->hash_output) + this->hash_output = this->state.blake2b.buf; + + if (this->state.blake2b.keybytes) + bytes = BLAKE2B_BLOCK_SIZE; + else + memcpy(this->state.blake2b.buf, m, bytes); + libblake_blake2b_digest(&this->state.blake2b.s, this->state.blake2b.buf, + bytes, 0, this->hash_size, this->hash_output); + + memset(&this->state.blake2b.s, 0, sizeof(this->state.blake2b.s)); + this->state.blake2b.keybytes = 0; + return 0; +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise(struct libhashsum_hasher *this, void *data, size_t bytes, unsigned extra_bits, size_t size) +{ + unsigned char *m = data; + size_t r; + + if (extra_bits) { + errno = EINVAL; + return -1; + } + + r = process(this, data, bytes); + m = &m[r]; + bytes -= r; + size -= r; + + if (!this->hash_output) + this->hash_output = this->state.blake224.buf; + + if (this->state.blake2b.keybytes) { + bytes = BLAKE2B_BLOCK_SIZE; + m = this->state.blake2b.buf; + } else if (size < libblake_blake2b_digest_get_required_input_size(bytes)) { + memcpy(this->state.blake2b.buf, m, bytes); + m = this->state.blake2b.buf; + } + libblake_blake2b_digest(&this->state.blake2b.s, m, bytes, 0, this->hash_size, this->hash_output); + + memset(&this->state.blake2b.s, 0, sizeof(this->state.blake2b.s)); + this->state.blake2b.keybytes = 0; + return 0; +} + + +#if defined(__GNUC__) +__attribute__((__pure__)) +#endif +static int +allzeroes(const uint8_t *data, size_t n) +{ + if (data) + while (n--) + if (data[n]) + return 0; + return 1; +} + + +static char * +hex(char *buf, const uint8_t *data, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) { + *buf++ = "0123456789abcdef"[(data[i] >> 4) & 15]; + *buf++ = "0123456789abcdef"[(data[i] >> 0) & 15]; + } + return buf; +} + + +static const char * +mkalgostr(char *buf, const char *name, size_t hashbits, const uint8_t *salt, + const uint8_t *pepper, size_t salt_pepper_bytes, const uint8_t *key, size_t keybytes) +{ + char *p, *b; + int with_salt = (salt && !allzeroes(salt, salt_pepper_bytes)); + int with_pepper = (pepper && !allzeroes(pepper, salt_pepper_bytes)); + if (!hashbits && !with_salt && !with_pepper && !keybytes) + return name; + b = p = stpcpy(buf, name); + if (hashbits) + p = &p[sprintf(p, ",n=%zu", hashbits)]; + if (with_salt) + p = hex(stpcpy(p, ",salt="), salt, salt_pepper_bytes); + if (with_pepper) + p = hex(stpcpy(p, ",pepper="), pepper, salt_pepper_bytes); + if (keybytes) + p = hex(stpcpy(p, ",key="), key, keybytes); + *b = '['; + *p++ = ']'; + *p++ = '\0'; + return buf; +} + + +int +libhashsum_init_blake2b_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, + const void *pepper, const void *key, size_t keybits) +{ + struct libblake_blake2b_params params = { + .digest_len = (unsigned char)(hashbits / 8U), + .key_len = (unsigned char)(keybits / 8U), + .fanout = 1U, + .depth = 1U, + .leaf_len = 0U, + .node_offset = 0U, + .node_depth = 0U, + .inner_len = 0U + }; + if (((hashbits | keybits) & 7U) || ((hashbits | keybits) > 256U)) { + errno = EINVAL; + return -1; + } + if (!hashbits) + hashbits = 512U; + libblake_init(); + this->algorithm = LIBHASHSUM_BLAKE2B; + this->algorithm_string = mkalgostr(this->state.blake2b.algostr, "BLAKE2b", + hashbits == 512U ? 0U : hashbits, + salt, pepper, 16U, key, keybits / 8U); + this->input_block_size = BLAKE2B_BLOCK_SIZE; + this->hash_size = hashbits / 8U; + this->hash_output = NULL; + this->supports_non_whole_bytes = 0; + this->process = &process; + this->finalise_const = &finalise_const; + this->finalise = &finalise; + this->stretch = NULL; + this->destroy = NULL; + if (salt) + memcpy(params.salt, salt, sizeof(params.salt)); + if (pepper) + memcpy(params.pepper, pepper, sizeof(params.pepper)); + this->state.blake2b.keybytes = (unsigned char)(keybits / 8U); + if (this->state.blake2b.keybytes) { + memcpy(this->state.blake2b.buf, key, keybits / 8U); + memset(&this->state.blake2b.buf[keybits / 8U], 0, sizeof(this->state.blake2b.buf) - keybits / 8U); + } + libblake_blake2b_init(&this->state.blake2b.s, ¶ms); + return 0; +} + + +#else +int +libhashsum_init_blake2b_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, + const void *pepper, const void *key, size_t keybits) +{ + (void) this; + (void) hashbits; + (void) salt; + (void) pepper; + (void) key; + (void) keybits; + errno = ENOSYS; + return -1; +} +#endif diff --git a/libhashsum_init_blake2s_hasher.c b/libhashsum_init_blake2s_hasher.c new file mode 100644 index 0000000..0957b22 --- /dev/null +++ b/libhashsum_init_blake2s_hasher.c @@ -0,0 +1,201 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifdef SUPPORT_BLAKE2S + + +#define BLAKE2S_BLOCK_SIZE 64U + + +LIBHASHSUM_1_NONNULL_ +static size_t +process(struct libhashsum_hasher *this, const void *data, size_t bytes) +{ + if (this->state.blake2s.keybytes && bytes) { + libblake_blake2s_force_update(&this->state.blake2s.s, this->state.blake2s.buf, BLAKE2S_BLOCK_SIZE); + this->state.blake2s.keybytes = 0; + memset(this->state.blake2s.buf, 0, (size_t)this->state.blake2s.keybytes); + } + return libblake_blake2s_update(&this->state.blake2s.s, data, bytes); +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise_const(struct libhashsum_hasher *this, const void *data, size_t bytes, unsigned extra_bits) +{ + const unsigned char *m = data; + size_t r; + + if (extra_bits) { + errno = EINVAL; + return -1; + } + + r = process(this, data, bytes); + m = &m[r]; + bytes -= r; + + if (!this->hash_output) + this->hash_output = this->state.blake2s.buf; + + if (this->state.blake2s.keybytes) + bytes = BLAKE2S_BLOCK_SIZE; + else + memcpy(this->state.blake2s.buf, m, bytes); + libblake_blake2s_digest(&this->state.blake2s.s, this->state.blake2s.buf, + bytes, 0, this->hash_size, this->hash_output); + + memset(&this->state.blake2s.s, 0, sizeof(this->state.blake2s.s)); + this->state.blake2s.keybytes = 0; + return 0; +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise(struct libhashsum_hasher *this, void *data, size_t bytes, unsigned extra_bits, size_t size) +{ + unsigned char *m = data; + size_t r; + + if (extra_bits) { + errno = EINVAL; + return -1; + } + + r = process(this, data, bytes); + m = &m[r]; + bytes -= r; + size -= r; + + if (!this->hash_output) + this->hash_output = this->state.blake224.buf; + + if (this->state.blake2s.keybytes) { + bytes = BLAKE2S_BLOCK_SIZE; + m = this->state.blake2s.buf; + } else if (size < libblake_blake2s_digest_get_required_input_size(bytes)) { + memcpy(this->state.blake2s.buf, m, bytes); + m = this->state.blake2s.buf; + } + libblake_blake2s_digest(&this->state.blake2s.s, m, bytes, 0, this->hash_size, this->hash_output); + + memset(&this->state.blake2s.s, 0, sizeof(this->state.blake2s.s)); + this->state.blake2s.keybytes = 0; + return 0; +} + + +#if defined(__GNUC__) +__attribute__((__pure__)) +#endif +static int +allzeroes(const uint8_t *data, size_t n) +{ + while (n--) + if (data[n]) + return 0; + return 1; +} + + +static char * +hex(char *buf, const uint8_t *data, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) { + *buf++ = "0123456789abcdef"[(data[i] >> 4) & 15]; + *buf++ = "0123456789abcdef"[(data[i] >> 0) & 15]; + } + return buf; +} + + +static const char * +mkalgostr(char *buf, const char *name, size_t hashbits, const uint8_t *salt, + const uint8_t *pepper, size_t salt_pepper_bytes, const uint8_t *key, size_t keybytes) +{ + char *p, *b; + int with_salt = (salt && !allzeroes(salt, salt_pepper_bytes)); + int with_pepper = (pepper && !allzeroes(pepper, salt_pepper_bytes)); + if (!hashbits && !with_salt && !with_pepper && !keybytes) + return name; + b = p = stpcpy(buf, name); + if (hashbits) + p = &p[sprintf(p, ",n=%zu", hashbits)]; + if (with_salt) + p = hex(stpcpy(p, ",salt="), salt, salt_pepper_bytes); + if (with_pepper) + p = hex(stpcpy(p, ",pepper="), pepper, salt_pepper_bytes); + if (keybytes) + p = hex(stpcpy(p, ",key="), key, keybytes); + *b = '['; + *p++ = ']'; + *p++ = '\0'; + return buf; +} + + +int +libhashsum_init_blake2s_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, + const void *pepper, const void *key, size_t keybits) +{ + struct libblake_blake2s_params params = { + .digest_len = (unsigned char)(hashbits / 8U), + .key_len = (unsigned char)(keybits / 8U), + .fanout = 1U, + .depth = 1U, + .leaf_len = 0U, + .node_offset = 0U, + .node_depth = 0U, + .inner_len = 0U + }; + if (((hashbits | keybits) & 7U) || ((hashbits | keybits) > 256U)) { + errno = EINVAL; + return -1; + } + if (!hashbits) + hashbits = 256U; + libblake_init(); + this->algorithm = LIBHASHSUM_BLAKE2S; + this->algorithm_string = mkalgostr(this->state.blake2s.algostr, "BLAKE2s", + hashbits == 256U ? 0U : hashbits, + salt, pepper, 8U, key, keybits / 8U); + this->input_block_size = BLAKE2S_BLOCK_SIZE; + this->hash_size = hashbits / 8U; + this->hash_output = NULL; + this->supports_non_whole_bytes = 0; + this->process = &process; + this->finalise_const = &finalise_const; + this->finalise = &finalise; + this->stretch = NULL; + this->destroy = NULL; + if (salt) + memcpy(params.salt, salt, sizeof(params.salt)); + if (pepper) + memcpy(params.pepper, pepper, sizeof(params.pepper)); + this->state.blake2s.keybytes = (unsigned char)(keybits / 8U); + if (this->state.blake2s.keybytes) { + memcpy(this->state.blake2s.buf, key, keybits / 8U); + memset(&this->state.blake2s.buf[keybits / 8U], 0, sizeof(this->state.blake2s.buf) - keybits / 8U); + } + libblake_blake2s_init(&this->state.blake2s.s, ¶ms); + return 0; +} + + +#else +int +libhashsum_init_blake2s_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, + const void *pepper, const void *key, size_t keybits) +{ + (void) this; + (void) hashbits; + (void) salt; + (void) pepper; + (void) key; + (void) keybits; + errno = ENOSYS; + return -1; +} +#endif diff --git a/libhashsum_init_hasher.3 b/libhashsum_init_hasher.3 index 0f3f978..a61b00e 100644 --- a/libhashsum_init_hasher.3 +++ b/libhashsum_init_hasher.3 @@ -39,7 +39,7 @@ Link with (unless support for Keccak, SHA-3, SHAKE, and RawSHAKE was excluded) .br .I -lblake -(unless support for BLAKE was excluded). +(unless support for BLAKE and BLAKE2 was excluded). .SH DESCRIPTION The @@ -232,6 +232,16 @@ for more information. Selects BLAKE512 (BLAKE, BLAKEb). See .BR libhashsum_init_blake512_hasher (3) for more information. +.TP +.B LIBHASHSUM_BLAKE2S +Selects BLAKE2s (BLAKE2). See +.BR libhashsum_init_blake2s_hasher (3) +for more information. +.TP +.B LIBHASHSUM_BLAKE2B +Selects BLAKE2b (BLAKE). See +.BR libhashsum_init_blake2b_hasher (3) +for more information. .PP .I hasher->algorithm will be set to diff --git a/libhashsum_init_hasher.c b/libhashsum_init_hasher.c index 6f09629..02c1e92 100644 --- a/libhashsum_init_hasher.c +++ b/libhashsum_init_hasher.c @@ -72,6 +72,10 @@ libhashsum_init_hasher(struct libhashsum_hasher *this, enum libhashsum_algorithm return libhashsum_init_blake384_hasher(this, NULL); case LIBHASHSUM_BLAKE512: return libhashsum_init_blake512_hasher(this, NULL); + case LIBHASHSUM_BLAKE2S: + return libhashsum_init_blake2s_hasher(this, 0, NULL, NULL, NULL, 0); + case LIBHASHSUM_BLAKE2B: + return libhashsum_init_blake2b_hasher(this, 0, NULL, NULL, NULL, 0); default: case LIBHASHSUM_KECCAK: errno = EINVAL; diff --git a/libhashsum_init_hasher_from_string.3 b/libhashsum_init_hasher_from_string.3 index db88547..901d3f5 100644 --- a/libhashsum_init_hasher_from_string.3 +++ b/libhashsum_init_hasher_from_string.3 @@ -37,7 +37,7 @@ Link with (unless support for Keccak, SHA-3, SHAKE, and RawSHAKE was excluded) .br .I -lblake -(unless support for BLAKE was excluded). +(unless support for BLAKE and BLAKE2 was excluded). .SH DESCRIPTION The diff --git a/libhashsum_init_hasher_from_string.c b/libhashsum_init_hasher_from_string.c index a1ee827..ffd23eb 100644 --- a/libhashsum_init_hasher_from_string.c +++ b/libhashsum_init_hasher_from_string.c @@ -3,28 +3,42 @@ static int +parse_value(size_t *valp, const char *p, const char **end_out) +{ + size_t digit; + if (*valp) + return -1; + if (*p++ != '=' || !('1' <= *p && *p <= '9')) + return -1; + while (isdigit(*p)) { + digit = (size_t)(*p++ & 15); + if (*valp > (SIZE_MAX - digit) / 10U) + return -1; + *valp = *valp * 10U + digit; + } + *end_out = p; + return 0; +} + + +static int with_n(int (*initfunc)(struct libhashsum_hasher *, size_t), struct libhashsum_hasher *this, const char *algorithm) { const char *p; - size_t n = 0, digit; + size_t n = 0; p = strchr(algorithm, '['); - if (!p || *++p == ']') + if (!p || *++p == ']') { + if (p && *++p) + goto einval; return initfunc(this, 0); + } if (*p != 'n' && *p != 'N') goto einval; - p++; - if (*p++ != '=' || !('1' <= *p && *p <= '9')) + if (parse_value(&n, &p[1], &p)) goto einval; - while (isdigit(*p)) { - digit = (size_t)(*p++ & 15); - if (n > (SIZE_MAX - digit) / 10U) - goto einval; - n = n * 10U + digit; - } - if (*p++ != ']' || *p) goto einval; @@ -37,25 +51,6 @@ einval: static int -parse_value(size_t *valp, const char *p, const char **end_out) -{ - size_t digit; - if (*valp) - return -1; - if (*p++ != '=' || !('1' <= *p && *p <= '9')) - return -1; - while (isdigit(*p)) { - digit = (size_t)(*p++ & 15); - if (*valp > (SIZE_MAX - digit) / 10U) - return -1; - *valp = *valp * 10U + digit; - } - *end_out = p; - return 0; -} - - -static int with_rcnz(int (*initfunc)(struct libhashsum_hasher *, size_t, size_t, size_t, size_t), struct libhashsum_hasher *this, const char *algorithm) { @@ -64,7 +59,7 @@ with_rcnz(int (*initfunc)(struct libhashsum_hasher *, size_t, size_t, size_t, si p = strchr(algorithm, '['); if (!p || *++p == ']') { - if (p && *p) + if (p && *++p) goto einval; return initfunc(this, 0, 0, 0, 0); } @@ -112,8 +107,11 @@ with_salt(int (*initfunc)(struct libhashsum_hasher *, const void *), size_t salti = 0; p = strchr(algorithm, '['); - if (!p || *++p == ']') + if (!p || *++p == ']') { + if (p && *++p) + goto einval; return initfunc(this, NULL); + } if (*p != 's' && *p != 'S') goto einval; @@ -156,10 +154,116 @@ with_salt(int (*initfunc)(struct libhashsum_hasher *, const void *), if (*p++ != ']' || *p) goto einval; - return initfunc(this, salt); + return initfunc(this, salti ? salt : NULL); + +einval: + errno = EINVAL; + return -1; +} + + +static int +blake2(int (*initfunc)(struct libhashsum_hasher *, size_t, const void *, const void *, const void *, size_t), + struct libhashsum_hasher *this, const char *algorithm, size_t saltbytes, size_t pepperbytes) +{ + const char *p; + uint8_t a, b, salt[16], pepper[16], *key = NULL; + size_t n = 0, salti = 0, pepperi = 0, keyi = 0, i; + int r; + + p = strchr(algorithm, '['); + if (!p || *++p == ']') { + if (p && *++p) + goto einval; + return initfunc(this, 0, NULL, NULL, NULL, 0); + } + +next: + if (!salti && !strncasecmp(p, "salt=", 5U)) { + p = &p[5]; + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + p = &p[2]; + for (;;) { + if (isxdigit(p[0]) && isxdigit(p[1])) { + if (!saltbytes) + goto einval; + saltbytes--; + } else if (isxdigit(p[0])) { + goto einval; + } else if (saltbytes) { + goto einval; + } else { + break; + } + a = (uint8_t)(((p[0] & 15) + (p[0] > '9' ? 9 : 0)) << 4); + b = (uint8_t)(((p[1] & 15) + (p[1] > '9' ? 9 : 0)) << 0); + salt[salti++] = (uint8_t)(a | b); + p = &p[2]; + } + } else if (!pepperi && !strncasecmp(p, "pepper=", 7U)) { + p = &p[7]; + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + p = &p[2]; + for (;;) { + if (isxdigit(p[0]) && isxdigit(p[1])) { + if (!pepperbytes) + goto einval; + pepperbytes--; + } else if (isxdigit(p[0])) { + goto einval; + } else if (pepperbytes) { + goto einval; + } else { + break; + } + a = (uint8_t)(((p[0] & 15) + (p[0] > '9' ? 9 : 0)) << 4); + b = (uint8_t)(((p[1] & 15) + (p[1] > '9' ? 9 : 0)) << 0); + pepper[pepperi++] = (uint8_t)(a | b); + p = &p[2]; + } + } else if (!keyi && !strncasecmp(p, "key=", 4U)) { + p = &p[4]; + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + p = &p[2]; + while (isxdigit(p[keyi | 0]) && isxdigit(p[keyi | 1])) + keyi += 2U; + if (isxdigit(p[keyi])) + goto einval; + keyi /= 2U; + if (keyi) { + key = malloc(keyi); + if (!key) + goto fail; + } + for (i = 0; i < keyi; i++) { + a = (uint8_t)(((p[0] & 15) + (p[0] > '9' ? 9 : 0)) << 4); + b = (uint8_t)(((p[1] & 15) + (p[1] > '9' ? 9 : 0)) << 0); + key[i] = (uint8_t)(a | b); + p = &p[2]; + } + } else if (*p == 'n' || *p == 'N') { + if (parse_value(&n, &p[1], &p)) + goto einval; + } else { + goto einval; + } + + if (*p == ',') { + p++; + goto next; + } + + if (*p++ != ']' || *p) + goto einval; + + r = initfunc(this, n, salti ? salt : NULL, pepperi ? pepper : NULL, key, keyi); + free(key); + return r; einval: errno = EINVAL; +fail: + free(key); return -1; } @@ -207,6 +311,8 @@ libhashsum_init_hasher_from_string(struct libhashsum_hasher *this, const char *a case LIBHASHSUM_BLAKE256: return with_salt(&libhashsum_init_blake256_hasher, this, algorithm, 16U); case LIBHASHSUM_BLAKE384: return with_salt(&libhashsum_init_blake384_hasher, this, algorithm, 32U); case LIBHASHSUM_BLAKE512: return with_salt(&libhashsum_init_blake512_hasher, this, algorithm, 32U); + case LIBHASHSUM_BLAKE2S: return blake2(&libhashsum_init_blake2s_hasher, this, algorithm, 8U, 8U); + case LIBHASHSUM_BLAKE2B: return blake2(&libhashsum_init_blake2b_hasher, this, algorithm, 16U, 16U); default: abort(); } |