/* See LICENSE file for copyright and license details. */
#include "common.h"
#if defined(__GNUC__)
__attribute__((__pure__))
#endif
static int
equiv(const char *a, const char *b)
{
while (*a && *b && *b != '[') {
if (tolower(*a) == tolower(*b)) {
a++;
b++;
} else if (*b == '-') {
b++;
} else {
return 0;
}
}
return !*a && (!*b || *b == '[');
}
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;
p = strchr(algorithm, '[');
if (!p || *++p == ']')
return initfunc(this, 0);
if ((*p++ != 'n' && *p++ != 'N'))
goto einval;
if (*p++ != '=' || !('1' <= *p && *p <= '9'))
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;
return initfunc(this, n);
einval:
errno = EINVAL;
return -1;
}
static int
parse_value(size_t *valp, const char *p, const char **end_out)
{
size_t digit;
if (*valp)
return -1;
p++;
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_rcn(int (*initfunc)(struct libhashsum_hasher *, size_t, size_t, size_t),
struct libhashsum_hasher *this, const char *algorithm)
{
const char *p;
size_t r = 0, c = 0, n = 0;
p = strchr(algorithm, '[');
if (!p || *++p == ']')
return initfunc(this, 0, 0, 0);
for (;;) {
if (*p == 'r' || *p == 'R') {
if (parse_value(&r, p, &p))
goto einval;
} else if (*p == 'c' || *p == 'C') {
if (parse_value(&c, p, &p))
goto einval;
} else if (*p == 'n' || *p == 'N') {
if (parse_value(&n, p, &p))
goto einval;
} else if (*p == ']') {
break;
} else {
goto einval;
}
if (*p == ']')
break;
if (*p++ != ',')
goto einval;
}
if (p[1])
goto einval;
return initfunc(this, r, c, n);
einval:
errno = EINVAL;
return -1;
}
int
libhashsum_init_hasher_from_string(struct libhashsum_hasher *this, const char *algorithm)
{
if (!strcasecmp(algorithm, "MD2"))
return libhashsum_init_md2_hasher(this);
if (!strcasecmp(algorithm, "MD4"))
return libhashsum_init_md4_hasher(this);
if (!strcasecmp(algorithm, "MD5"))
return libhashsum_init_md5_hasher(this);
if (equiv(algorithm, "RIPEMD-128"))
return libhashsum_init_ripemd_128_hasher(this);
if (equiv(algorithm, "RIPEMD-160"))
return libhashsum_init_ripemd_160_hasher(this);
if (equiv(algorithm, "RIPEMD-256"))
return libhashsum_init_ripemd_256_hasher(this);
if (equiv(algorithm, "RIPEMD-320"))
return libhashsum_init_ripemd_320_hasher(this);
if (equiv(algorithm, "SHA-0"))
return libhashsum_init_sha0_hasher(this);
if (equiv(algorithm, "SHA-1"))
return libhashsum_init_sha1_hasher(this);
if (equiv(algorithm, "SHA-224") || !strcasecmp(algorithm, "SHA2-224"))
return libhashsum_init_sha_224_hasher(this);
if (equiv(algorithm, "SHA-256") || !strcasecmp(algorithm, "SHA2-256"))
return libhashsum_init_sha_256_hasher(this);
if (equiv(algorithm, "SHA-384") || !strcasecmp(algorithm, "SHA2-384"))
return libhashsum_init_sha_384_hasher(this);
if (equiv(algorithm, "SHA-512") || !strcasecmp(algorithm, "SHA2-512"))
return libhashsum_init_sha_512_hasher(this);
if (equiv(algorithm, "SHA-512/224") || !strcasecmp(algorithm, "SHA2-512/224"))
return libhashsum_init_sha_512_224_hasher(this);
if (equiv(algorithm, "SHA-512/256") || !strcasecmp(algorithm, "SHA2-512/256"))
return libhashsum_init_sha_512_256_hasher(this);
if (equiv(algorithm, "Keccak-224"))
return libhashsum_init_keccak_224_hasher(this);
if (equiv(algorithm, "Keccak-256"))
return libhashsum_init_keccak_256_hasher(this);
if (equiv(algorithm, "Keccak-384"))
return libhashsum_init_keccak_384_hasher(this);
if (equiv(algorithm, "Keccak-512"))
return libhashsum_init_keccak_512_hasher(this);
if (!strcasecmp(algorithm, "SHA3-224"))
return libhashsum_init_sha3_224_hasher(this);
if (!strcasecmp(algorithm, "SHA3-256"))
return libhashsum_init_sha3_256_hasher(this);
if (!strcasecmp(algorithm, "SHA3-384"))
return libhashsum_init_sha3_384_hasher(this);
if (!strcasecmp(algorithm, "SHA3-512"))
return libhashsum_init_sha3_512_hasher(this);
if (equiv(algorithm, "SHAKE-128["))
return with_n(&libhashsum_init_shake128_hasher, this, algorithm);
if (equiv(algorithm, "SHAKE-256["))
return with_n(&libhashsum_init_shake256_hasher, this, algorithm);
if (equiv(algorithm, "SHAKE-512["))
return with_n(&libhashsum_init_shake512_hasher, this, algorithm);
if (equiv(algorithm, "RawSHAKE-128["))
return with_n(&libhashsum_init_rawshake128_hasher, this, algorithm);
if (equiv(algorithm, "RawSHAKE-256["))
return with_n(&libhashsum_init_rawshake256_hasher, this, algorithm);
if (equiv(algorithm, "RawSHAKE-512["))
return with_n(&libhashsum_init_rawshake512_hasher, this, algorithm);
if (equiv(algorithm, "Keccak["))
return with_rcn(&libhashsum_init_keccak_hasher, this, algorithm);
if (equiv(algorithm, "BLAKE-224"))
return libhashsum_init_blake224_hasher(this);
if (equiv(algorithm, "BLAKE-256"))
return libhashsum_init_blake256_hasher(this);
if (equiv(algorithm, "BLAKE-384"))
return libhashsum_init_blake384_hasher(this);
if (equiv(algorithm, "BLAKE-512"))
return libhashsum_init_blake512_hasher(this);
errno = EINVAL;
return -1;
}