aboutsummaryrefslogblamecommitdiffstats
path: root/libhashsum_init_hasher_from_string.c
blob: 652b2061d15e9fd1f8787465d118a800698c8ec3 (plain) (tree)
1
2
3
4
5



                                                         
          


















                                                              


                                                                                                                  
                     

                                   


                                    
                                         
         
 
                                   
                            
                                       

                            











                                 
                                                                                                  

                                                               
                                                     
                      

                                   
                                
                              
                                    
                                               
         


                                             
                                                                     

                                                    
                                                                    
                                            







                                                                              

                                                    
                                                                     









                                            

                                 



                            
                                       



                       


 








                                                                                  


                                    
                                            
         
 
                                   
                            

                                   
                            

                                   
                            

                                   
                            

                      
                            
            
















                                                        

                                                                         
                                                 
                          




                              































































































                                                                                                             

                                 





                              



                                                                                            

                  


                       

                  



                  


                                                                                         
                                       
                                                                      
































                                                                                                          
                                                                                                      



                                                                                                               

                                                                                                                


                        
 
/* See LICENSE file for copyright and license details. */
#include "common.h"


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;

	p = strchr(algorithm, '[');
	if (!p || *++p == ']') {
		if (p && *++p)
			goto einval;
		return initfunc(this, 0);
	}

	if (*p != 'n' && *p != 'N')
		goto einval;
	if (parse_value(&n, &p[1], &p))
		goto einval;

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

	return initfunc(this, n);

einval:
	errno = EINVAL;
	return -1;
}


static int
keccak(int (*initfunc)(struct libhashsum_hasher *, const struct libhashsum_keccak_params *params),
         struct libhashsum_hasher *this, const char *algorithm)
{
	struct libhashsum_keccak_params params = {0};
	const char *p;

	p = strchr(algorithm, '[');
	if (!p || *++p == ']') {
		if (p && *++p)
			goto einval;
		return initfunc(this, &params);
	}

	for (;;) {
		if (*p == 'r' || *p == 'R') {
			if (parse_value(&params.ratebits, &p[1], &p))
				goto einval;
		} else if (*p == 'c' || *p == 'C') {
			if (parse_value(&params.capbits, &p[1], &p))
				goto einval;
		} else if (*p == 'n' || *p == 'N' || *p == 'o' || *p == 'O') {
			if (parse_value(&params.hashbits, &p[1], &p))
				goto einval;
		} else if (*p == 's' || *p == 'S' || *p == 'b' || *p == 'B') {
			if (parse_value(&params.statebits, &p[1], &p))
				goto einval;
		} else if (*p == 'w' || *p == 'W') {
			if (parse_value(&params.wordbits, &p[1], &p))
				goto einval;
		} else if (*p == 'z' || *p == 'Z') {
			if (parse_value(&params.squeezes, &p[1], &p))
				goto einval;
		} else if (*p == ']') {
			break;
		} else {
			goto einval;
		}
		if (*p == ']')
			break;
		if (*p++ != ',')
			goto einval;
		while (*p == ' ')
			p++;
	}
	if (p[1])
		goto einval;

	return initfunc(this, &params);

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 == ']') {
		if (p && *++p)
			goto einval;
		return initfunc(this, NULL);
	}

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

	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];
	}

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

	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++;
		while (*p == ' ')
			p++;
		goto next;
	}

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

	if (keyi > SIZE_MAX / 8U)
		goto einval;

	r = initfunc(this, n, salti ? salt : NULL, pepperi ? pepper : NULL, key, keyi * 8U);
	free(key);
	return r;

einval:
	errno = EINVAL;
fail:
	free(key);
	return -1;
}


int
libhashsum_init_hasher_from_string(struct libhashsum_hasher *this, const char *algorithm)
{
	enum libhashsum_algorithm algo;
	if (!libhashsum_get_algorithm_from_string(&algo, algorithm)) {
		errno = EINVAL;
		return -1;
	}
	switch (algo) {
	case LIBHASHSUM_MD2:          return libhashsum_init_md2_hasher(this);
	case LIBHASHSUM_MD4:          return libhashsum_init_md4_hasher(this);
	case LIBHASHSUM_MD5:          return libhashsum_init_md5_hasher(this);
	case LIBHASHSUM_RIPEMD_128:   return libhashsum_init_ripemd_128_hasher(this);
	case LIBHASHSUM_RIPEMD_160:   return libhashsum_init_ripemd_160_hasher(this);
	case LIBHASHSUM_RIPEMD_256:   return libhashsum_init_ripemd_256_hasher(this);
	case LIBHASHSUM_RIPEMD_320:   return libhashsum_init_ripemd_320_hasher(this);
	case LIBHASHSUM_SHA0:         return libhashsum_init_sha0_hasher(this);
	case LIBHASHSUM_SHA1:         return libhashsum_init_sha1_hasher(this);
	case LIBHASHSUM_SHA_224:      return libhashsum_init_sha_224_hasher(this);
	case LIBHASHSUM_SHA_256:      return libhashsum_init_sha_256_hasher(this);
	case LIBHASHSUM_SHA_384:      return libhashsum_init_sha_384_hasher(this);
	case LIBHASHSUM_SHA_512:      return libhashsum_init_sha_512_hasher(this);
	case LIBHASHSUM_SHA_512_224:  return libhashsum_init_sha_512_224_hasher(this);
	case LIBHASHSUM_SHA_512_256:  return libhashsum_init_sha_512_256_hasher(this);
	case LIBHASHSUM_KECCAK_224:   return libhashsum_init_keccak_224_hasher(this);
	case LIBHASHSUM_KECCAK_256:   return libhashsum_init_keccak_256_hasher(this);
	case LIBHASHSUM_KECCAK_384:   return libhashsum_init_keccak_384_hasher(this);
	case LIBHASHSUM_KECCAK_512:   return libhashsum_init_keccak_512_hasher(this);
	case LIBHASHSUM_SHA3_224:     return libhashsum_init_sha3_224_hasher(this);
	case LIBHASHSUM_SHA3_256:     return libhashsum_init_sha3_256_hasher(this);
	case LIBHASHSUM_SHA3_384:     return libhashsum_init_sha3_384_hasher(this);
	case LIBHASHSUM_SHA3_512:     return libhashsum_init_sha3_512_hasher(this);
	case LIBHASHSUM_SHAKE128:     return with_n(&libhashsum_init_shake128_hasher, this, algorithm);
	case LIBHASHSUM_SHAKE256:     return with_n(&libhashsum_init_shake256_hasher, this, algorithm);
	case LIBHASHSUM_SHAKE512:     return with_n(&libhashsum_init_shake512_hasher, this, algorithm);
	case LIBHASHSUM_RAWSHAKE128:  return with_n(&libhashsum_init_rawshake128_hasher, this, algorithm);
	case LIBHASHSUM_RAWSHAKE256:  return with_n(&libhashsum_init_rawshake256_hasher, this, algorithm);
	case LIBHASHSUM_RAWSHAKE512:  return with_n(&libhashsum_init_rawshake512_hasher, this, algorithm);
	case LIBHASHSUM_KECCAK:       return keccak(&libhashsum_init_keccak_hasher2, this, algorithm);
	case LIBHASHSUM_BLAKE224:     return with_salt(&libhashsum_init_blake224_hasher, this, algorithm, 16U);
	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();
	}
}