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.
@@ -5,3 +5,4 @@ libargon2.dylib
5
5
  .DS_Store
6
6
  src/*.o
7
7
  src/blake2/*.o
8
+ test.c
@@ -14,7 +14,7 @@ GENKAT = genkat
14
14
  DIST = phc-winner-argon2
15
15
 
16
16
  CC = gcc
17
- SRC = src/argon2.c src/core.c src/blake2/blake2b.c src/thread.c
17
+ SRC = src/argon2.c src/core.c src/blake2/blake2b.c src/thread.c src/encoding.c
18
18
  SRC_RUN = src/run.c
19
19
  SRC_BENCH = src/bench.c
20
20
  SRC_GENKAT = src/genkat.c
@@ -36,10 +36,9 @@ results.
36
36
  on your system. To show usage instructions, run
37
37
  `./argon2` without arguments as
38
38
  ```
39
- $ ./argon2
40
- Usage: ./argon2 pwd salt [-d] [-t iterations] [-m memory] [-p parallelism]
39
+ Usage: ./argon2 salt [-d] [-t iterations] [-m memory] [-p parallelism]
40
+ Password is read from stdin
41
41
  Parameters:
42
- pwd The password to hash
43
42
  salt The salt to use, at most 16 characters
44
43
  -d Use Argon2d instead of Argon2i (which is the default)
45
44
  -t N Sets the number of iterations to N (default = 3)
@@ -49,13 +48,15 @@ Parameters:
49
48
  For example, to hash "password" using "somesalt" as a salt and doing 2
50
49
  iterations, consuming 64 MiB, and using four parallel threads:
51
50
  ```
52
- $ ./argon2 password somesalt -t 2 -m 16 -p 4
51
+ $ echo -n "password" | ./argon2 somesalt -t 2 -m 16 -p 4
53
52
  Type: Argon2i
54
53
  Iterations: 2
55
54
  Memory: 65536 KiB
56
55
  Parallelism: 4
57
56
  Hash: 4162f32384d8f4790bd994cb73c83a4a29f076165ec18af3cfdcf10a8d1b9066
58
- 0.265 seconds
57
+ Encoded: $argon2i$m=65536,t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY
58
+ 0.271 seconds
59
+ Verification ok
59
60
  ```
60
61
 
61
62
  ### Library
@@ -83,48 +84,47 @@ below is named `test.c` and placed in the project's root directory.
83
84
  #include <string.h>
84
85
  #include <stdlib.h>
85
86
 
86
- #define OUTLEN 32
87
+ #define HASHLEN 32
87
88
  #define SALTLEN 16
88
89
  #define PWD "password"
89
90
 
90
91
  int main(void)
91
92
  {
92
- uint8_t out1[OUTLEN];
93
- uint8_t out2[OUTLEN];
93
+ uint8_t hash1[HASHLEN];
94
+ uint8_t hash2[HASHLEN];
94
95
 
95
96
  uint8_t salt[SALTLEN];
96
97
  memset( salt, 0x00, SALTLEN );
97
98
 
98
- uint8_t *in = (uint8_t *)strdup(PWD);
99
- uint32_t inlen = strlen((char *)in);
99
+ uint8_t *pwd = (uint8_t *)strdup(PWD);
100
+ uint32_t pwdlen = strlen((char *)pwd);
100
101
 
101
102
  uint32_t t_cost = 2; // 1-pass computation
102
103
  uint32_t m_cost = (1<<16); // 64 mebibytes memory usage
104
+ uint32_t parallelism = 1; // number of threads and lanes
103
105
 
104
106
  // high-level API
105
- hash_argon2i( out1, OUTLEN, in, inlen, salt, SALTLEN, t_cost, m_cost );
106
- free(in);
107
+ argon2i_hash_raw(t_cost, m_cost, parallelism, pwd, pwdlen, salt, SALTLEN, hash1, HASHLEN);
107
108
 
108
109
  // low-level API
109
- uint32_t lanes = 1; // lanes 1 by default
110
- uint32_t threads = 1; // threads 1 by default
111
- in = (uint8_t *)strdup(PWD); // was erased by previous call
110
+ uint32_t lanes = parallelism;
111
+ uint32_t threads = parallelism;
112
112
  argon2_context context = {
113
- out2, OUTLEN,
114
- in, inlen,
113
+ hash2, HASHLEN,
114
+ pwd, pwdlen,
115
115
  salt, SALTLEN,
116
116
  NULL, 0, /* secret data */
