mirror of
https://git.sr.ht/~sircmpwn/mkproof
synced 2024-06-08 16:36:07 +02:00
Decoding length clarified
argon2_verify() puts hard constraints on the lengths of ad, salt, and output, as well as t,m,p values, which were not properly reflected in the description
This commit is contained in:
parent
7788a0ec61
commit
56c177a00d
24
src/argon2.c
24
src/argon2.c
|
@ -102,7 +102,9 @@ static const char *Argon2_ErrorMessage[] = {
|
|||
/*},
|
||||
{ARGON2_DECODING_FAIL, */ "Decoding failed",
|
||||
/*},
|
||||
{ARGON2_THREAD_FAIL */ "Threading failure", /*},*/
|
||||
{ARGON2_THREAD_FAIL */ "Threading failure",
|
||||
/*,
|
||||
{ARGON2_DECODING_LENGTH_FAIL */ "Some of encoded parameters are too long or too short" /*},*/
|
||||
};
|
||||
|
||||
|
||||
|
@ -213,7 +215,7 @@ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
|
|||
result = argon2_core(&context, type);
|
||||
|
||||
if (result != ARGON2_OK) {
|
||||
memset(out, 0x00, hashlen);
|
||||
secure_wipe_memory(out, hashlen);
|
||||
free(out);
|
||||
return result;
|
||||
}
|
||||
|
@ -226,13 +228,13 @@ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
|
|||
/* if encoding requested, write it */
|
||||
if (encoded && encodedlen) {
|
||||
if (!encode_string(encoded, encodedlen, &context, type)) {
|
||||
memset(out, 0x00, hashlen);
|
||||
memset(encoded, 0x00, encodedlen);
|
||||
secure_wipe_memory(out, hashlen);//wipe buffers if error
|
||||
secure_wipe_memory(encoded, encodedlen);
|
||||
free(out);
|
||||
return ARGON2_ENCODING_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
secure_wipe_memory(out, hashlen);
|
||||
free(out);
|
||||
|
||||
return ARGON2_OK;
|
||||
|
@ -294,9 +296,9 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
|
|||
int ret;
|
||||
|
||||
/* max values, to be updated in decode_string */
|
||||
ctx.adlen = 512;
|
||||
ctx.saltlen = 512;
|
||||
ctx.outlen = 512;
|
||||
ctx.adlen = ARGON2_MAX_DECODED_AD_LEN;
|
||||
ctx.saltlen = ARGON2_MAX_DECODED_SALT_LEN;
|
||||
ctx.outlen = ARGON2_MAX_DECODED_OUT_LEN;
|
||||
|
||||
ctx.ad = malloc(ctx.adlen);
|
||||
ctx.salt = malloc(ctx.saltlen);
|
||||
|
@ -314,13 +316,13 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
|
|||
free(ctx.out);
|
||||
return ARGON2_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
|
||||
if(decode_string(&ctx, encoded, type) != 1) {
|
||||
int decode_result = decode_string(&ctx, encoded, type);
|
||||
if(decode_result != 1) {
|
||||
free(ctx.ad);
|
||||
free(ctx.salt);
|
||||
free(ctx.out);
|
||||
free(out);
|
||||
return ARGON2_DECODING_FAIL;
|
||||
return decode_result;
|
||||
}
|
||||
|
||||
ret = argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen, ctx.salt,
|
||||
|
|
17
src/argon2.h
17
src/argon2.h
|
@ -131,6 +131,8 @@ typedef enum Argon2_ErrorCodes {
|
|||
|
||||
ARGON2_THREAD_FAIL = 33,
|
||||
|
||||
ARGON2_DECODING_LENGTH_FAIL=34,
|
||||
|
||||
ARGON2_ERROR_CODES_LENGTH /* Do NOT remove; Do NOT add error codes after
|
||||
this
|
||||
error code */
|
||||
|
@ -197,6 +199,12 @@ typedef struct Argon2_Context {
|
|||
typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type;
|
||||
|
||||
|
||||
/*****Decoding restrictions (maximal salt/ad/out lengths allowed in a string to be decoded******/
|
||||
#define ARGON2_MAX_DECODED_SALT_LEN UINT32_C(512)
|
||||
#define ARGON2_MAX_DECODED_OUT_LEN UINT32_C(512)
|
||||
#define ARGON2_MAX_DECODED_AD_LEN UINT32_C(512)
|
||||
|
||||
|
||||
/*
|
||||
* Function that performs memory-hard hashing with certain degree of parallelism
|
||||
* @param context Pointer to the Argon2 internal structure
|
||||
|
@ -226,7 +234,7 @@ int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
|
|||
char *encoded, const size_t encodedlen);
|
||||
|
||||
/**
|
||||
* Hashes a password with Argon2i, producing a raw hash
|
||||
* Hashes a password with Argon2i, producing a raw hash by allocating memory at @hash
|
||||
* @param t_cost Number of iterations
|
||||
* @param m_cost Sets memory usage to m_cost kibibytes
|
||||
* @param parallelism Number of threads and compute lanes
|
||||
|
@ -234,7 +242,7 @@ int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
|
|||
* @param pwdlen Password size in bytes
|
||||
* @param salt Pointer to salt
|
||||
* @param saltlen Salt size in bytes
|
||||
* @param hash Buffer where to write the raw hash
|
||||
* @param hash Buffer where to write the raw hash - updated by the function
|
||||
* @param hashlen Desired length of the hash in bytes
|
||||
* @pre Different parallelism levels will give different results
|
||||
* @pre Returns ARGON2_OK if successful
|
||||
|
@ -264,6 +272,11 @@ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
|
|||
|
||||
/**
|
||||
* Verifies a password against an encoded string
|
||||
* Encoded string has the following restrictions:
|
||||
* Salt between ARGON2_MIN_DECODED_SALT_LEN and ARGON2_MAX_DECODED_SALT_LEN
|
||||
* Parallelism between 1 and ARGON2_MAX_DECODED_LANES
|
||||
* Associated data no longer than ARGON2_MAX_DECODED_AD_LEN
|
||||
* Output between ARGON2_MIN_DECODED_OUT_LEN and ARGON2_MAX_DECODED_OUT_LEN
|
||||
* @param encoded String encoding parameters, salt, hash
|
||||
* @param pwd Pointer to password
|
||||
* @pre Returns ARGON2_OK if successful
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "encoding.h"
|
||||
|
||||
#/*
|
||||
* Example code for a decoder and encoder of "hash strings", with Argon2i
|
||||
* Example code for a decoder and encoder of "hash strings", with Argon2
|
||||
* parameters.
|
||||
*
|
||||
* This code comprises three sections:
|
||||
|
@ -17,7 +17,7 @@
|
|||
* the relevant functions are made public (non-static) and be given
|
||||
* reasonable names to avoid collisions with other functions.
|
||||
*
|
||||
* -- The second section is specific to Argon2i. It encodes and decodes
|
||||
* -- The second section is specific to Argon2. It encodes and decodes
|
||||
* the parameters, salts and outputs. It does not compute the hash
|
||||
* itself.
|
||||
*
|
||||
|
@ -224,13 +224,13 @@ static const char *decode_decimal(const char *str, unsigned long *v) {
|
|||
|
||||
/* ==================================================================== */
|
||||
/*
|
||||
* Code specific to Argon2i.
|
||||
* Code specific to Argon2.
|
||||
*
|
||||
* The code below applies the following format:
|
||||
*
|
||||
* $argon2i$m=<num>,t=<num>,p=<num>[,keyid=<bin>][,data=<bin>][$<bin>[$<bin>]]
|
||||
* $argon2<T>$m=<num>,t=<num>,p=<num>[,keyid=<bin>][,data=<bin>][$<bin>[$<bin>]]
|
||||
*
|
||||
* where <num> is a decimal integer (positive, fits in an 'unsigned long')
|
||||
* where <T> is either 'd' or 'i', <num> is a decimal integer (positive, fits in an 'unsigned long'),
|
||||
* and <bin> is Base64-encoded data (no '=' padding characters, no newline
|
||||
* or whitespace). The "keyid" is a binary identifier for a key (up to 8
|
||||
* bytes); "data" is associated data (up to 32 bytes). When the 'keyid'
|
||||
|
@ -242,11 +242,9 @@ static const char *decode_decimal(const char *str, unsigned long *v) {
|
|||
* The output length is always exactly 32 bytes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Decode an Argon2i hash string into the provided structure 'ctx'.
|
||||
* Returned value is 1 on success, 0 on error.
|
||||
*/
|
||||
int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
||||
|
||||
//check for prefix
|
||||
#define CC(prefix) \
|
||||
do { \
|
||||
size_t cc_len = strlen(prefix); \
|
||||
|
@ -256,6 +254,7 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
|||
str += cc_len; \
|
||||
} while ((void)0, 0)
|
||||
|
||||
//prefix checking with supplied code
|
||||
#define CC_opt(prefix, code) \
|
||||
do { \
|
||||
size_t cc_len = strlen(prefix); \
|
||||
|
@ -265,6 +264,7 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
|||
} \
|
||||
} while ((void)0, 0)
|
||||
|
||||
//Decoding prefix into decimal
|
||||
#define DECIMAL(x) \
|
||||
do { \
|
||||
unsigned long dec_x; \
|
||||
|
@ -297,7 +297,7 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
|||
else if (type == Argon2_d)
|
||||
CC("$argon2d");
|
||||
else
|
||||
return 0;
|
||||
return ARGON2_INCORRECT_TYPE;
|
||||
CC("$m=");
|
||||
DECIMAL(ctx->m_cost);
|
||||
CC(",t=");
|
||||
|
@ -313,22 +313,22 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
|||
* on machines where 'unsigned long' is a 32-bit type.
|
||||
*/
|
||||
if (ctx->m_cost < 1 || (ctx->m_cost >> 30) > 3) {
|
||||
return 0;
|
||||
return ARGON2_DECODING_LENGTH_FAIL;
|
||||
}
|
||||
if (ctx->t_cost < 1 || (ctx->t_cost >> 30) > 3) {
|
||||
return 0;
|
||||
return ARGON2_DECODING_LENGTH_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parallelism p must be between 1 and 255. The memory cost
|
||||
* The parallelism p must be between 1 and ARGON2_MAX_DECODED_LANES. The memory cost
|
||||
* parameter, expressed in kilobytes, must be at least 8 times
|
||||
* the value of p.
|
||||
*/
|
||||
if (ctx->lanes < 1 || ctx->lanes > 255) {
|
||||
return 0;
|
||||
if (ctx->lanes < 1 || ctx->lanes > ARGON2_MAX_DECODED_LANES) {
|
||||
return ARGON2_DECODING_LENGTH_FAIL;
|
||||
}
|
||||
if (ctx->m_cost < (ctx->lanes << 3)) {
|
||||
return 0;
|
||||
return ARGON2_DECODING_LENGTH_FAIL;
|
||||
}
|
||||
|
||||
CC_opt(",data=", BIN(ctx->ad, maxadlen, ctx->adlen));
|
||||
|
@ -337,16 +337,16 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
|||
}
|
||||
CC("$");
|
||||
BIN(ctx->salt, maxsaltlen, ctx->saltlen);
|
||||
if (ctx->saltlen < 8) {
|
||||
return 0;
|
||||
if (ctx->saltlen < ARGON2_MIN_DECODED_SALT_LEN) {
|
||||
return ARGON2_DECODING_LENGTH_FAIL;
|
||||
}
|
||||
if (*str == 0) {
|
||||
return 1;
|
||||
}
|
||||
CC("$");
|
||||
BIN(ctx->out, maxoutlen, ctx->outlen);
|
||||
if (ctx->outlen < 12) {
|
||||
return 0;
|
||||
if (ctx->outlen < ARGON2_MIN_DECODED_OUT_LEN) {
|
||||
return ARGON2_DECODING_LENGTH_FAIL;
|
||||
}
|
||||
return *str == 0;
|
||||
|
||||
|
@ -356,18 +356,6 @@ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
|
|||
#undef BIN
|
||||
}
|
||||
|
||||
/*
|
||||
* encode an argon2i hash string into the provided buffer. 'dst_len'
|
||||
* contains the size, in characters, of the 'dst' buffer; if 'dst_len'
|
||||
* is less than the number of required characters (including the
|
||||
* terminating 0), then this function returns 0.
|
||||
*
|
||||
* if pp->output_len is 0, then the hash string will be a salt string
|
||||
* (no output). if pp->salt_len is also 0, then the string will be a
|
||||
* parameter-only string (no salt and no output).
|
||||
*
|
||||
* on success, 1 is returned.
|
||||
*/
|
||||
int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
|
||||
argon2_type type) {
|
||||
#define SS(str) \
|
||||
|
|
|
@ -2,9 +2,42 @@
|
|||
#define ENCODING_H
|
||||
#include "argon2.h"
|
||||
|
||||
#define ARGON2_MAX_DECODED_LANES UINT32_C(255)
|
||||
#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8)
|
||||
#define ARGON2_MIN_DECODED_OUT_LEN UINT32_C(12)
|
||||
|
||||
|
||||
/*
|
||||
* encode an Argon2 hash string into the provided buffer. 'dst_len'
|
||||
* contains the size, in characters, of the 'dst' buffer; if 'dst_len'
|
||||
* is less than the number of required characters (including the
|
||||
* terminating 0), then this function returns 0.
|
||||
*
|
||||
* if ctx->outlen is 0, then the hash string will be a salt string
|
||||
* (no output). if ctx->saltlen is also 0, then the string will be a
|
||||
* parameter-only string (no salt and no output).
|
||||
*
|
||||
* on success, 1 is returned.
|
||||
*
|
||||
* No other parameters are checked
|
||||
*/
|
||||
int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
|
||||
argon2_type type);
|
||||
|
||||
|
||||
/*
|
||||
* Decodes an Argon2 hash string into the provided structure 'ctx'.
|
||||
* The fields ctx.saltlen, ctx.adlen, ctx.outlen set the maximal salt, ad, out length values
|
||||
* that are allowed; invalid input string causes an error
|
||||
* Returned value is 1 on success, 0 on error.
|
||||
*
|
||||
* WARNING: the procedure rejects some inputs that are valid outputs of encode_string(), see below
|
||||
* Allows m_cost and t_cost between 1 and 2^32-1 (hard-coded values),
|
||||
* parallelism between 1 and ARGON2_MAX_DECODED_LANES.
|
||||
* Also rejects m_cost if smaller than 8 times parallelism.
|
||||
* Rejects salts shorter than ARGON2_MIN_DECODED_SALT_LEN bytes.
|
||||
* Rejects hashes shorter than ARGON2_MIN_DECODED_OUT_LEN bytes.
|
||||
*/
|
||||
int decode_string(argon2_context *ctx, const char *str, argon2_type type);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue