diff options
| author | Mattias Andrée <maandree@kth.se> | 2022-02-15 16:21:36 +0100 | 
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2022-02-15 16:21:36 +0100 | 
| commit | f74764136b8b0564aa0e75e5c667b9d11158a2a9 (patch) | |
| tree | 4b21592981aa6e06ecd4b336e2ad940cc8957613 | |
| parent | Add libar2simplified_init_context (diff) | |
| download | libar2simplified-f74764136b8b0564aa0e75e5c667b9d11158a2a9.tar.gz libar2simplified-f74764136b8b0564aa0e75e5c667b9d11158a2a9.tar.bz2 libar2simplified-f74764136b8b0564aa0e75e5c667b9d11158a2a9.tar.xz | |
Add libar2simplified_decode_r
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | libar2simplified.7 | 1 | ||||
| -rw-r--r-- | libar2simplified.h | 46 | ||||
| -rw-r--r-- | libar2simplified_decode.3 | 1 | ||||
| -rw-r--r-- | libar2simplified_decode.c | 188 | ||||
| -rw-r--r-- | libar2simplified_decode_r.3 | 148 | ||||
| -rw-r--r-- | libar2simplified_decode_r.c | 196 | ||||
| -rw-r--r-- | test.c | 6 | 
8 files changed, 409 insertions, 178 deletions
| @@ -19,6 +19,7 @@ LIB_NAME = ar2simplified  OBJ =\  	libar2simplified_crypt.o\  	libar2simplified_decode.o\ +        libar2simplified_decode_r.o\  	libar2simplified_encode.o\  	libar2simplified_encode_hash.o\  	libar2simplified_hash.o\ diff --git a/libar2simplified.7 b/libar2simplified.7 index fa9219d..809ba1e 100644 --- a/libar2simplified.7 +++ b/libar2simplified.7 @@ -43,6 +43,7 @@ the parameters.  .BR libar2simplified (7),  .BR libar2simplified_crypt (3),  .BR libar2simplified_decode (3), +.BR libar2simplified_decode_r (3),  .BR libar2simplified_encode (3),  .BR libar2simplified_encode_hash (3),  .BR libar2simplified_hash (3), diff --git a/libar2simplified.h b/libar2simplified.h index 0d005fb..e58e68c 100644 --- a/libar2simplified.h +++ b/libar2simplified.h @@ -105,6 +105,52 @@ struct libar2_argon2_parameters *  libar2simplified_decode(const char *str, char **tagp, char **endp, int (*random_byte_generator)(char *out, size_t n));  /** + * Decode hashing parameters + *  + * If the salt's lengths is encoded, but not an + * actual salt, a random salt will be created + *  + * The hashing string does not encode information + * about `params->key` or `params->ad`, therefore + * `params->key` and `params->ad` will be set to + * `NULL` and `params->keylen` and `params->adlen` + * will be set to 0; where `params` is the returned + * pointer + *  + * @param   str                    The hashing parameter string to decode + * @param   tagp                   Output parameter for the tag (hash result), or `NULL`. + *                                 Unless `NULL`, `NULL` will be stored in `*tagp` if `str` + *                                 includes a tag length instead of an actual tag, otherwise + *                                 unless `NULL`, the beginning of the tag, in `str`, will + *                                 be stored in `*tagp`. `*endp` will (unless `endp` or + *                                 `*tagp` is `NULL`) mark the end of the tag. + * @param   endp                   Output parameter for the end of the hashing parameter + *                                 string, or `NULL`. Unless `NULL`, one position beyond the + *                                 last byte in `str` determined to be part of the hashing + *                                 parameter string will be stored in `*endp`. The application + *                                 shall make sure that `**endp` is a valid termination of + *                                 the hashing parameter string; typically this would be a ':' + *                                 or a NUL byte. + * @param   random_byte_generator  Random number generator function, used to generate salt if + *                                 `str` does not contain one. The function shall output `n` + *                                 random bytes (only the lower 6 bits in each byte need to + *                                 be random) to `out` and return 0. On failure, the function + *                                 shall return -1. If `NULL`, the function will use a random + *                                 number generator provided by the C standard library or the + *                                 operating system. + * @param   user_data              Will be parsed as is as the third argument of + *                                 `random_byte_generator` and is otherwise unused. + * @return                         Decoded hashing parameters. Shall be deallocated using + *                                 free(3) when no longer needed. Be aware than the allocation + *                                 size of the returned object will exceed the size of the + *                                 return type. + */ +LIBAR2_PUBLIC__ LIBAR2_NONNULL__(1) +struct libar2_argon2_parameters * +libar2simplified_decode_r(const char *str, char **tagp, char **endp, +                          int (*random_byte_generator)(char *out, size_t n, void *user_data), void *user_data); + +/**   * Calculate a password hash   *    * @param   hash    Output parameter for the tag (hash result). diff --git a/libar2simplified_decode.3 b/libar2simplified_decode.3 index 8de6ddf..4a54ddc 100644 --- a/libar2simplified_decode.3 +++ b/libar2simplified_decode.3 @@ -133,6 +133,7 @@ deallocated.  .SH SEE ALSO  .BR libar2simplified (7), +.BR libar2simplified_decode_r (3),  .BR libar2simplified_encode (3),  .BR libar2simplified_encode_hash (3),  .BR libar2simplified_recommendation (3), diff --git a/libar2simplified_decode.c b/libar2simplified_decode.c index 2c2f38e..eb3d3ee 100644 --- a/libar2simplified_decode.c +++ b/libar2simplified_decode.c @@ -1,194 +1,28 @@  /* See LICENSE file for copyright and license details. */  #include "common.h" -#ifdef __linux__ -#include <sys/random.h> -#endif -#include <time.h> -static size_t -decode_u32(const char *s, uint_least32_t *outp) -{ -	uint_least32_t digit; -	size_t i; - -	if ((s[0] == '0' && s[1] == '0') || !isdigit(s[0])) { -		errno = EINVAL; -		return 0; -	} - -	*outp = 0; -	for (i = 0; isdigit(s[i]); i++) { -		digit = (uint_least32_t)(s[i] & 15); -		if (*outp > ((uint_least32_t)0xFFFFffffUL - digit) / 10) { -			errno = ERANGE; -			return 0; -		} -		*outp = *outp * 10 + digit; -	} - -	return i; -} +union function { +	int (*func)(char *out, size_t n); +};  static int -random_salt(char *out, size_t n, int (*random_byte_generator)(char *out, size_t n)) -{ -#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" -	static int srand_called = 0; - -	double x; -	size_t i; -	int xi; -#ifdef __linux__ -	ssize_t r; -#endif - -	if (random_byte_generator) { -		if (random_byte_generator(out, n)) -			return -1; -	} else { -		i = 0; -#ifdef __linux__ -		for(; i < n; i += (size_t)r) { -			r = getrandom(&out[i], n - i, GRND_NONBLOCK); -			if(r < 0) -				break; -		} -#endif -		if (!srand_called) { -			srand((unsigned int)time(NULL) ^ (unsigned int)rand()); -			srand_called = 1; -		} -		for(; i < n; i++) { -			xi = rand(); -			x = (double)xi; -			x /= (double)RAND_MAX; -			x *= 63; -			out[i] = (char)x; -		} -	} - -	for (i = 0; i < n; i++) -		out[i] = ALPHABET[out[i] % 64]; -	return 0; -} - - -static void * -allocate(size_t num, size_t size, size_t alignment, struct libar2_context *ctx) -{ -	(void) ctx; -	(void) alignment; -	return malloc(num * size); -} - - -static void -deallocate(void *ptr, struct libar2_context *ctx) +function_wrapper(char *out, size_t n, void *function)  { -	(void) ctx; -	free(ptr); +	union function *func = function; +	return func->func(out, n);  }  struct libar2_argon2_parameters *  libar2simplified_decode(const char *str, char **tagp, char **endp, int (*random_byte_generator)(char *out, size_t n))  { -	struct libar2_argon2_parameters params, *ret; -	const char *p = str; -	const char *end; -	char *str_free = NULL; -	char *buf = NULL; -	size_t n, saltsize, offset; -	uint_least32_t saltlen, hashlen; -	struct libar2_context ctx; - -	if (*p != '$') -		goto einval; -	p = strchr(&p[1], '$'); -	if (!p) -		goto einval; -	if (p[1] == 'v' && p[2] == '=') { -		p = strchr(&p[1], '$'); -		if (!p) -			goto einval; -	} -	p = strchr(&p[1], '$'); -	if (!p) -		goto einval; -	p++; -	end = strchr(p, '$'); -	if (!end) -		goto einval; - -	if (*p == '*') { -		n = decode_u32(&p[1], &saltlen); -		if (!n++) -			goto fail; -		if (&p[n] != end) -			goto einval; -		params.saltlen = (size_t)saltlen; -		saltsize = libar2_encode_base64(NULL, NULL, saltlen) - 1; -		offset = (size_t)(p - str); -		str_free = malloc(offset + saltsize + strlen(&p[n]) + 1); -		if (!str_free) -			goto enomem; -		memcpy(str_free, str, offset); -		if (random_salt(&str_free[offset], saltsize, random_byte_generator)) -			goto fail; -		offset += saltsize; -		stpcpy(&str_free[offset], &p[n]); -		str = str_free; -	} -	end++; - -	ctx.allocate = allocate; -	ctx.deallocate = deallocate; - -	if (!libar2_decode_params(str, ¶ms, &buf, &ctx)) -		goto fail; - -	if (*end == '*') { -		n = decode_u32(&end[1], &hashlen); -		if (!n++) -			goto fail; -		end = &end[n]; -		params.hashlen = (size_t)hashlen; -		if (tagp) -			*tagp = NULL; +	union function func; +	if (random_byte_generator) { +		func.func = random_byte_generator; +		return libar2simplified_decode_r(str, tagp, endp, function_wrapper, &func);  	} else { -		if (tagp) -			*tagp = *(void **)(void *)&end; -		end = &end[libar2_encode_base64(NULL, NULL, params.hashlen) - 1]; +		return libar2simplified_decode_r(str, tagp, endp, NULL, NULL);  	} - -	ret = malloc(sizeof(params) + params.saltlen); -	if (!ret) -		goto enomem; -	memcpy(ret, ¶ms, sizeof(params)); -	if (buf) { -		memcpy(&((char *)ret)[sizeof(params)], buf, params.saltlen); -		ret->salt = &((unsigned char *)ret)[sizeof(params)]; -		deallocate(buf, &ctx); -	} - -	if (endp) -		*endp = *(void **)(void *)&end; - -	free(str_free); -	return ret; - -einval: -	errno = EINVAL; -	return NULL; - -fail: -	free(str_free); -	return NULL; - -enomem: -	free(str_free); -	errno = ENOMEM; -	return NULL;  } diff --git a/libar2simplified_decode_r.3 b/libar2simplified_decode_r.3 new file mode 100644 index 0000000..0cc229b --- /dev/null +++ b/libar2simplified_decode_r.3 @@ -0,0 +1,148 @@ +.TH LIBAR2SIMPLIFIED_DECODE_R 3 LIBAR2SIMPLIFIED +.SH NAME +libar2simplified_decode_r - Decode hashing parameters + +.SH SYNOPSIS +.nf +#include <libar2simplified.h> + +struct libar2_argon2_parameters * +libar2simplified_decode_r(const char *\fIstr\fP, char **\fItagp\fP, char **\fIendp\fP, +                          int (*\fIrandom_byte_generator\fP)(char *\fIout\fP, size_t \fIn\fP, void *\fIuser_data\fP), +                          void *\fIuser_data\fP); +.fi +.PP +Link with +.IR "-lar2simplified -lar2" . + +.SH DESCRIPTION +The +.BR libar2simplified_decode_r () +function a decode hashing parameter string provided +in the +.I str +parameter. +.PP +This function supports the extended format described in +.BR libar2simplified_encode (3). +If the parameter string only specifies a salt length, and +not an actual salt, one is generate using the function +provided via the +.I random_byte_generator +parameter; or if +.I random_byte_generator +is +.IR NULL , +a function built into the library itself. If the parameter +string specifies a tag (hash result), a pointer to it +is stored in +.IR *tagp , +otherwise +.I *tagp +is set to +.IR NULL . +.RI ( *tagp +is only set unless +.I tagp +is +.IR NULL ) +.PP +Unless +.I endp +is +.IR NULL , +.I *endp +will be set to the end of the parameter string, which +terminates the tag. The application shall make sure +that +.I *endp +is a proper termination of the parameter string, +typically this would be a colon +.RB ( : ), +if read from +.I /etc/shadow +or a similar file, or a NUL byte. The +.BR libar2simplified_decode_r () +function will +.B not +make this check even if +.I endp +is +.IR NULL . +.PP +Unless +.I random_byte_generator +is +.IR NULL , +it shall generate +.I n +random bytes and store them in +.I out +and return 0, or on failure -1. +.I user_data +will be passed as is as the third argument to +.IR *random_byte_generator . +Each byte need only have its 6 lower bits set +randomly. +.PP +The hashing string does not encode information +about the secret (pepper) or associated data, +which will therefore be set to zero-length. +.PP +.I params +may not be +.IR NULL . + +.SH RETURN VALUES +The +.BR libar2simplified_decode_r () +function returns a dynamically allocated +structure detailing the contents of +.IR str , +which can be deallocated using the +.BR free (3) +function, upon successful completion. +On error, +.I NULL +is returned and +.I errno +is set to describe the error. + +.SH ERRORS +The +.BR libar2simplified_decode_r () +function will fail if: +.TP +.B EINVAL +The contents of +.I str +is invalid or unsupported. +.TP +.B ENOMEM +Insufficient storage space is available. +.PP +The +.BR libar2simplified_decode_r () +function will fail if the +.I random_byte_generator +fails, in which case it will not modify +the value of +.IR errno . + +.SH NOTES +The returned objects allocation size will +exceed the size of its type, so that the +salt can be stored in it, and automatically +deallocated when the returned pointer is +deallocated. + +.SH SEE ALSO +.BR libar2simplified (7), +.BR libar2simplified_decode (3), +.BR libar2simplified_encode (3), +.BR libar2simplified_encode_hash (3), +.BR libar2simplified_recommendation (3), +.BR libar2simplified_hash (3), +.BR libar2_decode_params (3), +.BR libar2_validate_params (3), +.BR libar2_hash (3) diff --git a/libar2simplified_decode_r.c b/libar2simplified_decode_r.c new file mode 100644 index 0000000..e49907c --- /dev/null +++ b/libar2simplified_decode_r.c @@ -0,0 +1,196 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifdef __linux__ +#include <sys/random.h> +#endif +#include <time.h> + + +static size_t +decode_u32(const char *s, uint_least32_t *outp) +{ +	uint_least32_t digit; +	size_t i; + +	if ((s[0] == '0' && s[1] == '0') || !isdigit(s[0])) { +		errno = EINVAL; +		return 0; +	} + +	*outp = 0; +	for (i = 0; isdigit(s[i]); i++) { +		digit = (uint_least32_t)(s[i] & 15); +		if (*outp > ((uint_least32_t)0xFFFFffffUL - digit) / 10) { +			errno = ERANGE; +			return 0; +		} +		*outp = *outp * 10 + digit; +	} + +	return i; +} + + +static int +random_salt(char *out, size_t n, int (*random_byte_generator)(char *out, size_t n, void *user_data), void *user_data) +{ +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +	static int srand_called = 0; + +	double x; +	size_t i; +	int xi; +#ifdef __linux__ +	ssize_t r; +#endif + +	if (random_byte_generator) { +		if (random_byte_generator(out, n, user_data)) +			return -1; +	} else { +		i = 0; +#ifdef __linux__ +		for(; i < n; i += (size_t)r) { +			r = getrandom(&out[i], n - i, GRND_NONBLOCK); +			if(r < 0) +				break; +		} +#endif +		if (!srand_called) { +			srand((unsigned int)time(NULL) ^ (unsigned int)rand()); +			srand_called = 1; +		} +		for(; i < n; i++) { +			xi = rand(); +			x = (double)xi; +			x /= (double)RAND_MAX; +			x *= 63; +			out[i] = (char)x; +		} +	} + +	for (i = 0; i < n; i++) +		out[i] = ALPHABET[out[i] % 64]; +	return 0; +} + + +static void * +allocate(size_t num, size_t size, size_t alignment, struct libar2_context *ctx) +{ +	(void) ctx; +	(void) alignment; +	return malloc(num * size); +} + + +static void +deallocate(void *ptr, struct libar2_context *ctx) +{ +	(void) ctx; +	free(ptr); +} + + +struct libar2_argon2_parameters * +libar2simplified_decode_r(const char *str, char **tagp, char **endp, +                          int (*random_byte_generator)(char *out, size_t n, void *user_data), +                          void *user_data) +{ +	struct libar2_argon2_parameters params, *ret; +	const char *p = str; +	const char *end; +	char *str_free = NULL; +	char *buf = NULL; +	size_t n, saltsize, offset; +	uint_least32_t saltlen, hashlen; +	struct libar2_context ctx; + +	if (*p != '$') +		goto einval; +	p = strchr(&p[1], '$'); +	if (!p) +		goto einval; +	if (p[1] == 'v' && p[2] == '=') { +		p = strchr(&p[1], '$'); +		if (!p) +			goto einval; +	} +	p = strchr(&p[1], '$'); +	if (!p) +		goto einval; +	p++; +	end = strchr(p, '$'); +	if (!end) +		goto einval; + +	if (*p == '*') { +		n = decode_u32(&p[1], &saltlen); +		if (!n++) +			goto fail; +		if (&p[n] != end) +			goto einval; +		params.saltlen = (size_t)saltlen; +		saltsize = libar2_encode_base64(NULL, NULL, saltlen) - 1; +		offset = (size_t)(p - str); +		str_free = malloc(offset + saltsize + strlen(&p[n]) + 1); +		if (!str_free) +			goto enomem; +		memcpy(str_free, str, offset); +		if (random_salt(&str_free[offset], saltsize, random_byte_generator, user_data)) +			goto fail; +		offset += saltsize; +		stpcpy(&str_free[offset], &p[n]); +		str = str_free; +	} +	end++; + +	ctx.allocate = allocate; +	ctx.deallocate = deallocate; + +	if (!libar2_decode_params(str, ¶ms, &buf, &ctx)) +		goto fail; + +	if (*end == '*') { +		n = decode_u32(&end[1], &hashlen); +		if (!n++) +			goto fail; +		end = &end[n]; +		params.hashlen = (size_t)hashlen; +		if (tagp) +			*tagp = NULL; +	} else { +		if (tagp) +			*tagp = *(void **)(void *)&end; +		end = &end[libar2_encode_base64(NULL, NULL, params.hashlen) - 1]; +	} + +	ret = malloc(sizeof(params) + params.saltlen); +	if (!ret) +		goto enomem; +	memcpy(ret, ¶ms, sizeof(params)); +	if (buf) { +		memcpy(&((char *)ret)[sizeof(params)], buf, params.saltlen); +		ret->salt = &((unsigned char *)ret)[sizeof(params)]; +		deallocate(buf, &ctx); +	} + +	if (endp) +		*endp = *(void **)(void *)&end; + +	free(str_free); +	return ret; + +einval: +	errno = EINVAL; +	return NULL; + +fail: +	free(str_free); +	return NULL; + +enomem: +	free(str_free); +	errno = ENOMEM; +	return NULL; +} @@ -10,6 +10,8 @@  #define SALT_ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +#define TIME_RECOMMENDATIONS 0 +  #define MEM(S) S, sizeof(S) - 1 @@ -183,6 +185,7 @@ check_random_salt_generate(void)  } +#if TIME_RECOMMENDATIONS  static void  time_hash(const char *params_str, const char *params_name, int lineno)  { @@ -216,6 +219,7 @@ time_hash(const char *params_str, const char *params_name, int lineno)  	from_lineno = 0;  } +#endif  static int @@ -291,7 +295,7 @@ main(void)  	assert_streq(libar2simplified_recommendation(1), RECOMMENDATION_SIDE_CHANNEL_FREE_ENVIRONMENT);  #endif -#if 0 +#if TIME_RECOMMENDATIONS  #define TIME_HASH(PARAMS) time_hash(PARAMS, #PARAMS, __LINE__)  	TIME_HASH(libar2simplified_recommendation(0));  	TIME_HASH(libar2simplified_recommendation(1)); | 