117
117
  NULL, 0, /* associated data */
118
- t_cost, m_cost, lanes, threads,
118
+ t_cost, m_cost, parallelism, parallelism,
119
119
  NULL, NULL, /* custom memory allocation / deallocation functions */
120
120
  ARGON2_DEFAULT_FLAGS /* by default the password is zeroed on exit */
121
121
  };
122
122
  argon2i( &context );
123
- free(in);
123
+ free(pwd);
124
124
 
125
- for( int i=0; i<OUTLEN; ++i ) printf( "%02x", out1[i] ); printf( "\n" );
126
- if (memcmp(out1, out2, OUTLEN)) {
127
- for( int i=0; i<OUTLEN; ++i ) printf( "%02x", out2[i] ); printf( "\n" );
125
+ for( int i=0; i<HASHLEN; ++i ) printf( "%02x", hash1[i] ); printf( "\n" );
126
+ if (memcmp(hash1, hash2, HASHLEN)) {
127
+ for( int i=0; i<HASHLEN; ++i ) printf( "%02x", hash2[i] ); printf( "\n" );
128
128
  printf("fail\n");
129
129
  }
130
130
  else printf("ok\n");
@@ -133,17 +133,22 @@ int main(void)
133
133
  }
134
134
  ```
135
135
 
136
- To use Argon2d instead of Argon2i call `hash_argon2d` instead of
137
- `hash_argon2i` using the high-level API, and `argon2d` instead of
136
+ To use Argon2d instead of Argon2i call `argon2d_hash` instead of
137
+ `argon2i_hash` using the high-level API, and `argon2d` instead of
138
138
  `argon2i` using the low-level API.
139
139
 
140
+ To produce the crypt-like encoding rather than the raw hash, call
141
+ `argon2i_hash_encoded` for Argon2i and `argon2d_hash_encoded` for Argon2d.
142
+
143
+ See [`src/argon2.h`](src/argon2.h) for API detais.
144
+
140
145
  *Note: in this example the salt is set to the all-`0x00` string for the
141
146
  sake of simplicity, but in your application you should use a random salt.*
142
147
 
143
148
 
144
149
  ### Benchmarks
145
150
 
146
- `make bench` creates the exectuble `bench`, which measures the execution
151
+ `make bench` creates the executable `bench`, which measures the execution
147
152
  time of various Argon2 instances:
148
153
 
149
154
  ```
@@ -182,7 +187,7 @@ repository is copyright (c) 2015 Daniel Dinu, Dmitry Khovratovich (main
182
187
  authors), Jean-Philippe Aumasson and Samuel Neves, and under
