| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /*
- * Argon2 reference source code package - reference C implementations
- *
- * Copyright 2015
- * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
- *
- * You may use this work under the terms of a Creative Commons CC0 1.0
- * License/Waiver or the Apache Public License 2.0, at your option. The terms of
- * these licenses can be found at:
- *
- * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
- *
- * You should have received a copy of both of these licenses along with this
- * software. If not, they may be obtained at the above URLs.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- #include "encoding.h"
- #include "core.h"
- /*
- * Example code for a decoder and encoder of "hash strings", with Argon2
- * 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>,
- * to whom comments and remarks may be sent. It is released under what
- * should amount to Public Domain or its closest equivalent; the
- * following mantra is supposed to incarnate that fact with all the
- * proper legal rituals:
- *
- * ---------------------------------------------------------------------
- * This file is provided under the terms of Creative Commons CC0 1.0
- * Public Domain Dedication. To the extent possible under law, the
- * author (Thomas Pornin) has waived all copyright and related or
- * neighboring rights to this file. This work is published from: Canada.
- * ---------------------------------------------------------------------
- *
- * Copyright (c) 2015 Thomas Pornin
- */
- /* ==================================================================== */
- /*
- * 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 & (((unsigned)1 << acc_len) - 1)) != 0) {
- return NULL;
- }
- *dst_len = len;
- return src;
- }
- /*
- * Decode decimal integer from 'str'; the value is written in '*v'.
- * Returned value is a pointer to the next non-decimal character in the
- * string. If there is no digit at all, or the value encoding is not
- * minimal (extra leading zeros), or the value does not fit in an
- * 'unsigned long', then NULL is returned.
- */
- static const char *decode_decimal(const char *str, unsigned long *v) {
- const char *orig;
- unsigned long acc;
- acc = 0;
- for (orig = str;; str++) {
- int c;
- c = *str;
- if (c < '0' || c > '9') {
- break;
- }
- c -= '0';
- if (acc > (ULONG_MAX / 10)) {
- return NULL;
- }
- acc *= 10;
- if ((unsigned long)c > (ULONG_MAX - acc)) {
- return NULL;
- }
- acc += (unsigned long)c;
- }
- if (str == orig || (*orig == '0' && str != (orig + 1))) {
- return NULL;
- }
- *v = acc;
- return str;
- }
- /* ==================================================================== */
- /*
- * Code specific to Argon2.
- *
- * The code below applies the following format:
- *
- * $argon2<T>[$v=<num>]$m=<num>,t=<num>,p=<num>$<bin>$<bin>
- *
- * where <T> is either 'd', 'id', 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 last two binary chunks (encoded in Base64) are, in that order,
- * the salt and the output. Both are required. The binary salt length and the
- * output length must be in the allowed ranges defined in argon2.h.
- *
- * The ctx struct must contain buffers large enough to hold the salt and pwd
- * when it is fed into decode_string.
- */
- int decode_string(argon2_context_t *ctx, const char *str, argon2_type_t type) {
- /* check for prefix */
- #define CC(prefix) \
- do { \
- size_t cc_len = strlen(prefix); \
- if (strncmp(str, prefix, cc_len) != 0) { \
- return ARGON2_DECODING_FAIL; \
- } \
- str += cc_len; \
- } while ((void)0, 0)
- /* optional prefix checking with supplied code */
- #define CC_opt(prefix, code) \
- do { \
- size_t cc_len = strlen(prefix); \
- if (strncmp(str, prefix, cc_len) == 0) { \
- str += cc_len; \
- { code; } \
- } \
- } while ((void)0, 0)
- /* Decoding prefix into decimal */
- #define DECIMAL(x) \
- do { \
- unsigned long dec_x; \
- str = decode_decimal(str, &dec_x); \
- if (str == NULL) { \
- return ARGON2_DECODING_FAIL; \
- } \
- (x) = dec_x; \
- } while ((void)0, 0)
- /* Decoding prefix into uint32_t decimal */
- #define DECIMAL_U32(x) \
- do { \
- unsigned long dec_x; \
- str = decode_decimal(str, &dec_x); \
- if (str == NULL || dec_x > UINT32_MAX) { \
- return ARGON2_DECODING_FAIL; \
- } \
- (x) = (uint32_t)dec_x; \
- } while ((void)0, 0)
- /* Decoding base64 into a binary buffer */
- #define BIN(buf, max_len, len) \
- do { \
- size_t bin_len = (max_len); \
- str = from_base64(buf, &bin_len, str); \
- if (str == NULL || bin_len > UINT32_MAX) { \
- return ARGON2_DECODING_FAIL; \
- } \
- (len) = (uint32_t)bin_len; \
- } while ((void)0, 0)
- size_t maxsaltlen = ctx->saltlen;
- size_t maxoutlen = ctx->outlen;
- int validation_result;
- const char* type_string;
- /* We should start with the argon2_type we are using */
- type_string = kp_argon2_type2string(type, 0);
- if (!type_string) {
- return ARGON2_INCORRECT_TYPE;
- }
- CC("$");
- CC(type_string);
- /* Reading the version number if the default is suppressed */
- ctx->version = ARGON2_VERSION_10;
- CC_opt("$v=", DECIMAL_U32(ctx->version));
- CC("$m=");
- DECIMAL_U32(ctx->m_cost);
- CC(",t=");
- DECIMAL_U32(ctx->t_cost);
- CC(",p=");
- DECIMAL_U32(ctx->lanes);
- ctx->threads = ctx->lanes;
- CC("$");
- BIN(ctx->salt, maxsaltlen, ctx->saltlen);
- CC("$");
- BIN(ctx->out, maxoutlen, ctx->outlen);
- /* The rest of the fields get the default values */
- ctx->secret = NULL;
- ctx->secretlen = 0;
- ctx->ad = NULL;
- ctx->adlen = 0;
- ctx->allocate_cbk = NULL;
- ctx->free_cbk = NULL;
- ctx->flags = ARGON2_DEFAULT_FLAGS;
- /* On return, must have valid context */
- validation_result = validate_inputs(ctx);
- if (validation_result != ARGON2_OK) {
- return validation_result;
- }
- /* Can't have any additional characters */
- if (*str == 0) {
- return ARGON2_OK;
- } else {
- return ARGON2_DECODING_FAIL;
- }
- #undef CC
- #undef CC_opt
- #undef DECIMAL
- #undef BIN
- }
- int encode_string(char *dst, size_t dst_len, argon2_context_t *ctx,
- argon2_type_t type) {
- #define SS(str) \
- do { \
- size_t pp_len = strlen(str); \
- if (pp_len >= dst_len) { \
- return ARGON2_ENCODING_FAIL; \
- } \
- memcpy(dst, str, pp_len + 1); \
- dst += pp_len; \
- dst_len -= pp_len; \
- } while ((void)0, 0)
- #define SX(x) \
- do { \
- char tmp[30]; \
- sprintf(tmp, "%lu", (unsigned long)(x)); \
- SS(tmp); \
- } while ((void)0, 0)
- #define SB(buf, len) \
- do { \
- size_t sb_len = to_base64(dst, dst_len, buf, len); \
- if (sb_len == (size_t)-1) { \
- return ARGON2_ENCODING_FAIL; \
- } \
- dst += sb_len; \
- dst_len -= sb_len; \
- } while ((void)0, 0)
- const char* type_string = kp_argon2_type2string(type, 0);
- int validation_result = validate_inputs(ctx);
- if (!type_string) {
- return ARGON2_ENCODING_FAIL;
- }
- if (validation_result != ARGON2_OK) {
- return validation_result;
- }
- SS("$");
- SS(type_string);
- SS("$v=");
- SX(ctx->version);
- SS("$m=");
- SX(ctx->m_cost);
- SS(",t=");
- SX(ctx->t_cost);
- SS(",p=");
- SX(ctx->lanes);
- SS("$");
- SB(ctx->salt, ctx->saltlen);
- SS("$");
- SB(ctx->out, ctx->outlen);
- return ARGON2_OK;
- #undef SS
- #undef SX
- #undef SB
- }
- size_t b64len(uint32_t len) {
- size_t olen = ((size_t)len / 3) << 2;
- switch (len % 3) {
- case 2:
- olen++;
- /* fall through */
- case 1:
- olen += 2;
- break;
- }
- return olen;
- }
- size_t numlen(uint32_t num) {
- size_t len = 1;
- while (num >= 10) {
- ++len;
- num = num / 10;
- }
- return len;
- }
|