aboutsummaryrefslogblamecommitdiffstats
path: root/libhashsum_init_hasher_from_string.c
blob: 1bdc70d71cc1476bb5213dbb483fe4a4a56545f9 (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                         
                                       








                                                 













                                                                                                                  
                                       
















































































                                                                             


 






















































                                                                                  
































                                                                                         





























                                                                                    







                                                                                         



                       
/* 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;
}


static int
with_salt(int (*initfunc)(struct libhashsum_hasher *, const void *),
          struct libhashsum_hasher *this, const char *algorithm, size_t saltbytes)
{
	const char *p;
	uint8_t a, b, salt[32];
	size_t salti = 0;

	p = strchr(algorithm, '[');
	if (!p || *++p == ']')
		return initfunc(this, NULL);

	if (*p++ != 's' && *p++ != 'S')
		goto einval;
	if (*p++ != 'a' && *p++ != 'A')
		goto einval;
	if (*p++ != 'l' && *p++ != 'L')
		goto einval;
	if (*p++ != 't' && *p++ != 'T')
		goto einval;
	if (*p++ != '=')
		goto einval;

	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 & 15) + (*p > '9' ? 9 : 0)) << 4);
		b = (uint8_t)(((*p & 15) + (*p > '9' ? 9 : 0)) << 0);
		salt[salti++] = (uint8_t)(a | b);
	}

	if (*p++ != ']' || *p)
		goto einval;

	return initfunc(this, salt);

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 with_salt(&libhashsum_init_blake224_hasher, this, algorithm, 16U);
	if (equiv(algorithm, "BLAKE-256["))
		return with_salt(&libhashsum_init_blake256_hasher, this, algorithm, 16U);
	if (equiv(algorithm, "BLAKE-384["))
		return with_salt(&libhashsum_init_blake384_hasher, this, algorithm, 32U);
	if (equiv(algorithm, "BLAKE-512["))
		return with_salt(&libhashsum_init_blake512_hasher, this, algorithm, 32U);

	errno = EINVAL;
	return -1;
}