183
188
  [CC0 license](https://creativecommons.org/about/cc0).
184
189
 
185
- The string encoding routines in [`src/argon2.c`](src/argon2.c) are
190
+ The string encoding routines in [`src/encoding.c`](src/encoding.c) are
186
191
  copyright (c) 2015 Thomas Pornin, and under [CC0
187
192
  license](https://creativecommons.org/about/cc0).
188
193
 
@@ -13,10 +13,12 @@
13
13
 
14
14
  #include <stdint.h>
15
15
  #include <string.h>
16
+ #include <stdlib.h>
16
17
  #include <stdio.h>
17
18
  #include <limits.h>
18
19
 
19
20
  #include "argon2.h"
21
+ #include "encoding.h"
20
22
  #include "core.h"
21
23
 
22
24
  /* Error messages */
@@ -96,22 +98,30 @@ static const char *Argon2_ErrorMessage[] = {
96
98
  /*},
97
99
  {ARGON2_THREADS_TOO_MANY, */ "Too many threads",
98
100
  /*},
99
- {ARGON2_MISSING_ARGS, */ "Missing arguments", /*},*/
101
+ {ARGON2_MISSING_ARGS, */ "Missing arguments",
102
+ /*},
103
+ {ARGON2_ENCODING_FAIL, */ "Encoding failed",
104
+ /*},
105
+ {ARGON2_DECODING_FAIL, */ "Decoding failed", /*},*/
100
106
  };
101
107
 
102
- int hash_argon2i(void *out, size_t outlen, const void *in, size_t inlen,
103
- const void *salt, size_t saltlen, unsigned int t_cost,
104
- unsigned int m_cost) {
108
+ int argon2_hash(const uint32_t t_cost, const uint32_t m_cost,
109
+ const uint32_t parallelism, const void *pwd,
110
+ const size_t pwdlen, const void *salt, const size_t saltlen,
111
+ void *hash, const size_t hashlen, char *encoded,
112
+ const size_t encodedlen, argon2_type type) {
105
113
 
106
114
  argon2_context context;
115
+ int result;
116
+ uint8_t *out;
107
117
 
108
118
  /* Detect and reject overflowing sizes */
109
119
  /* TODO: This should probably be fixed in the function signature */
110
- if (inlen > UINT32_MAX) {
120
+ if (pwdlen > UINT32_MAX) {
111
121
  return ARGON2_PWD_TOO_LONG;
112
122
  }
113
123
 
114
- if (outlen > UINT32_MAX) {
124
+ if (hashlen > UINT32_MAX) {
115
125
  return ARGON2_OUTPUT_TOO_LONG;
116
126
  }
117
127
 
@@ -119,10 +129,12 @@ int hash_argon2i(void *out, size_t outlen, const void *in, size_t inlen,
119
129
  return ARGON2_SALT_TOO_LONG;
120
130
  }
121
131
 
132
+ out = malloc(hashlen);
133
+
122
134
  context.out = (uint8_t *)out;
123
- context.outlen = (uint32_t)outlen;
124
- context.pwd = (uint8_t *)in;
125
- context.pwdlen = (uint32_t)inlen;
135
+ context.outlen = (uint32_t)hashlen;
136
+ context.pwd = (uint8_t *)pwd;
137
+ context.pwdlen = (uint32_t)pwdlen;
126
138
  context.salt = (uint8_t *)salt;
127
139
  context.saltlen = (uint32_t)saltlen;
128
140
  context.secret = NULL;
@@ -131,53 +143,131 @@ int hash_argon2i(void *out, size_t outlen, const void *in, size_t inlen,
131
143
  context.adlen = 0;
132
144
  context.t_cost = t_cost;
133
145
  context.m_cost = m_cost;
134
- context.lanes = 1;
135
- context.threads = 1;
146
+ context.lanes = parallelism;
147
+ context.threads = parallelism;
136
148
  context.allocate_cbk = NULL;
137
149
  context.free_cbk = NULL;
138
150
  context.flags = ARGON2_DEFAULT_FLAGS;
139
151
 
140
- return argon2_core(&context, Argon2_i);
141
- }
152
+ result = argon2_core(&context, type);
142
153
 
143
- int hash_argon2d(void *out, size_t outlen, const void *in, size_t inlen,
144
- const void *salt, size_t saltlen, unsigned int t_cost,
145
- unsigned int m_cost) {
146
- argon2_context context;
154
+ if (result != ARGON2_OK) {
155
+ memset(out, 0x00, hashlen);
156
+ free(out);
157
+ return result;
158
+ }
147
159
 
148
- /* Detect and reject overflowing sizes */
149
- /* TODO: This should probably be fixed in the function signature */
150
- if (inlen > UINT32_MAX) {
151
- return ARGON2_PWD_TOO_LONG;
160
+ /* if raw hash requested, write it */
161
+ if (hash) {
162
+ memcpy(hash, out, hashlen);
152
163
  }
153
164
 
154
- if (outlen > UINT32_MAX) {
155
- return ARGON2_OUTPUT_TOO_LONG;
165
+ /* if encoding requested, write it */
166
+ if (encoded && encodedlen) {
167
+ if (!encode_string(encoded, encodedlen, &context, type)) {
168
+ memset(out, 0x00, hashlen);
169
+ memset(encoded, 0x00, encodedlen);
170
+ free(out);
171
+ return ARGON2_ENCODING_FAIL;
172
+ }
156
173
  }
157
174
 
158
- if (saltlen > UINT32_MAX) {
159
- return ARGON2_SALT_TOO_LONG;
175
+ free(out);
176
+
177
+ return ARGON2_OK;
178
+ }
179
+
180
+ int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
181
+ const uint32_t parallelism, const void *pwd,
182
+ const size_t pwdlen, const void *salt,
183
+ const size_t saltlen, const size_t hashlen,
184
+ char *encoded, const size_t encodedlen) {
185
+
186
+ return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
187
+ NULL, hashlen, encoded, encodedlen, Argon2_i);
188
+ }
189
+
190
+ int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
191
+ const uint32_t parallelism, const void *pwd,
192
+ const size_t pwdlen, const void *salt,
193
+ const size_t saltlen, void *hash, const size_t hashlen) {
194
+
195
+ return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
196
+ hash, hashlen, NULL, 0, Argon2_i);
197
+ }
198
+
199
+ int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost,
200
+ const uint32_t parallelism, const void *pwd,
201
+ const size_t pwdlen, const void *salt,
202
+ const size_t saltlen, const size_t hashlen,
203
+ char *encoded, const size_t encodedlen) {
204
+
205
+ return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
206
+ NULL, hashlen, encoded, encodedlen, Argon2_d);
207
+ }
208
+
209
+ int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost,
210
+ const uint32_t parallelism, const void *pwd,
211
+ const size_t pwdlen, const void *salt,
212
+ const size_t saltlen, void *hash, const size_t hashlen) {
213
+
214
+ return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen,
215
+ hash, hashlen, NULL, 0, Argon2_d);
216
+ }
217
+
218
+ int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) {
219
+ size_t i;
220
+ uint8_t d = 0U;
221
+
222
+ for (i = 0U; i < len; i++) {
223
+ d |= b1[i] ^ b2[i];
160
224
  }
225
+ return (int)((1 & ((d - 1) >> 8)) - 1);
226
+ }
161
227
 
162
- context.out = (uint8_t *)out;
163
- context.outlen = (uint32_t)outlen;
164
- context.pwd = (uint8_t *)in;
165
- context.pwdlen = (uint32_t)inlen;
166
- context.salt = (uint8_t *)salt;
167
- context.saltlen = (uint32_t)saltlen;
168
- context.secret = NULL;
169
- context.secretlen = 0;
170
- context.ad = NULL;
171
- context.adlen = 0;
172
- context.t_cost = t_cost;
173
- context.m_cost = m_cost;
174
- context.lanes = 1;
175
- context.threads = 1;
176
- context.allocate_cbk = NULL;
177
- context.free_cbk = NULL;
178
- context.flags = ARGON2_DEFAULT_FLAGS;
228
+ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
229
+ argon2_type type) {
230
+
231
+ argon2_context ctx;
232
+ uint8_t *out;
179
233
 
180
- return argon2_core(&context, Argon2_d);
234
+ /* max values, to be updated in decode_string */
235
+ ctx.adlen = 512;
236
+ ctx.saltlen = 512;
237
+ ctx.outlen = 512;
238
+
239
+ ctx.ad = malloc(ctx.adlen);
240
+ ctx.salt = malloc(ctx.saltlen);
241
+ ctx.out = malloc(ctx.outlen);
242
+ out = malloc(ctx.outlen);
243
+
244
+ decode_string(&ctx, encoded, type);
245
+
246
+ argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen, ctx.salt,
247
+ ctx.saltlen, out, ctx.outlen, NULL, 0, type);
248
+
249
+ free(ctx.ad);
250
+ free(ctx.salt);
251
+
252
+ if (argon2_compare(out, ctx.out, ctx.outlen)) {
253
+ free(out);
254
+ free(ctx.out);
255
+ return ARGON2_DECODING_FAIL;
256
+ }
257
+ free(out);
258
+ free(ctx.out);
259
+
260
+ return ARGON2_OK;
261
+ }
262
+
263
+ int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
264
+
265
+ return argon2_verify(encoded, pwd, pwdlen, Argon2_i);
266
+ }
267
+
268
+ int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) {
269
+
270
+ return argon2_verify(encoded, pwd, pwdlen, Argon2_d);
181
271
  }
