2
0
Fork 0
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:
khovratovich 2016-01-21 22:34:12 +01:00
parent 7788a0ec61
commit 56c177a00d
4 changed files with 81 additions and 45 deletions

View File

@ -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,

View File

@ -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

View File

@ -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) \

View File

@ -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