Argon2: use sodium_{bin2base64,base642bin} instead of a private implementation
This commit is contained in:
parent
265bdcfe07
commit
76995c52ff
@ -1,5 +1,6 @@
|
|||||||
#include "argon2-encoding.h"
|
#include "argon2-encoding.h"
|
||||||
#include "argon2-core.h"
|
#include "argon2-core.h"
|
||||||
|
#include "utils.h"
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -9,19 +10,6 @@
|
|||||||
* Example code for a decoder and encoder of "hash strings", with Argon2
|
* Example code for a decoder and encoder of "hash strings", with Argon2
|
||||||
* parameters.
|
* parameters.
|
||||||
*
|
*
|
||||||
* This code comprises three sections:
|
|
||||||
*
|
|
||||||
* -- The first section contains generic Base64 encoding and decoding
|
|
||||||
* functions. It is conceptually applicable to any hash function
|
|
||||||
* implementation that uses Base64 to encode and decode parameters,
|
|
||||||
* salts and outputs. It could be made into a library, provided that
|
|
||||||
* 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 Argon2. It encodes and decodes
|
|
||||||
* the parameters, salts and outputs. It does not compute the hash
|
|
||||||
* itself.
|
|
||||||
*
|
|
||||||
* The code was originally written by Thomas Pornin <pornin@bolet.org>,
|
* The code was originally written by Thomas Pornin <pornin@bolet.org>,
|
||||||
* to whom comments and remarks may be sent. It is released under what
|
* to whom comments and remarks may be sent. It is released under what
|
||||||
* should amount to Public Domain or its closest equivalent; the
|
* should amount to Public Domain or its closest equivalent; the
|
||||||
@ -39,156 +27,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
/*
|
|
||||||
* Common code; could be shared between different hash functions.
|
|
||||||
*
|
|
||||||
* Note: the Base64 functions below assume that uppercase letters (resp.
|
|
||||||
* lowercase letters) have consecutive numerical codes, that fit on 8
|
|
||||||
* bits. All modern systems use ASCII-compatible charsets, where these
|
|
||||||
* properties are true. If you are stuck with a dinosaur of a system
|
|
||||||
* that still defaults to EBCDIC then you already have much bigger
|
|
||||||
* interoperability issues to deal with.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some macros for constant-time comparisons. These work over values in
|
|
||||||
* the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
|
|
||||||
*/
|
|
||||||
#define EQ(x, y) \
|
|
||||||
((((0U - ((unsigned) (x) ^ (unsigned) (y))) >> 8) & 0xFF) ^ 0xFF)
|
|
||||||
#define GT(x, y) ((((unsigned) (y) - (unsigned) (x)) >> 8) & 0xFF)
|
|
||||||
#define GE(x, y) (GT(y, x) ^ 0xFF)
|
|
||||||
#define LT(x, y) GT(y, x)
|
|
||||||
#define LE(x, y) GE(y, x)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert value x (0..63) to corresponding Base64 character.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
b64_byte_to_char(unsigned x)
|
|
||||||
{
|
|
||||||
return (LT(x, 26) & (x + 'A')) |
|
|
||||||
(GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
|
|
||||||
(GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
|
|
||||||
(EQ(x, 63) & '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert character c to the corresponding 6-bit value. If character c
|
|
||||||
* is not a Base64 character, then 0xFF (255) is returned.
|
|
||||||
*/
|
|
||||||
static unsigned
|
|
||||||
b64_char_to_byte(int c)
|
|
||||||
{
|
|
||||||
unsigned x;
|
|
||||||
|
|
||||||
x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
|
|
||||||
(GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
|
|
||||||
(GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |
|
|
||||||
(EQ(c, '/') & 63);
|
|
||||||
return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert some bytes to Base64. 'dst_len' is the length (in characters)
|
|
||||||
* of the output buffer 'dst'; if that buffer is not large enough to
|
|
||||||
* receive the result (including the terminating 0), then (size_t)-1
|
|
||||||
* is returned. Otherwise, the zero-terminated Base64 string is written
|
|
||||||
* in the buffer, and the output length (counted WITHOUT the terminating
|
|
||||||
* zero) is returned.
|
|
||||||
*/
|
|
||||||
static size_t
|
|
||||||
to_base64(char *dst, size_t dst_len, const void *src, size_t src_len)
|
|
||||||
{
|
|
||||||
size_t olen;
|
|
||||||
const unsigned char *buf;
|
|
||||||
unsigned acc, acc_len;
|
|
||||||
|
|
||||||
olen = (src_len / 3) << 2;
|
|
||||||
switch (src_len % 3) {
|
|
||||||
case 2:
|
|
||||||
olen++;
|
|
||||||
/* fall through */
|
|
||||||
case 1:
|
|
||||||
olen += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (dst_len <= olen) {
|
|
||||||
return (size_t) -1;
|
|
||||||
}
|
|
||||||
acc = 0;
|
|
||||||
acc_len = 0;
|
|
||||||
buf = (const unsigned char *) src;
|
|
||||||
while (src_len-- > 0) {
|
|
||||||
acc = (acc << 8) + (*buf++);
|
|
||||||
acc_len += 8;
|
|
||||||
while (acc_len >= 6) {
|
|
||||||
acc_len -= 6;
|
|
||||||
*dst++ = (char) b64_byte_to_char((acc >> acc_len) & 0x3F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (acc_len > 0) {
|
|
||||||
*dst++ = (char) b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);
|
|
||||||
}
|
|
||||||
*dst++ = 0;
|
|
||||||
return olen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decode Base64 chars into bytes. The '*dst_len' value must initially
|
|
||||||
* contain the length of the output buffer '*dst'; when the decoding
|
|
||||||
* ends, the actual number of decoded bytes is written back in
|
|
||||||
* '*dst_len'.
|
|
||||||
*
|
|
||||||
* Decoding stops when a non-Base64 character is encountered, or when
|
|
||||||
* the output buffer capacity is exceeded. If an error occurred (output
|
|
||||||
* buffer is too small, invalid last characters leading to unprocessed
|
|
||||||
* buffered bits), then NULL is returned; otherwise, the returned value
|
|
||||||
* points to the first non-Base64 character in the source stream, which
|
|
||||||
* may be the terminating zero.
|
|
||||||
*/
|
|
||||||
static const char *
|
|
||||||
from_base64(void *dst, size_t *dst_len, const char *src)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
unsigned char *buf;
|
|
||||||
unsigned acc, acc_len;
|
|
||||||
|
|
||||||
buf = (unsigned char *) dst;
|
|
||||||
len = 0;
|
|
||||||
acc = 0;
|
|
||||||
acc_len = 0;
|
|
||||||
for (;;) {
|
|
||||||
unsigned d;
|
|
||||||
|
|
||||||
d = b64_char_to_byte(*src);
|
|
||||||
if (d == 0xFF) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
src++;
|
|
||||||
acc = (acc << 6) + d;
|
|
||||||
acc_len += 6;
|
|
||||||
if (acc_len >= 8) {
|
|
||||||
acc_len -= 8;
|
|
||||||
if ((len++) >= *dst_len) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*buf++ = (acc >> acc_len) & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the input length is equal to 1 modulo 4 (which is
|
|
||||||
* invalid), then there will remain 6 unprocessed bits;
|
|
||||||
* otherwise, only 0, 2 or 4 bits are buffered. The buffered
|
|
||||||
* bits must also all be zero.
|
|
||||||
*/
|
|
||||||
if (acc_len > 4 || (acc & ((1U << acc_len) - 1)) != 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*dst_len = len;
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode decimal integer from 'str'; the value is written in '*v'.
|
* Decode decimal integer from 'str'; the value is written in '*v'.
|
||||||
@ -300,14 +138,18 @@ decode_string(argon2_context *ctx, const char *str, argon2_type type)
|
|||||||
} while ((void)0, 0)
|
} while ((void)0, 0)
|
||||||
|
|
||||||
/* Decoding base64 into a binary buffer */
|
/* Decoding base64 into a binary buffer */
|
||||||
#define BIN(buf, max_len, len) \
|
#define BIN(buf, max_len, len) \
|
||||||
do { \
|
do { \
|
||||||
size_t bin_len = (max_len); \
|
size_t bin_len = (max_len); \
|
||||||
str = from_base64(buf, &bin_len, str); \
|
const char *str_end; \
|
||||||
if (str == NULL || bin_len > UINT32_MAX) { \
|
if (sodium_base642bin((buf), (max_len), str, strlen(str), NULL, \
|
||||||
return ARGON2_DECODING_FAIL; \
|
&bin_len, &str_end, \
|
||||||
} \
|
sodium_base64_VARIANT_ORIGINAL_NO_PADDING) != 0 || \
|
||||||
(len) = (uint32_t) bin_len; \
|
bin_len > UINT32_MAX) { \
|
||||||
|
return ARGON2_DECODING_FAIL; \
|
||||||
|
} \
|
||||||
|
(len) = (uint32_t) bin_len; \
|
||||||
|
str = str_end; \
|
||||||
} while ((void) 0, 0)
|
} while ((void) 0, 0)
|
||||||
|
|
||||||
size_t maxsaltlen = ctx->saltlen;
|
size_t maxsaltlen = ctx->saltlen;
|
||||||
@ -416,14 +258,16 @@ encode_string(char *dst, size_t dst_len, argon2_context *ctx, argon2_type type)
|
|||||||
SS(tmp); \
|
SS(tmp); \
|
||||||
} while ((void) 0, 0)
|
} while ((void) 0, 0)
|
||||||
|
|
||||||
#define SB(buf, len) \
|
#define SB(buf, len) \
|
||||||
do { \
|
do { \
|
||||||
size_t sb_len = to_base64(dst, dst_len, buf, len); \
|
size_t sb_len; \
|
||||||
if (sb_len == (size_t) -1) { \
|
if (sodium_bin2base64(dst, dst_len, (buf), (len), \
|
||||||
return ARGON2_ENCODING_FAIL; \
|
sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == NULL) { \
|
||||||
} \
|
return ARGON2_ENCODING_FAIL; \
|
||||||
dst += sb_len; \
|
} \
|
||||||
dst_len -= sb_len; \
|
sb_len = strlen(dst); \
|
||||||
|
dst += sb_len; \
|
||||||
|
dst_len -= sb_len; \
|
||||||
} while ((void) 0, 0)
|
} while ((void) 0, 0)
|
||||||
|
|
||||||
int validation_result;
|
int validation_result;
|
||||||
|
Loading…
Reference in New Issue
Block a user