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