182
272
 
183
273
  int argon2d(argon2_context *context) { return argon2_core(context, Argon2_d); }
@@ -213,148 +303,3 @@ const char *error_message(int error_code) {
213
303
  }
214
304
  return "Unknown error code.";
215
305
  }
216
-
217
- /* encoding/decoding helpers */
218
-
219
- /*
220
- * Some macros for constant-time comparisons. These work over values in
221
- * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
222
- */
223
- #define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)
224
- #define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)
225
- #define GE(x, y) (GT(y, x) ^ 0xFF)
226
- #define LT(x, y) GT(y, x)
227
- #define LE(x, y) GE(y, x)
228
-
229
- /*
230
- * Convert value x (0..63) to corresponding Base64 character.
231
- */
232
- static int b64_byte_to_char(unsigned x) {
233
- return (LT(x, 26) & (x + 'A')) |
234
- (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
235
- (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
236
- (EQ(x, 63) & '/');
237
- }
238
-
239
- /*
240
- * Convert some bytes to Base64. 'dst_len' is the length (in characters)
241
- * of the output buffer 'dst'; if that buffer is not large enough to
242
- * receive the result (including the terminating 0), then (size_t)-1
243
- * is returned. Otherwise, the zero-terminated Base64 string is written
244
- * in the buffer, and the output length (counted WITHOUT the terminating
245
- * zero) is returned.
246
- */
247
- static size_t to_base64(char *dst, size_t dst_len, const void *src,
248
- size_t src_len) {
249
- size_t olen;
250
- const unsigned char *buf;
251
- unsigned acc, acc_len;
252
-
253
- olen = (src_len / 3) << 2;
254
- switch (src_len % 3) {
255
- case 2:
256
- olen++;
257
- /* fall through */
258
- case 1:
259
- olen += 2;
260
- break;
261
- }
262
- if (dst_len <= olen) {
263
- return (size_t)-1;
264
- }
265
- acc = 0;
266
- acc_len = 0;
267
- buf = (const unsigned char *)src;
268
- while (src_len-- > 0) {
269
- acc = (acc << 8) + (*buf++);
270
- acc_len += 8;
271
- while (acc_len >= 6) {
272
- acc_len -= 6;
273
- *dst++ = b64_byte_to_char((acc >> acc_len) & 0x3F);
274
- }
275
- }
276
- if (acc_len > 0) {
277
- *dst++ = b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);
278
- }
279
- *dst++ = 0;
280
- return olen;
281
- }
282
-
283
- /* ==================================================================== */
284
- /*
285
- * Code specific to Argon2i.
286
- *
287
- * The code below applies the following format:
288
- *
289
- * $argon2i$m=<num>,t=<num>,p=<num>[,keyid=<bin>][,data=<bin>][$<bin>[$<bin>]]
290
- *
291
- * where <num> is a decimal integer (positive, fits in an 'unsigned long')
292
- * and <bin> is Base64-encoded data (no '=' padding characters, no newline
293
- * or whitespace). The "keyid" is a binary identifier for a key (up to 8
294
- * bytes); "data" is associated data (up to 32 bytes). When the 'keyid'
295
- * (resp. the 'data') is empty, then it is ommitted from the output.
296
- *
297
- * The last two binary chunks (encoded in Base64) are, in that order,
298
- * the salt and the output. Both are optional, but you cannot have an
299
- * output without a salt. The binary salt length is between 8 and 48 bytes.
300
- * The output length is always exactly 32 bytes.
301
- */
302
-
303
- int encode_string(char *dst, size_t dst_len, argon2_context *ctx) {
304
- #define SS(str) \
305
- do { \
306
- size_t pp_len = strlen(str); \
307
- if (pp_len >= dst_len) { \
308
- return 0; \
309
- } \
310
- memcpy(dst, str, pp_len + 1); \
311
- dst += pp_len; \
312
- dst_len -= pp_len; \
313
- } while (0)
314
-
315
- #define SX(x) \
316
- do { \
317
- char tmp[30]; \
318
- sprintf(tmp, "%lu", (unsigned long)(x)); \
319
- SS(tmp); \
320
- } while (0);
321
-
322
- #define SB(buf, len) \
323
- do { \
324
- size_t sb_len = to_base64(dst, dst_len, buf, len); \
325
- if (sb_len == (size_t)-1) { \
326
- return 0; \
327
- } \
328
- dst += sb_len; \
329
- dst_len -= sb_len; \
330
- } while (0);
331
-
332
- SS("$argon2i$m=");
333
- SX(ctx->m_cost);
334
- SS(",t=");
335
- SX(ctx->t_cost);
336
- SS(",p=");
337
- SX(ctx->lanes);
338
-
339
- if (ctx->adlen > 0) {
340
- SS(",data=");
341
- SB(ctx->ad, ctx->adlen);
342
- }
343
-
344
- if (ctx->saltlen == 0)
345
- return 1;
346
-
347
- SS("$");
348
- SB(ctx->salt, ctx->saltlen);
349
-
350
- if (ctx->outlen == 0)
351
- return 1;
352
-
353
- SS("$");
354
- SB(ctx->out, ctx->outlen);
355
- return 1;
356
-
357
- #undef SS
358
- #undef SX
359
- #undef SB
360
- }