Argon2: use sodium_{bin2base64,base642bin} instead of a private implementation

This commit is contained in:
Frank Denis 2017-08-09 22:25:10 +02:00
parent 265bdcfe07
commit 76995c52ff

View File

@ -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'.
@ -303,11 +141,15 @@ decode_string(argon2_context *ctx, const char *str, argon2_type type)
#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, \
&bin_len, &str_end, \
sodium_base64_VARIANT_ORIGINAL_NO_PADDING) != 0 || \
bin_len > UINT32_MAX) { \
return ARGON2_DECODING_FAIL; \ return ARGON2_DECODING_FAIL; \
} \ } \
(len) = (uint32_t) bin_len; \ (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;
@ -418,10 +260,12 @@ encode_string(char *dst, size_t dst_len, argon2_context *ctx, argon2_type type)
#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), \
sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == NULL) { \
return ARGON2_ENCODING_FAIL; \ return ARGON2_ENCODING_FAIL; \
} \ } \
sb_len = strlen(dst); \
dst += sb_len; \ dst += sb_len; \
dst_len -= sb_len; \ dst_len -= sb_len; \
} while ((void) 0, 0) } while ((void) 0, 0)