Coverage Report

Created: 2025-07-07 10:01

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