argon2 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -73,8 +73,7 @@ extern "C" {
73
73
  #define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0)
74
74
  #define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)
75
75
  #define ARGON2_FLAG_CLEAR_MEMORY (UINT32_C(1) << 2)
76
- #define ARGON2_DEFAULT_FLAGS \
77
- (ARGON2_FLAG_CLEAR_PASSWORD | ARGON2_FLAG_CLEAR_MEMORY)
76
+ #define ARGON2_DEFAULT_FLAGS (ARGON2_FLAG_CLEAR_MEMORY)
78
77
 
79
78
  /* Error codes */
80
79
  typedef enum Argon2_ErrorCodes {
@@ -126,6 +125,10 @@ typedef enum Argon2_ErrorCodes {
126
125
 
127
126
  ARGON2_MISSING_ARGS = 30,
128
127
 
128
+ ARGON2_ENCODING_FAIL = 31,
129
+
130
+ ARGON2_DECODING_FAIL = 32,
131
+
129
132
  ARGON2_ERROR_CODES_LENGTH /* Do NOT remove; Do NOT add error codes after
130
133
  this
131
134
  error code */
@@ -188,27 +191,80 @@ typedef struct Argon2_Context {
188
191
  uint32_t flags; /* array of bool options */
189
192
  } argon2_context;
190
193
 
194
+ /* Argon2 primitive type */
195
+ typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type;
196
+
197
+ /**
198
+ * Hashes a password with Argon2i, producing an encoded hash
199
+ * @param t_cost Number of iterations
200
+ * @param m_cost Sets memory usage to 2^m_cost kibibytes
201
+ * @param parallelism Number of threads and compute lanes
202
+ * @param pwd Pointer to password
203
+ * @param pwdlen Password size in bytes
204
+ * @param salt Pointer to salt
205
+ * @param saltlen Salt size in bytes
206
+ * @param hashlen Desired length of the hash in bytes
207
+ * @param encoded Buffer where to write the encoded hash
208
+ * @param encodedlen Size of the buffer (thus max size of the encoded hash)
209
+ * @pre Different parallelism levels will give different results
210
+ * @pre Returns ARGON2_OK if successful
211
+ */
212
+ int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
213
+ const uint32_t parallelism, const void *pwd,
214
+ const size_t pwdlen, const void *salt,
215
+ const size_t saltlen, const size_t hashlen,
216
+ char *encoded, const size_t encodedlen);
217
+
218
+ /**
219
+ * Hashes a password with Argon2i, producing a raw hash
220
+ * @param t_cost Number of iterations
221
+ * @param m_cost Sets memory usage to 2^m_cost kibibytes
222
+ * @param parallelism Number of threads and compute lanes
223
+ * @param pwd Pointer to password
224
+ * @param pwdlen Password size in bytes
225
+ * @param salt Pointer to salt
226
+ * @param saltlen Salt size in bytes
227
+ * @param hash Buffer where to write the raw hash
228
+ * @param hashlen Desired length of the hash in bytes
229
+ * @pre Different parallelism levels will give different results
230
+ * @pre Returns ARGON2_OK if successful
231
+ */
232
+ int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
233
+ const uint32_t parallelism, const void *pwd,
234
+ const size_t pwdlen, const void *salt,
235
+ const size_t saltlen, void *hash, const size_t hashlen);
236
+
237
+ int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
238
+ const uint32_t parallelism, const void *pwd,
239
+ const size_t pwdlen, const void *salt,
240
+ const size_t saltlen, const size_t hashlen,
241
+ char *encoded, const size_t encodedlen);
242
+
243
+ int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
244
+ const uint32_t parallelism, const void *pwd,
245
+ const size_t pwdlen, const void *salt,
246
+ const size_t saltlen, void *hash, const size_t hashlen);
247
+
248
+ /* generic function underlying the above ones */
249
+ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
250
+ const uint32_t parallelism, const void *pwd,
251
+ const size_t pwdlen, const void *salt, const size_t saltlen,
252
+ void *hash, const size_t hashlen, char *encoded,
253
+ const size_t encodedlen, argon2_type type);
254
+
191
255
  /**
192
- * Function to hash the inputs in the memory-hard fashion (uses Argon2i)
193
- * @param out Pointer to the memory where the hash digest will be written
194
- * @param outlen Digest length in bytes
195
- * @param in Pointer to the input (password)
196
- * @param inlen Input length in bytes
197
- * @param salt Pointer to the salt
198
- * @param saltlen Salt length in bytes
199
- * @pre @a out must have at least @a outlen bytes allocated
200
- * @pre @a in must be at least @inlen bytes long
201
- * @pre @a saltlen must be at least @saltlen bytes long
202
- * @return Zero if successful, 1 otherwise.
256
+ * Verifies a password against an encoded string
257
+ * @param encoded String encoding parameters, salt, hash
258
+ * @param pwd Pointer to password
259
+ * @pre Returns ARGON2_OK if successful
203
260
  */
204
- int hash_argon2i(void *out, size_t outlen, const void *in, size_t inlen,
205
- const void *salt, size_t saltlen, unsigned int t_cost,
206
- unsigned int m_cost);
261
+ int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen);
207
262
 
208
- /* same for argon2d */
209
- int hash_argon2d(void *out, size_t outlen, const void *in, size_t inlen,
210
- const void *salt, size_t saltlen, unsigned int t_cost,
211
- unsigned int m_cost);
263
+ int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen);
264
+
265
+ /* generic function underlying the above ones */
266
+ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
267
+ argon2_type type);
212
268
 
213
269
  /*
214
270
  * **************Argon2d: Version of Argon2 that picks memory blocks depending
@@ -269,28 +325,6 @@ int verify_d(argon2_context *context, const char *hash);
269
325
  */
270
326
  const char *error_message(int error_code);
271
327
 
272
- /* ==================================================================== */
273
- /*
274
- * Code specific to Argon2i.
275
- *
276
- * The code below applies the following format:
277
- *
278
- * $argon2i$m=<num>,t=<num>,p=<num>[,keyid=<bin>][,data=<bin>][$<bin>[$<bin>]]
279
- *
280
- * where <num> is a decimal integer (positive, fits in an 'unsigned long')
281
- * and <bin> is Base64-encoded data (no '=' padding characters, no newline
282
- * or whitespace). The "keyid" is a binary identifier for a key (up to 8
283
- * bytes); "data" is associated data (up to 32 bytes). When the 'keyid'
284
- * (resp. the 'data') is empty, then it is ommitted from the output.
285
- *
286
- * The last two binary chunks (encoded in Base64) are, in that order,
287
- * the salt and the output. Both are optional, but you cannot have an
288
- * output without a salt. The binary salt length is between 8 and 48 bytes.
289
- * The output length is always exactly 32 bytes.
290
- */
291
-
292
- int encode_string(char *dst, size_t dst_len, argon2_context *ctx);
293
-
294
328
  #if defined(__cplusplus)
295
329
  }
296
330
  #endif
@@ -26,7 +26,6 @@
26
26
  #include <stdlib.h>
27
27
  #include <string.h>
28
28
 
29
- #include "argon2.h"
30
29
  #include "core.h"
31
30
  #include "thread.h"
32
31
  #include "blake2/blake2.h"
@@ -14,6 +14,8 @@
14
14
  #ifndef ARGON2_CORE_H
15
15
  #define ARGON2_CORE_H
16
16
 
17
+ #include "argon2.h"
18
+
17
19
  #if defined(_MSC_VER)
18
20
  #define ALIGN(n) __declspec(align(16))
19
21
  #elif defined(__GNUC__) || defined(__clang)
@@ -44,9 +46,6 @@ enum argon2_core_constants {
44
46
  ARGON2_PREHASH_SEED_LENGTH = 72
45
47
  };
46
48
 
47
- /* Argon2 primitive type */
48
- typedef enum Argon2_type { Argon2_d = 0, Argon2_i = 1 } argon2_type;
49
-
50
49
  /*************************Argon2 internal data
51
50
  * types**************************************************/
52
51
 
@@ -0,0 +1,435 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <limits.h>
5
+ #include "encoding.h"
6
+
7
+ #/*
8
+ * Example code for a decoder and encoder of "hash strings", with Argon2i
9
+ * parameters.
10
+ *
11
+ * This code comprises three sections:
12
+ *
13
+ * -- The first section contains generic Base64 encoding and decoding
14
+ * functions. It is conceptually applicable to any hash function
15
+ * implementation that uses Base64 to encode and decode parameters,
16
+ * salts and outputs. It could be made into a library, provided that
17
+ * the relevant functions are made public (non-static) and be given
18
+ * reasonable names to avoid collisions with other functions.
19
+ *
20
+ * -- The second section is specific to Argon2i. It encodes and decodes
21
+ * the parameters, salts and outputs. It does not compute the hash
22
+ * itself.
23
+ *
24
+ * -- The third section is test code, with a main() function. With
25
+ * this section, the whole file compiles as a stand-alone program
26
+ * that exercises the encoding and decoding functions with some
27
+ * test vectors.
28
+ *
29
+ * The code was originally written by Thomas Pornin <pornin@bolet.org>,
30
+ * to whom comments and remarks may be sent. It is released under what
31
+ * should amount to Public Domain or its closest equivalent; the
32
+ * following mantra is supposed to incarnate that fact with all the
33
+ * proper legal rituals:
34
+ *
35
+ * ---------------------------------------------------------------------
36
+ * This file is provided under the terms of Creative Commons CC0 1.0
37
+ * Public Domain Dedication. To the extent possible under law, the
38
+ * author (Thomas Pornin) has waived all copyright and related or
39
+ * neighboring rights to this file. This work is published from: Canada.
40
+ * ---------------------------------------------------------------------
41
+ *
42
+ * Copyright (c) 2015 Thomas Pornin
43
+ */
44
+
45
+ /* ==================================================================== */
46
+ /*
47
+ * Common code; could be shared between different hash functions.
48
+ *
49
+ * Note: the Base64 functions below assume that uppercase letters (resp.
50
+ * lowercase letters) have consecutive numerical codes, that fit on 8
51
+ * bits. All modern systems use ASCII-compatible charsets, where these
52
+ * properties are true. If you are stuck with a dinosaur of a system
53
+ * that still defaults to EBCDIC then you already have much bigger
54
+ * interoperability issues to deal with.
55
+ */
56
+
57
+ /*
58
+ * Some macros for constant-time comparisons. These work over values in
59
+ * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
60
+ */
61
+ #define EQ(x, y) ((((-((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)
62
+ #define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)
63
+ #define GE(x, y) (GT(y, x) ^ 0xFF)
64
+ #define LT(x, y) GT(y, x)
65
+ #define LE(x, y) GE(y, x)
66
+
67
+ /*
68
+ * Convert value x (0..63) to corresponding Base64 character.
69
+ */
70
+ static int b64_byte_to_char(unsigned x) {
71
+ return (LT(x, 26) & (x + 'A')) |
72
+ (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
73
+ (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
74
+ (EQ(x, 63) & '/');
75
+ }
76
+
77
+ /*
78
+ * Convert character c to the corresponding 6-bit value. If character c
79
+ * is not a Base64 character, then 0xFF (255) is returned.
80
+ */
81
+ static unsigned b64_char_to_byte(int c) {
82
+ unsigned x;
83
+
84
+ x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
85
+ (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
86
+ (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |
87
+ (EQ(c, '/') & 63);
88
+ return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
89
+ }
90
+
91
+ /*
92
+ * Convert some bytes to Base64. 'dst_len' is the length (in characters)
93
+ * of the output buffer 'dst'; if that buffer is not large enough to
94
+ * receive the result (including the terminating 0), then (size_t)-1
95
+ * is returned. Otherwise, the zero-terminated Base64 string is written
96
+ * in the buffer, and the output length (counted WITHOUT the terminating
97
+ * zero) is returned.
98
+ */
99
+ static size_t to_base64(char *dst, size_t dst_len, const void *src,
100
+ size_t src_len) {
101
+ size_t olen;
102
+ const unsigned char *buf;
103
+ unsigned acc, acc_len;
104
+
105
+ olen = (src_len / 3) << 2;
106
+ switch (src_len % 3) {
107
+ case 2:
108
+ olen++;
109
+ /* fall through */
110
+ case 1:
111
+ olen += 2;
112
+ break;
113
+ }
114
+ if (dst_len <= olen) {
115
+ return (size_t)-1;
116
+ }
117
+ acc = 0;
118
+ acc_len = 0;
119
+ buf = (const unsigned char *)src;
120
+ while (src_len-- > 0) {
121
+ acc = (acc << 8) + (*buf++);
122
+ acc_len += 8;
123
+ while (acc_len >= 6) {
124
+ acc_len -= 6;
125
+ *dst++ = b64_byte_to_char((acc >> acc_len) & 0x3F);
126
+ }
127
+ }
128
+ if (acc_len > 0) {
129
+ *dst++ = b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);
130
+ }
131
+ *dst++ = 0;
132
+ return olen;
133
+ }
134
+
135
+ /*
136
+ * Decode Base64 chars into bytes. The '*dst_len' value must initially
137
+ * contain the length of the output buffer '*dst'; when the decoding
138
+ * ends, the actual number of decoded bytes is written back in
139
+ * '*dst_len'.
140
+ *
141
+ * Decoding stops when a non-Base64 character is encountered, or when
142
+ * the output buffer capacity is exceeded. If an error occurred (output
143
+ * buffer is too small, invalid last characters leading to unprocessed
144
+ * buffered bits), then NULL is returned; otherwise, the returned value
145
+ * points to the first non-Base64 character in the source stream, which
146
+ * may be the terminating zero.
147
+ */
148
+ static const char *from_base64(void *dst, size_t *dst_len, const char *src) {
149
+ size_t len;
150
+ unsigned char *buf;
151
+ unsigned acc, acc_len;
152
+
153
+ buf = (unsigned char *)dst;
154
+ len = 0;
155
+ acc = 0;
156
+ acc_len = 0;
157
+ for (;;) {
158
+ unsigned d;
159
+
160
+ d = b64_char_to_byte(*src);
161
+ if (d == 0xFF) {
162
+ break;
163
+ }
164
+ src++;
165
+ acc = (acc << 6) + d;
166
+ acc_len += 6;
167
+ if (acc_len >= 8) {
168
+ acc_len -= 8;
169
+ if ((len++) >= *dst_len) {
170
+ return NULL;
171
+ }
172
+ *buf++ = (acc >> acc_len) & 0xFF;
173
+ }
174
+ }
175
+
176
+ /*
177
+ * If the input length is equal to 1 modulo 4 (which is
178
+ * invalid), then there will remain 6 unprocessed bits;
179
+ * otherwise, only 0, 2 or 4 bits are buffered. The buffered
180
+ * bits must also all be zero.
181
+ */
182
+ if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) {
183
+ return NULL;
184
+ }
185
+ *dst_len = len;
186
+ return src;
187
+ }
188
+
189
+ /*
190
+ * Decode decimal integer from 'str'; the value is written in '*v'.
191
+ * Returned value is a pointer to the next non-decimal character in the
192
+ * string. If there is no digit at all, or the value encoding is not
193
+ * minimal (extra leading zeros), or the value does not fit in an
194
+ * 'unsigned long', then NULL is returned.
195
+ */
196
+ static const char *decode_decimal(const char *str, unsigned long *v) {
197
+ const char *orig;
198
+ unsigned long acc;
199
+
200
+ orig = str;
201
+ acc = 0;
202
+ for (orig = str;; str++) {
203
+ int c;
204
+
205
+ c = *str;
206
+ if (c < '0' || c > '9') {
207
+ break;
208
+ }
209
+ c -= '0';
210
+ if (acc > (ULONG_MAX / 10)) {
211
+ return NULL;
212
+ }
213
+ acc *= 10;
214
+ if ((unsigned long)c > (ULONG_MAX - acc)) {
215
+ return NULL;
216
+ }
217
+ acc += (unsigned long)c;
218
+ }
219
+ if (str == orig || (*orig == '0' && str != (orig + 1))) {
220
+ return NULL;
221
+ }
222
+ *v = acc;
223
+ return str;
224
+ }
225
+
226
+ /* ==================================================================== */
227
+ /*
228
+ * Code specific to Argon2i.
229
+ *
230
+ * The code below applies the following format:
231
+ *
232
+ * $argon2i$m=<num>,t=<num>,p=<num>[,keyid=<bin>][,data=<bin>][$<bin>[$<bin>]]
233
+ *
234
+ * where <num> is a decimal integer (positive, fits in an 'unsigned long')
235
+ * and <bin> is Base64-encoded data (no '=' padding characters, no newline
236
+ * or whitespace). The "keyid" is a binary identifier for a key (up to 8
237
+ * bytes); "data" is associated data (up to 32 bytes). When the 'keyid'
238
+ * (resp. the 'data') is empty, then it is ommitted from the output.
239
+ *
240
+ * The last two binary chunks (encoded in Base64) are, in that order,
241
+ * the salt and the output. Both are optional, but you cannot have an
242
+ * output without a salt. The binary salt length is between 8 and 48 bytes.
243
+ * The output length is always exactly 32 bytes.
244
+ */
245
+
246
+ /*
247
+ * Decode an Argon2i hash string into the provided structure 'ctx'.
248
+ * Returned value is 1 on success, 0 on error.
249
+ */
250
+ int decode_string(argon2_context *ctx, const char *str, argon2_type type) {
251
+ #define CC(prefix) \
252
+ do { \
253
+ size_t cc_len = strlen(prefix); \
254
+ if (strncmp(str, prefix, cc_len) != 0) { \
255
+ return 0; \
256
+ } \
257
+ str += cc_len; \
258
+ } while (0)
259
+
260
+ #define CC_opt(prefix, code) \
261
+ do { \
262
+ size_t cc_len = strlen(prefix); \
263
+ if (strncmp(str, prefix, cc_len) == 0) { \
264
+ str += cc_len; \
265
+ { code; } \
266
+ } \
267
+ } while (0)
268
+
269
+ #define DECIMAL(x) \
270
+ do { \
271
+ unsigned long dec_x; \
272
+ str = decode_decimal(str, &dec_x); \
273
+ if (str == NULL) { \
274
+ return 0; \
275
+ } \
276
+ (x) = dec_x; \
277
+ } while (0)
278
+
279
+ #define BIN(buf, max_len, len) \
280
+ do { \
281
+ size_t bin_len = (max_len); \
282
+ str = from_base64(buf, &bin_len, str); \
283
+ if (str == NULL) { \
284
+ return 0; \
285
+ } \
286
+ (len) = bin_len; \
287
+ } while (0)
288
+
289
+ size_t maxadlen = ctx->adlen;
290
+ size_t maxsaltlen = ctx->saltlen;
291
+ size_t maxoutlen = ctx->outlen;
292
+
293
+ ctx->adlen = 0;
294
+ ctx->saltlen = 0;
295
+ ctx->outlen = 0;
296
+ if (type == Argon2_i)
297
+ CC("$argon2i");
298
+ else if (type == Argon2_d)
299
+ CC("$argon2d");
300
+ else
301
+ return 0;
302
+ CC("$m=");
303
+ DECIMAL(ctx->m_cost);
304
+ CC(",t=");
305
+ DECIMAL(ctx->t_cost);
306
+ CC(",p=");
307
+ DECIMAL(ctx->lanes);
308
+ ctx->threads = ctx->lanes;
309
+
310
+ /*
311
+ * Both m and t must be no more than 2^32-1. The tests below
312
+ * use a shift by 30 bits to avoid a direct comparison with
313
+ * 0xFFFFFFFF, which may trigger a spurious compiler warning
314
+ * on machines where 'unsigned long' is a 32-bit type.
315
+ */
316
+ if (ctx->m_cost < 1 || (ctx->m_cost >> 30) > 3) {
317
+ return 0;
318
+ }
319
+ if (ctx->t_cost < 1 || (ctx->t_cost >> 30) > 3) {
320
+ return 0;
321
+ }
322
+
323
+ /*
324
+ * The parallelism p must be between 1 and 255. The memory cost
325
+ * parameter, expressed in kilobytes, must be at least 8 times
326
+ * the value of p.
327
+ */
328
+ if (ctx->lanes < 1 || ctx->lanes > 255) {
329
+ return 0;
330
+ }
331
+ if (ctx->m_cost < (ctx->lanes << 3)) {
332
+ return 0;
333
+ }
334
+
335
+ CC_opt(",data=", BIN(ctx->ad, maxadlen, ctx->adlen));
336
+ if (*str == 0) {
337
+ return 1;
338
+ }
339
+ CC("$");
340
+ BIN(ctx->salt, maxsaltlen, ctx->saltlen);
341
+ if (ctx->saltlen < 8) {
342
+ return 0;
343
+ }
344
+ if (*str == 0) {
345
+ return 1;
346
+ }
347
+ CC("$");
348
+ BIN(ctx->out, maxoutlen, ctx->outlen);
349
+ if (ctx->outlen < 12) {
350
+ return 0;
351
+ }
352
+ return *str == 0;
353
+
354
+ #undef CC
355
+ #undef CC_opt
356
+ #undef DECIMAL
357
+ #undef BIN
358
+ }
359
+
360
+ /*
361
+ * encode an argon2i hash string into the provided buffer. 'dst_len'
362
+ * contains the size, in characters, of the 'dst' buffer; if 'dst_len'
363
+ * is less than the number of required characters (including the
364
+ * terminating 0), then this function returns 0.
365
+ *
366
+ * if pp->output_len is 0, then the hash string will be a salt string
367
+ * (no output). if pp->salt_len is also 0, then the string will be a
368
+ * parameter-only string (no salt and no output).
369
+ *
370
+ * on success, 1 is returned.
371
+ */
372
+ int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
373
+ argon2_type type) {
374
+ #define SS(str) \
375
+ do { \
376
+ size_t pp_len = strlen(str); \
377
+ if (pp_len >= dst_len) { \
378
+ return 0; \
379
+ } \
380
+ memcpy(dst, str, pp_len + 1); \
381
+ dst += pp_len; \
382
+ dst_len -= pp_len; \
383
+ } while (0)
384
+
385
+ #define SX(x) \
386
+ do { \
387
+ char tmp[30]; \
388
+ sprintf(tmp, "%lu", (unsigned long)(x)); \
389
+ SS(tmp); \
390
+ } while (0);
391
+
392
+ #define SB(buf, len) \
393
+ do { \
394
+ size_t sb_len = to_base64(dst, dst_len, buf, len); \
395
+ if (sb_len == (size_t)-1) { \
396
+ return 0; \
397
+ } \
398
+ dst += sb_len; \
399
+ dst_len -= sb_len; \
400
+ } while (0);
401
+
402
+ if (type == Argon2_i)
403
+ SS("$argon2i$m=");
404
+ else if (type == Argon2_d)
405
+ SS("$argon2d$m=");
406
+ else
407
+ return 0;
408
+ SX(ctx->m_cost);
409
+ SS(",t=");
410
+ SX(ctx->t_cost);
411
+ SS(",p=");
412
+ SX(ctx->lanes);
413
+
414
+ if (ctx->adlen > 0) {
415
+ SS(",data=");
416
+ SB(ctx->ad, ctx->adlen);
417
+ }
418
+
419
+ if (ctx->saltlen == 0)
420
+ return 1;
421
+
422
+ SS("$");
423
+ SB(ctx->salt, ctx->saltlen);
424
+
425
+ if (ctx->outlen == 0)
426
+ return 1;
427
+
428
+ SS("$");
429
+ SB(ctx->out, ctx->outlen);
430
+ return 1;
431
+
432
+ #undef SS
433
+ #undef SX
434
+ #undef SB
435
+ }