1*0090dad1Sjhigh /*
2*0090dad1Sjhigh * Argon2 reference source code package - reference C implementations
3*0090dad1Sjhigh *
4*0090dad1Sjhigh * Copyright 2015
5*0090dad1Sjhigh * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6*0090dad1Sjhigh *
7*0090dad1Sjhigh * You may use this work under the terms of a Creative Commons CC0 1.0
8*0090dad1Sjhigh * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9*0090dad1Sjhigh * these licenses can be found at:
10*0090dad1Sjhigh *
11*0090dad1Sjhigh * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
12*0090dad1Sjhigh * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
13*0090dad1Sjhigh *
14*0090dad1Sjhigh * You should have received a copy of both of these licenses along with this
15*0090dad1Sjhigh * software. If not, they may be obtained at the above URLs.
16*0090dad1Sjhigh */
17*0090dad1Sjhigh
18*0090dad1Sjhigh #include <stdio.h>
19*0090dad1Sjhigh #include <stdlib.h>
20*0090dad1Sjhigh #include <string.h>
21*0090dad1Sjhigh #include <limits.h>
22*0090dad1Sjhigh #include "encoding.h"
23*0090dad1Sjhigh #include "core.h"
24*0090dad1Sjhigh
25*0090dad1Sjhigh /*
26*0090dad1Sjhigh * Example code for a decoder and encoder of "hash strings", with Argon2
27*0090dad1Sjhigh * parameters.
28*0090dad1Sjhigh *
29*0090dad1Sjhigh * This code comprises three sections:
30*0090dad1Sjhigh *
31*0090dad1Sjhigh * -- The first section contains generic Base64 encoding and decoding
32*0090dad1Sjhigh * functions. It is conceptually applicable to any hash function
33*0090dad1Sjhigh * implementation that uses Base64 to encode and decode parameters,
34*0090dad1Sjhigh * salts and outputs. It could be made into a library, provided that
35*0090dad1Sjhigh * the relevant functions are made public (non-static) and be given
36*0090dad1Sjhigh * reasonable names to avoid collisions with other functions.
37*0090dad1Sjhigh *
38*0090dad1Sjhigh * -- The second section is specific to Argon2. It encodes and decodes
39*0090dad1Sjhigh * the parameters, salts and outputs. It does not compute the hash
40*0090dad1Sjhigh * itself.
41*0090dad1Sjhigh *
42*0090dad1Sjhigh * The code was originally written by Thomas Pornin <pornin@bolet.org>,
43*0090dad1Sjhigh * to whom comments and remarks may be sent. It is released under what
44*0090dad1Sjhigh * should amount to Public Domain or its closest equivalent; the
45*0090dad1Sjhigh * following mantra is supposed to incarnate that fact with all the
46*0090dad1Sjhigh * proper legal rituals:
47*0090dad1Sjhigh *
48*0090dad1Sjhigh * ---------------------------------------------------------------------
49*0090dad1Sjhigh * This file is provided under the terms of Creative Commons CC0 1.0
50*0090dad1Sjhigh * Public Domain Dedication. To the extent possible under law, the
51*0090dad1Sjhigh * author (Thomas Pornin) has waived all copyright and related or
52*0090dad1Sjhigh * neighboring rights to this file. This work is published from: Canada.
53*0090dad1Sjhigh * ---------------------------------------------------------------------
54*0090dad1Sjhigh *
55*0090dad1Sjhigh * Copyright (c) 2015 Thomas Pornin
56*0090dad1Sjhigh */
57*0090dad1Sjhigh
58*0090dad1Sjhigh /* ==================================================================== */
59*0090dad1Sjhigh /*
60*0090dad1Sjhigh * Common code; could be shared between different hash functions.
61*0090dad1Sjhigh *
62*0090dad1Sjhigh * Note: the Base64 functions below assume that uppercase letters (resp.
63*0090dad1Sjhigh * lowercase letters) have consecutive numerical codes, that fit on 8
64*0090dad1Sjhigh * bits. All modern systems use ASCII-compatible charsets, where these
65*0090dad1Sjhigh * properties are true. If you are stuck with a dinosaur of a system
66*0090dad1Sjhigh * that still defaults to EBCDIC then you already have much bigger
67*0090dad1Sjhigh * interoperability issues to deal with.
68*0090dad1Sjhigh */
69*0090dad1Sjhigh
70*0090dad1Sjhigh /*
71*0090dad1Sjhigh * Some macros for constant-time comparisons. These work over values in
72*0090dad1Sjhigh * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
73*0090dad1Sjhigh */
74*0090dad1Sjhigh #define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)
75*0090dad1Sjhigh #define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)
76*0090dad1Sjhigh #define GE(x, y) (GT(y, x) ^ 0xFF)
77*0090dad1Sjhigh #define LT(x, y) GT(y, x)
78*0090dad1Sjhigh #define LE(x, y) GE(y, x)
79*0090dad1Sjhigh
80*0090dad1Sjhigh /*
81*0090dad1Sjhigh * Convert value x (0..63) to corresponding Base64 character.
82*0090dad1Sjhigh */
b64_byte_to_char(unsigned x)83*0090dad1Sjhigh static int b64_byte_to_char(unsigned x) {
84*0090dad1Sjhigh return (LT(x, 26) & (x + 'A')) |
85*0090dad1Sjhigh (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
86*0090dad1Sjhigh (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
87*0090dad1Sjhigh (EQ(x, 63) & '/');
88*0090dad1Sjhigh }
89*0090dad1Sjhigh
90*0090dad1Sjhigh /*
91*0090dad1Sjhigh * Convert character c to the corresponding 6-bit value. If character c
92*0090dad1Sjhigh * is not a Base64 character, then 0xFF (255) is returned.
93*0090dad1Sjhigh */
b64_char_to_byte(int c)94*0090dad1Sjhigh static unsigned b64_char_to_byte(int c) {
95*0090dad1Sjhigh unsigned x;
96*0090dad1Sjhigh
97*0090dad1Sjhigh x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
98*0090dad1Sjhigh (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
99*0090dad1Sjhigh (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |
100*0090dad1Sjhigh (EQ(c, '/') & 63);
101*0090dad1Sjhigh return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
102*0090dad1Sjhigh }
103*0090dad1Sjhigh
104*0090dad1Sjhigh /*
105*0090dad1Sjhigh * Convert some bytes to Base64. 'dst_len' is the length (in characters)
106*0090dad1Sjhigh * of the output buffer 'dst'; if that buffer is not large enough to
107*0090dad1Sjhigh * receive the result (including the terminating 0), then (size_t)-1
108*0090dad1Sjhigh * is returned. Otherwise, the zero-terminated Base64 string is written
109*0090dad1Sjhigh * in the buffer, and the output length (counted WITHOUT the terminating
110*0090dad1Sjhigh * zero) is returned.
111*0090dad1Sjhigh */
to_base64(char * dst,size_t dst_len,const void * src,size_t src_len)112*0090dad1Sjhigh static size_t to_base64(char *dst, size_t dst_len, const void *src,
113*0090dad1Sjhigh size_t src_len) {
114*0090dad1Sjhigh size_t olen;
115*0090dad1Sjhigh const unsigned char *buf;
116*0090dad1Sjhigh unsigned acc, acc_len;
117*0090dad1Sjhigh
118*0090dad1Sjhigh olen = (src_len / 3) << 2;
119*0090dad1Sjhigh switch (src_len % 3) {
120*0090dad1Sjhigh case 2:
121*0090dad1Sjhigh olen++;
122*0090dad1Sjhigh /* fall through */
123*0090dad1Sjhigh case 1:
124*0090dad1Sjhigh olen += 2;
125*0090dad1Sjhigh break;
126*0090dad1Sjhigh }
127*0090dad1Sjhigh if (dst_len <= olen) {
128*0090dad1Sjhigh return (size_t)-1;
129*0090dad1Sjhigh }
130*0090dad1Sjhigh acc = 0;
131*0090dad1Sjhigh acc_len = 0;
132*0090dad1Sjhigh buf = (const unsigned char *)src;
133*0090dad1Sjhigh while (src_len-- > 0) {
134*0090dad1Sjhigh acc = (acc << 8) + (*buf++);
135*0090dad1Sjhigh acc_len += 8;
136*0090dad1Sjhigh while (acc_len >= 6) {
137*0090dad1Sjhigh acc_len -= 6;
138*0090dad1Sjhigh *dst++ = (char)b64_byte_to_char((acc >> acc_len) & 0x3F);
139*0090dad1Sjhigh }
140*0090dad1Sjhigh }
141*0090dad1Sjhigh if (acc_len > 0) {
142*0090dad1Sjhigh *dst++ = (char)b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);
143*0090dad1Sjhigh }
144*0090dad1Sjhigh *dst++ = 0;
145*0090dad1Sjhigh return olen;
146*0090dad1Sjhigh }
147*0090dad1Sjhigh
148*0090dad1Sjhigh /*
149*0090dad1Sjhigh * Decode Base64 chars into bytes. The '*dst_len' value must initially
150*0090dad1Sjhigh * contain the length of the output buffer '*dst'; when the decoding
151*0090dad1Sjhigh * ends, the actual number of decoded bytes is written back in
152*0090dad1Sjhigh * '*dst_len'.
153*0090dad1Sjhigh *
154*0090dad1Sjhigh * Decoding stops when a non-Base64 character is encountered, or when
155*0090dad1Sjhigh * the output buffer capacity is exceeded. If an error occurred (output
156*0090dad1Sjhigh * buffer is too small, invalid last characters leading to unprocessed
157*0090dad1Sjhigh * buffered bits), then NULL is returned; otherwise, the returned value
158*0090dad1Sjhigh * points to the first non-Base64 character in the source stream, which
159*0090dad1Sjhigh * may be the terminating zero.
160*0090dad1Sjhigh */
from_base64(void * dst,size_t * dst_len,const char * src)161*0090dad1Sjhigh static const char *from_base64(void *dst, size_t *dst_len, const char *src) {
162*0090dad1Sjhigh size_t len;
163*0090dad1Sjhigh unsigned char *buf;
164*0090dad1Sjhigh unsigned acc, acc_len;
165*0090dad1Sjhigh
166*0090dad1Sjhigh buf = (unsigned char *)dst;
167*0090dad1Sjhigh len = 0;
168*0090dad1Sjhigh acc = 0;
169*0090dad1Sjhigh acc_len = 0;
170*0090dad1Sjhigh for (;;) {
171*0090dad1Sjhigh unsigned d;
172*0090dad1Sjhigh
173*0090dad1Sjhigh d = b64_char_to_byte(*src);
174*0090dad1Sjhigh if (d == 0xFF) {
175*0090dad1Sjhigh break;
176*0090dad1Sjhigh }
177*0090dad1Sjhigh src++;
178*0090dad1Sjhigh acc = (acc << 6) + d;
179*0090dad1Sjhigh acc_len += 6;
180*0090dad1Sjhigh if (acc_len >= 8) {
181*0090dad1Sjhigh acc_len -= 8;
182*0090dad1Sjhigh if ((len++) >= *dst_len) {
183*0090dad1Sjhigh return NULL;
184*0090dad1Sjhigh }
185*0090dad1Sjhigh *buf++ = (acc >> acc_len) & 0xFF;
186*0090dad1Sjhigh }
187*0090dad1Sjhigh }
188*0090dad1Sjhigh
189*0090dad1Sjhigh /*
190*0090dad1Sjhigh * If the input length is equal to 1 modulo 4 (which is
191*0090dad1Sjhigh * invalid), then there will remain 6 unprocessed bits;
192*0090dad1Sjhigh * otherwise, only 0, 2 or 4 bits are buffered. The buffered
193*0090dad1Sjhigh * bits must also all be zero.
194*0090dad1Sjhigh */
195*0090dad1Sjhigh if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) {
196*0090dad1Sjhigh return NULL;
197*0090dad1Sjhigh }
198*0090dad1Sjhigh *dst_len = len;
199*0090dad1Sjhigh return src;
200*0090dad1Sjhigh }
201*0090dad1Sjhigh
202*0090dad1Sjhigh /*
203*0090dad1Sjhigh * Decode decimal integer from 'str'; the value is written in '*v'.
204*0090dad1Sjhigh * Returned value is a pointer to the next non-decimal character in the
205*0090dad1Sjhigh * string. If there is no digit at all, or the value encoding is not
206*0090dad1Sjhigh * minimal (extra leading zeros), or the value does not fit in an
207*0090dad1Sjhigh * 'unsigned long', then NULL is returned.
208*0090dad1Sjhigh */
decode_decimal(const char * str,unsigned long * v)209*0090dad1Sjhigh static const char *decode_decimal(const char *str, unsigned long *v) {
210*0090dad1Sjhigh const char *orig;
211*0090dad1Sjhigh unsigned long acc;
212*0090dad1Sjhigh
213*0090dad1Sjhigh acc = 0;
214*0090dad1Sjhigh for (orig = str;; str++) {
215*0090dad1Sjhigh int c;
216*0090dad1Sjhigh
217*0090dad1Sjhigh c = *str;
218*0090dad1Sjhigh if (c < '0' || c > '9') {
219*0090dad1Sjhigh break;
220*0090dad1Sjhigh }
221*0090dad1Sjhigh c -= '0';
222*0090dad1Sjhigh if (acc > (ULONG_MAX / 10)) {
223*0090dad1Sjhigh return NULL;
224*0090dad1Sjhigh }
225*0090dad1Sjhigh acc *= 10;
226*0090dad1Sjhigh if ((unsigned long)c > (ULONG_MAX - acc)) {
227*0090dad1Sjhigh return NULL;
228*0090dad1Sjhigh }
229*0090dad1Sjhigh acc += (unsigned long)c;
230*0090dad1Sjhigh }
231*0090dad1Sjhigh if (str == orig || (*orig == '0' && str != (orig + 1))) {
232*0090dad1Sjhigh return NULL;
233*0090dad1Sjhigh }
234*0090dad1Sjhigh *v = acc;
235*0090dad1Sjhigh return str;
236*0090dad1Sjhigh }
237*0090dad1Sjhigh
238*0090dad1Sjhigh /* ==================================================================== */
239*0090dad1Sjhigh /*
240*0090dad1Sjhigh * Code specific to Argon2.
241*0090dad1Sjhigh *
242*0090dad1Sjhigh * The code below applies the following format:
243*0090dad1Sjhigh *
244*0090dad1Sjhigh * $argon2<T>[$v=<num>]$m=<num>,t=<num>,p=<num>$<bin>$<bin>
245*0090dad1Sjhigh *
246*0090dad1Sjhigh * where <T> is either 'd', 'id', or 'i', <num> is a decimal integer (positive,
247*0090dad1Sjhigh * fits in an 'unsigned long'), and <bin> is Base64-encoded data (no '=' padding
248*0090dad1Sjhigh * characters, no newline or whitespace).
249*0090dad1Sjhigh *
250*0090dad1Sjhigh * The last two binary chunks (encoded in Base64) are, in that order,
251*0090dad1Sjhigh * the salt and the output. Both are required. The binary salt length and the
252*0090dad1Sjhigh * output length must be in the allowed ranges defined in argon2.h.
253*0090dad1Sjhigh *
254*0090dad1Sjhigh * The ctx struct must contain buffers large enough to hold the salt and pwd
255*0090dad1Sjhigh * when it is fed into decode_string.
256*0090dad1Sjhigh */
257*0090dad1Sjhigh
decode_string(argon2_context * ctx,const char * str,argon2_type type)258*0090dad1Sjhigh int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
259*0090dad1Sjhigh
260*0090dad1Sjhigh /* check for prefix */
261*0090dad1Sjhigh #define CC(prefix) \
262*0090dad1Sjhigh do { \
263*0090dad1Sjhigh size_t cc_len = strlen(prefix); \
264*0090dad1Sjhigh if (strncmp(str, prefix, cc_len) != 0) { \
265*0090dad1Sjhigh return ARGON2_DECODING_FAIL; \
266*0090dad1Sjhigh } \
267*0090dad1Sjhigh str += cc_len; \
268*0090dad1Sjhigh } while ((void)0, 0)
269*0090dad1Sjhigh
270*0090dad1Sjhigh /* optional prefix checking with supplied code */
271*0090dad1Sjhigh #define CC_opt(prefix, code) \
272*0090dad1Sjhigh do { \
273*0090dad1Sjhigh size_t cc_len = strlen(prefix); \
274*0090dad1Sjhigh if (strncmp(str, prefix, cc_len) == 0) { \
275*0090dad1Sjhigh str += cc_len; \
276*0090dad1Sjhigh { code; } \
277*0090dad1Sjhigh } \
278*0090dad1Sjhigh } while ((void)0, 0)
279*0090dad1Sjhigh
280*0090dad1Sjhigh /* Decoding prefix into decimal */
281*0090dad1Sjhigh #define DECIMAL(x) \
282*0090dad1Sjhigh do { \
283*0090dad1Sjhigh unsigned long dec_x; \
284*0090dad1Sjhigh str = decode_decimal(str, &dec_x); \
285*0090dad1Sjhigh if (str == NULL) { \
286*0090dad1Sjhigh return ARGON2_DECODING_FAIL; \
287*0090dad1Sjhigh } \
288*0090dad1Sjhigh (x) = dec_x; \
289*0090dad1Sjhigh } while ((void)0, 0)
290*0090dad1Sjhigh
291*0090dad1Sjhigh
292*0090dad1Sjhigh /* Decoding prefix into uint32_t decimal */
293*0090dad1Sjhigh #define DECIMAL_U32(x) \
294*0090dad1Sjhigh do { \
295*0090dad1Sjhigh unsigned long dec_x; \
296*0090dad1Sjhigh str = decode_decimal(str, &dec_x); \
297*0090dad1Sjhigh if (str == NULL || dec_x > UINT32_MAX) { \
298*0090dad1Sjhigh return ARGON2_DECODING_FAIL; \
299*0090dad1Sjhigh } \
300*0090dad1Sjhigh (x) = (uint32_t)dec_x; \
301*0090dad1Sjhigh } while ((void)0, 0)
302*0090dad1Sjhigh
303*0090dad1Sjhigh
304*0090dad1Sjhigh /* Decoding base64 into a binary buffer */
305*0090dad1Sjhigh #define BIN(buf, max_len, len) \
306*0090dad1Sjhigh do { \
307*0090dad1Sjhigh size_t bin_len = (max_len); \
308*0090dad1Sjhigh str = from_base64(buf, &bin_len, str); \
309*0090dad1Sjhigh if (str == NULL || bin_len > UINT32_MAX) { \
310*0090dad1Sjhigh return ARGON2_DECODING_FAIL; \
311*0090dad1Sjhigh } \
312*0090dad1Sjhigh (len) = (uint32_t)bin_len; \
313*0090dad1Sjhigh } while ((void)0, 0)
314*0090dad1Sjhigh
315*0090dad1Sjhigh size_t maxsaltlen = ctx->saltlen;
316*0090dad1Sjhigh size_t maxoutlen = ctx->outlen;
317*0090dad1Sjhigh int validation_result;
318*0090dad1Sjhigh const char* type_string;
319*0090dad1Sjhigh
320*0090dad1Sjhigh /* We should start with the argon2_type we are using */
321*0090dad1Sjhigh type_string = argon2_type2string(type, 0);
322*0090dad1Sjhigh if (!type_string) {
323*0090dad1Sjhigh return ARGON2_INCORRECT_TYPE;
324*0090dad1Sjhigh }
325*0090dad1Sjhigh
326*0090dad1Sjhigh CC("$");
327*0090dad1Sjhigh CC(type_string);
328*0090dad1Sjhigh
329*0090dad1Sjhigh /* Reading the version number if the default is suppressed */
330*0090dad1Sjhigh ctx->version = ARGON2_VERSION_10;
331*0090dad1Sjhigh CC_opt("$v=", DECIMAL_U32(ctx->version));
332*0090dad1Sjhigh
333*0090dad1Sjhigh CC("$m=");
334*0090dad1Sjhigh DECIMAL_U32(ctx->m_cost);
335*0090dad1Sjhigh CC(",t=");
336*0090dad1Sjhigh DECIMAL_U32(ctx->t_cost);
337*0090dad1Sjhigh CC(",p=");
338*0090dad1Sjhigh DECIMAL_U32(ctx->lanes);
339*0090dad1Sjhigh ctx->threads = ctx->lanes;
340*0090dad1Sjhigh
341*0090dad1Sjhigh CC("$");
342*0090dad1Sjhigh BIN(ctx->salt, maxsaltlen, ctx->saltlen);
343*0090dad1Sjhigh CC("$");
344*0090dad1Sjhigh BIN(ctx->out, maxoutlen, ctx->outlen);
345*0090dad1Sjhigh
346*0090dad1Sjhigh /* The rest of the fields get the default values */
347*0090dad1Sjhigh ctx->secret = NULL;
348*0090dad1Sjhigh ctx->secretlen = 0;
349*0090dad1Sjhigh ctx->ad = NULL;
350*0090dad1Sjhigh ctx->adlen = 0;
351*0090dad1Sjhigh ctx->allocate_cbk = NULL;
352*0090dad1Sjhigh ctx->free_cbk = NULL;
353*0090dad1Sjhigh ctx->flags = ARGON2_DEFAULT_FLAGS;
354*0090dad1Sjhigh
355*0090dad1Sjhigh /* On return, must have valid context */
356*0090dad1Sjhigh validation_result = validate_inputs(ctx);
357*0090dad1Sjhigh if (validation_result != ARGON2_OK) {
358*0090dad1Sjhigh return validation_result;
359*0090dad1Sjhigh }
360*0090dad1Sjhigh
361*0090dad1Sjhigh /* Can't have any additional characters */
362*0090dad1Sjhigh if (*str == 0) {
363*0090dad1Sjhigh return ARGON2_OK;
364*0090dad1Sjhigh } else {
365*0090dad1Sjhigh return ARGON2_DECODING_FAIL;
366*0090dad1Sjhigh }
367*0090dad1Sjhigh #undef CC
368*0090dad1Sjhigh #undef CC_opt
369*0090dad1Sjhigh #undef DECIMAL
370*0090dad1Sjhigh #undef BIN
371*0090dad1Sjhigh }
372*0090dad1Sjhigh
encode_string(char * dst,size_t dst_len,argon2_context * ctx,argon2_type type)373*0090dad1Sjhigh int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
374*0090dad1Sjhigh argon2_type type) {
375*0090dad1Sjhigh #define SS(str) \
376*0090dad1Sjhigh do { \
377*0090dad1Sjhigh size_t pp_len = strlen(str); \
378*0090dad1Sjhigh if (pp_len >= dst_len) { \
379*0090dad1Sjhigh return ARGON2_ENCODING_FAIL; \
380*0090dad1Sjhigh } \
381*0090dad1Sjhigh memcpy(dst, str, pp_len + 1); \
382*0090dad1Sjhigh dst += pp_len; \
383*0090dad1Sjhigh dst_len -= pp_len; \
384*0090dad1Sjhigh } while ((void)0, 0)
385*0090dad1Sjhigh
386*0090dad1Sjhigh #define SX(x) \
387*0090dad1Sjhigh do { \
388*0090dad1Sjhigh char tmp[30]; \
389*0090dad1Sjhigh sprintf(tmp, "%lu", (unsigned long)(x)); \
390*0090dad1Sjhigh SS(tmp); \
391*0090dad1Sjhigh } while ((void)0, 0)
392*0090dad1Sjhigh
393*0090dad1Sjhigh #define SB(buf, len) \
394*0090dad1Sjhigh do { \
395*0090dad1Sjhigh size_t sb_len = to_base64(dst, dst_len, buf, len); \
396*0090dad1Sjhigh if (sb_len == (size_t)-1) { \
397*0090dad1Sjhigh return ARGON2_ENCODING_FAIL; \
398*0090dad1Sjhigh } \
399*0090dad1Sjhigh dst += sb_len; \
400*0090dad1Sjhigh dst_len -= sb_len; \
401*0090dad1Sjhigh } while ((void)0, 0)
402*0090dad1Sjhigh
403*0090dad1Sjhigh const char* type_string = argon2_type2string(type, 0);
404*0090dad1Sjhigh int validation_result = validate_inputs(ctx);
405*0090dad1Sjhigh
406*0090dad1Sjhigh if (!type_string) {
407*0090dad1Sjhigh return ARGON2_ENCODING_FAIL;
408*0090dad1Sjhigh }
409*0090dad1Sjhigh
410*0090dad1Sjhigh if (validation_result != ARGON2_OK) {
411*0090dad1Sjhigh return validation_result;
412*0090dad1Sjhigh }
413*0090dad1Sjhigh
414*0090dad1Sjhigh
415*0090dad1Sjhigh SS("$");
416*0090dad1Sjhigh SS(type_string);
417*0090dad1Sjhigh
418*0090dad1Sjhigh SS("$v=");
419*0090dad1Sjhigh SX(ctx->version);
420*0090dad1Sjhigh
421*0090dad1Sjhigh SS("$m=");
422*0090dad1Sjhigh SX(ctx->m_cost);
423*0090dad1Sjhigh SS(",t=");
424*0090dad1Sjhigh SX(ctx->t_cost);
425*0090dad1Sjhigh SS(",p=");
426*0090dad1Sjhigh SX(ctx->lanes);
427*0090dad1Sjhigh
428*0090dad1Sjhigh SS("$");
429*0090dad1Sjhigh SB(ctx->salt, ctx->saltlen);
430*0090dad1Sjhigh
431*0090dad1Sjhigh SS("$");
432*0090dad1Sjhigh SB(ctx->out, ctx->outlen);
433*0090dad1Sjhigh return ARGON2_OK;
434*0090dad1Sjhigh
435*0090dad1Sjhigh #undef SS
436*0090dad1Sjhigh #undef SX
437*0090dad1Sjhigh #undef SB
438*0090dad1Sjhigh }
439*0090dad1Sjhigh
b64len(uint32_t len)440*0090dad1Sjhigh size_t b64len(uint32_t len) {
441*0090dad1Sjhigh size_t olen = ((size_t)len / 3) << 2;
442*0090dad1Sjhigh
443*0090dad1Sjhigh switch (len % 3) {
444*0090dad1Sjhigh case 2:
445*0090dad1Sjhigh olen++;
446*0090dad1Sjhigh /* fall through */
447*0090dad1Sjhigh case 1:
448*0090dad1Sjhigh olen += 2;
449*0090dad1Sjhigh break;
450*0090dad1Sjhigh }
451*0090dad1Sjhigh
452*0090dad1Sjhigh return olen;
453*0090dad1Sjhigh }
454*0090dad1Sjhigh
numlen(uint32_t num)455*0090dad1Sjhigh size_t numlen(uint32_t num) {
456*0090dad1Sjhigh size_t len = 1;
457*0090dad1Sjhigh while (num >= 10) {
458*0090dad1Sjhigh ++len;
459*0090dad1Sjhigh num = num / 10;
460*0090dad1Sjhigh }
461*0090dad1Sjhigh return len;
462*0090dad1Sjhigh }
463*0090dad1Sjhigh
464