argon2 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- }