argon2 0.1.4 → 1.0.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -9
  3. data/.travis.yml +0 -1
  4. data/CONTRIBUTING.md +12 -0
  5. data/Changelog.md +10 -11
  6. data/README.md +23 -14
  7. data/ext/argon2_wrap/Makefile +8 -6
  8. data/ext/argon2_wrap/argon_wrap.c +23 -12
  9. data/ext/argon2_wrap/test.c +14 -42
  10. data/ext/phc-winner-argon2/.gitignore +5 -1
  11. data/ext/phc-winner-argon2/.travis.yml +14 -0
  12. data/ext/phc-winner-argon2/Makefile +33 -12
  13. data/ext/phc-winner-argon2/README.md +48 -19
  14. data/ext/phc-winner-argon2/argon2-specs.pdf +0 -0
  15. data/ext/phc-winner-argon2/{src → include}/argon2.h +137 -137
  16. data/ext/phc-winner-argon2/kats/argon2d +12290 -12290
  17. data/ext/phc-winner-argon2/kats/argon2d.shasum +1 -1
  18. data/ext/phc-winner-argon2/kats/argon2i +12290 -12290
  19. data/ext/phc-winner-argon2/kats/argon2i.shasum +1 -1
  20. data/ext/phc-winner-argon2/opt.o +0 -0
  21. data/ext/phc-winner-argon2/src/argon2.c +125 -145
  22. data/ext/phc-winner-argon2/src/bench.c +5 -5
  23. data/ext/phc-winner-argon2/src/core.c +15 -20
  24. data/ext/phc-winner-argon2/src/core.h +5 -2
  25. data/ext/phc-winner-argon2/src/encoding.c +45 -72
  26. data/ext/phc-winner-argon2/src/encoding.h +24 -0
  27. data/ext/phc-winner-argon2/src/genkat.c +2 -2
  28. data/ext/phc-winner-argon2/src/opt.c +19 -10
  29. data/ext/phc-winner-argon2/src/opt.h +5 -17
  30. data/ext/phc-winner-argon2/src/ref.c +12 -9
  31. data/ext/phc-winner-argon2/src/ref.h +4 -12
  32. data/ext/phc-winner-argon2/src/run.c +67 -42
  33. data/ext/phc-winner-argon2/src/test.c +131 -0
  34. data/lib/argon2.rb +6 -5
  35. data/lib/argon2/constants.rb +3 -2
  36. data/lib/argon2/engine.rb +1 -0
  37. data/lib/argon2/errors.rb +37 -36
  38. data/lib/argon2/ffi_engine.rb +10 -10
  39. data/lib/argon2/version.rb +2 -1
  40. metadata +7 -12
@@ -16,14 +16,13 @@
16
16
  #include <stdlib.h>
17
17
 
18
18
  #include "argon2.h"
19
- #include "core.h"
20
19
  #include "ref.h"
21
20
 
22
21
  #include "blake2/blamka-round-ref.h"
23
22
  #include "blake2/blake2-impl.h"
24
23
  #include "blake2/blake2.h"
25
24
 
26
- void fill_block(const block *prev_block, const block *ref_block,
25
+ void fill_block_with_xor(const block *prev_block, const block *ref_block,
27
26
  block *next_block) {
28
27
  block blockR, block_tmp;
29
28
  unsigned i;
@@ -31,7 +30,8 @@ void fill_block(const block *prev_block, const block *ref_block,
31
30
  copy_block(&blockR, ref_block);
32
31
  xor_block(&blockR, prev_block);
33
32
  copy_block(&block_tmp, &blockR);
34
-
33
+ xor_block(&block_tmp, next_block); /*Saving the next block contents for XOR over*/
34
+ /*Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + next_block*/
35
35
  /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
36
36
  (16,17,..31)... finally (112,113,...127) */
37
37
  for (i = 0; i < 8; ++i) {
@@ -63,12 +63,11 @@ void fill_block(const block *prev_block, const block *ref_block,
63
63
  void generate_addresses(const argon2_instance_t *instance,
64
64
  const argon2_position_t *position,
65
65
  uint64_t *pseudo_rands) {
66
- block zero_block, input_block, address_block;
66
+ block zero_block, input_block, address_block,tmp_block;
67
67
  uint32_t i;
68
68
 
69
69
  init_block_value(&zero_block, 0);
70
70
  init_block_value(&input_block, 0);
71
- init_block_value(&address_block, 0);
72
71
 
73
72
  if (instance != NULL && position != NULL) {
74
73
  input_block.v[0] = position->pass;
@@ -81,8 +80,10 @@ void generate_addresses(const argon2_instance_t *instance,
81
80
  for (i = 0; i < instance->segment_length; ++i) {
82
81
  if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
83
82
  input_block.v[6]++;
84
- fill_block(&zero_block, &input_block, &address_block);
85
- fill_block(&zero_block, &address_block, &address_block);
83
+ init_block_value(&tmp_block, 0);
84
+ init_block_value(&address_block, 0);
85
+ fill_block_with_xor(&zero_block, &input_block, &tmp_block);
86
+ fill_block_with_xor(&zero_block, &tmp_block, &address_block);
86
87
  }
87
88
 
88
89
  pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
@@ -97,7 +98,7 @@ void fill_segment(const argon2_instance_t *instance,
97
98
  uint32_t prev_offset, curr_offset;
98
99
  uint32_t starting_index;
99
100
  uint32_t i;
100
- int data_independent_addressing = (instance->type == Argon2_i);
101
+ int data_independent_addressing;
101
102
  /* Pseudo-random values that determine the reference block position */
102
103
  uint64_t *pseudo_rands = NULL;
103
104
 
@@ -105,6 +106,8 @@ void fill_segment(const argon2_instance_t *instance,
105
106
  return;
106
107
  }
107
108
 
109
+ data_independent_addressing = (instance->type == Argon2_i);
110
+
108
111
  pseudo_rands =
109
112
  (uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length));
110
113
 
@@ -168,7 +171,7 @@ void fill_segment(const argon2_instance_t *instance,
168
171
  ref_block =
169
172
  instance->memory + instance->lane_length * ref_lane + ref_index;
170
173
  curr_block = instance->memory + curr_offset;
171
- fill_block(instance->memory + prev_offset, ref_block, curr_block);
174
+ fill_block_with_xor(instance->memory + prev_offset, ref_block, curr_block);
172
175
  }
173
176
 
174
177
  free(pseudo_rands);
@@ -14,14 +14,16 @@
14
14
  #ifndef ARGON2_REF_H
15
15
  #define ARGON2_REF_H
16
16
 
17
+ #include "core.h"
18
+
17
19
  /*
18
- * Function fills a new memory block
20
+ * Function fills a new memory block by XORing over @next_block. @next_block must be initialized
19
21
  * @param prev_block Pointer to the previous block
20
22
  * @param ref_block Pointer to the reference block
21
23
  * @param next_block Pointer to the block to be constructed
22
24
  * @pre all block pointers must be valid
23
25
  */
24
- void fill_block(const block *prev_block, const block *ref_block,
26
+ void fill_block_with_xor(const block *prev_block, const block *ref_block,
25
27
  block *next_block);
26
28
 
27
29
  /*
@@ -36,14 +38,4 @@ void generate_addresses(const argon2_instance_t *instance,
36
38
  const argon2_position_t *position,
37
39
  uint64_t *pseudo_rands);
38
40
 
39
- /*
40
- * Function that fills the segment using previous segments also from other
41
- * threads
42
- * @param instance Pointer to the current instance
43
- * @param position Current position
44
- * @pre all block pointers must be valid
45
- */
46
- void fill_segment(const argon2_instance_t *instance,
47
- argon2_position_t position);
48
-
49
41
  #endif /* ARGON2_REF_H */
@@ -11,9 +11,11 @@
11
11
  * <http://creativecommons.org/publicdomain/zero/1.0/>.
12
12
  */
13
13
 
14
- #include <stdio.h>
15
- #include <stdint.h>
14
+ #define _GNU_SOURCE 1
15
+
16
16
  #include <inttypes.h>
17
+ #include <stdint.h>
18
+ #include <stdio.h>
17
19
  #include <stdlib.h>
18
20
  #include <string.h>
19
21
  #include <time.h>
@@ -25,34 +27,17 @@
25
27
  #define LOG_M_COST_DEF 12 /* 2^12 = 4 MiB */
26
28
  #define LANES_DEF 1
27
29
  #define THREADS_DEF 1
28
- #define OUT_LEN 32
29
- #define SALT_LEN 16
30
- /* Sample encode: $argon2i$m=65536,t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY
31
- * Maximumum lengths are defined as:
32
- * strlen $argon2i$ = 9
33
- * m=65536 with strlen (uint32_t)-1 = 10, so this total is 12
34
- * ,t=2,p=4 If we consider each number to potentially reach four digits in future, this = 14
35
- * $c29tZXNhbHQAAAAAAAAAAA Formula for this is (SALT_LEN * 4 + 3) / 3 + 1 = 23
36
- * $QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY per above formula, = 44
37
- * + NULL byte
38
- * 9 + 12 + 14 + 23 + 44 + 1 = 103
39
- * Rounded to 4 byte boundary: 104
40
- *
41
- * WARNING: 104 is only for the parameters supported by this
42
- command-line utility. You'll need a longer ENCODED_LEN to support
43
- longer salts and ouputs, as supported by the argon2 library
44
- */
45
- #define ENCODED_LEN 108
30
+ #define OUTLEN_DEF 32
46
31
 
47
32
  #define UNUSED_PARAMETER(x) (void)(x)
48
33
 
49
34
  static void usage(const char *cmd) {
50
35
  printf("Usage: %s salt [-d] [-t iterations] [-m memory] "
51
- "[-p parallelism]\n",
36
+ "[-p parallelism] [-h hash length]\n",
52
37
  cmd);
53
38
  printf("\tPassword is read from stdin\n");
54
39
  printf("Parameters:\n");
55
- printf("\tsalt\t\tThe salt to use, at most 16 characters\n");
40
+ printf("\tsalt\t\tThe salt to use, at least 8 characters\n");
56
41
  printf("\t-d\t\tUse Argon2d instead of Argon2i (which is the default)\n");
57
42
  printf("\t-t N\t\tSets the number of iterations to N (default = %d)\n",
58
43
  T_COST_DEF);
@@ -60,6 +45,8 @@ static void usage(const char *cmd) {
60
45
  LOG_M_COST_DEF);
61
46
  printf("\t-p N\t\tSets parallelism to N threads (default %d)\n",
62
47
  THREADS_DEF);
48
+ printf("\t-h N\t\tSets hash output length to N bytes (default %d)\n",
49
+ OUTLEN_DEF);
63
50
  }
64
51
 
65
52
  static void fatal(const char *error) {
@@ -67,24 +54,43 @@ static void fatal(const char *error) {
67
54
  exit(1);
68
55
  }
69
56
 
57
+ static uint32_t b64len(uint32_t len) {
58
+ return ((len + 2) / 3) * 4;
59
+ }
60
+
61
+ static uint32_t numlen(uint32_t num) {
62
+ uint32_t len = 1;
63
+ while (num >= 10) {
64
+ ++len;
65
+ num = num / 10;
66
+ }
67
+ return len;
68
+ }
69
+
70
+ static uint32_t enclen(uint32_t outlen, uint32_t saltlen, uint32_t t_cost,
71
+ uint32_t m_cost, uint32_t lanes) {
72
+ return strlen("$argon2x$m=,t=,p=$$") + numlen(t_cost) + numlen(m_cost)
73
+ + numlen(lanes) + b64len(saltlen) + b64len(outlen);
74
+ }
75
+
76
+
70
77
  /*
71
78
  Runs Argon2 with certain inputs and parameters, inputs not cleared. Prints the
72
79
  Base64-encoded hash string
73
80
  @out output array with at least 32 bytes allocated
74
81
  @pwd NULL-terminated string, presumably from argv[]
75
- @salt salt array with at least SALTLEN_DEF bytes allocated
82
+ @salt salt array
76
83
  @t_cost number of iterations
77
84
  @m_cost amount of requested memory in KB
78
85
  @lanes amount of requested parallelism
79
86
  @threads actual parallelism
80
87
  @type String, only "d" and "i" are accepted
81
88
  */
82
- static void run(uint8_t *out, char *pwd, uint8_t *salt, uint32_t t_cost,
89
+ static void run(uint32_t outlen, char *pwd, char *salt, uint32_t t_cost,
83
90
  uint32_t m_cost, uint32_t lanes, uint32_t threads,
84
91
  argon2_type type) {
85
92
  clock_t start_time, stop_time;
86
- size_t pwdlen;
87
- char encoded[ENCODED_LEN];
93
+ size_t pwdlen, saltlen, encodedlen;
88
94
  uint32_t i;
89
95
  int result;
90
96
 
@@ -100,20 +106,35 @@ static void run(uint8_t *out, char *pwd, uint8_t *salt, uint32_t t_cost,
100
106
  }
101
107
 
102
108
  pwdlen = strlen(pwd);
109
+ saltlen = strlen(salt);
103
110
 
104
111
  UNUSED_PARAMETER(lanes);
105
112
 
106
- result = argon2_hash(t_cost, m_cost, threads, pwd, pwdlen, salt, SALT_LEN,
107
- out, OUT_LEN, encoded, sizeof encoded, type);
113
+ unsigned char* out = malloc(outlen + 1);
114
+ if (!out) {
115
+ secure_wipe_memory(pwd, strlen(pwd));
116
+ fatal("could not allocate memory for output");
117
+ }
118
+
119
+ encodedlen = enclen(outlen, saltlen, t_cost, m_cost, lanes);
120
+ char* encoded = malloc(encodedlen + 1);
121
+ if (!encoded) {
122
+ secure_wipe_memory(pwd, strlen(pwd));
123
+ fatal("could not allocate memory for hash");
124
+ }
125
+
126
+ result = argon2_hash(t_cost, m_cost, threads, pwd, pwdlen, salt, saltlen,
127
+ out, outlen, encoded, encodedlen, type);
108
128
  if (result != ARGON2_OK)
109
- fatal(error_message(result));
129
+ fatal(argon2_error_message(result));
110
130
 
111
131
  stop_time = clock();
112
132
 
113
133
  printf("Hash:\t\t");
114
- for (i = 0; i < OUT_LEN; ++i) {
134
+ for (i = 0; i < outlen; ++i) {
115
135
  printf("%02x", out[i]);
116
136
  }
137
+ free(out);
117
138
  printf("\n");
118
139
  printf("Encoded:\t%s\n", encoded);
119
140
 
@@ -122,27 +143,29 @@ static void run(uint8_t *out, char *pwd, uint8_t *salt, uint32_t t_cost,
122
143
 
123
144
  result = argon2_verify(encoded, pwd, pwdlen, type);
124
145
  if (result != ARGON2_OK)
125
- fatal(error_message(result));
146
+ fatal(argon2_error_message(result));
126
147
  printf("Verification ok\n");
148
+ free(encoded);
127
149
  }
128
150
 
129
151
  int main(int argc, char *argv[]) {
130
- unsigned char out[OUT_LEN];
152
+ uint32_t outlen = OUTLEN_DEF;
131
153
  uint32_t m_cost = 1 << LOG_M_COST_DEF;
132
154
  uint32_t t_cost = T_COST_DEF;
133
155
  uint32_t lanes = LANES_DEF;
134
156
  uint32_t threads = THREADS_DEF;
135
- uint8_t salt[SALT_LEN];
136
157
  argon2_type type = Argon2_i;
137
158
  int i;
138
159
  size_t n;
139
- char pwd[128];
160
+ char pwd[128], *salt;
140
161
 
141
162
  if (argc < 2) {
142
163
  usage(argv[0]);
143
164
  return ARGON2_MISSING_ARGS;
144
165
  }
145
166
 
167
+ salt = argv[1];
168
+
146
169
  /* get password from stdin */
147
170
  while ((n = fread(pwd, 1, sizeof pwd - 1, stdin)) > 0) {
148
171
  pwd[n] = '\0';
@@ -150,13 +173,6 @@ int main(int argc, char *argv[]) {
150
173
  pwd[n - 1] = '\0';
151
174
  }
152
175
 
153
- /* get salt from command line */
154
- if (strlen(argv[1]) > SALT_LEN) {
155
- fatal("salt too long");
156
- }
157
- memset(salt, 0x00, SALT_LEN); /* pad with null bytes */
158
- memcpy(salt, argv[1], strlen(argv[1]));
159
-
160
176
  /* parse options */
161
177
  for (i = 2; i < argc; i++) {
162
178
  const char *a = argv[i];
@@ -204,6 +220,15 @@ int main(int argc, char *argv[]) {
204
220
  } else {
205
221
  fatal("missing -p argument");
206
222
  }
223
+ } else if (!strcmp(a, "-h")) {
224
+ if (i < argc - 1) {
225
+ i++;
226
+ input = strtoul(argv[i], NULL, 10);
227
+ outlen = input;
228
+ continue;
229
+ } else {
230
+ fatal("missing -h argument");
231
+ }
207
232
  } else if (!strcmp(a, "-d")) {
208
233
  type = Argon2_d;
209
234
  } else {
@@ -218,7 +243,7 @@ int main(int argc, char *argv[]) {
218
243
  printf("Iterations:\t%" PRIu32 " \n", t_cost);
219
244
  printf("Memory:\t\t%" PRIu32 " KiB\n", m_cost);
220
245
  printf("Parallelism:\t%" PRIu32 " \n", lanes);
221
- run(out, pwd, salt, t_cost, m_cost, lanes, threads, type);
246
+ run(outlen, pwd, salt, t_cost, m_cost, lanes, threads, type);
222
247
 
223
248
  return ARGON2_OK;
224
249
  }
@@ -0,0 +1,131 @@
1
+ #include <stdio.h>
2
+ #include <stdint.h>
3
+ #include <inttypes.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+ #include <time.h>
7
+ #include <assert.h>
8
+
9
+ #include "argon2.h"
10
+
11
+ #define OUT_LEN 32
12
+ #define SALT_LEN 16
13
+ #define ENCODED_LEN 108
14
+
15
+ uint8_t salt[SALT_LEN];
16
+
17
+ /* Test harness will assert:
18
+ * argon_hash2() returns ARGON2_OK
19
+ * HEX output matches expected
20
+ * encoded output matches expected
21
+ * argon2_verify() correctly verifies value
22
+ */
23
+
24
+ void hashtest(uint32_t t, uint32_t m, uint32_t p, char *pwd, char *hexref,
25
+ char *mcfref) {
26
+ unsigned char out[OUT_LEN];
27
+ unsigned char hex_out[OUT_LEN * 2 + 4];
28
+ char encoded[ENCODED_LEN];
29
+ int ret, i;
30
+
31
+ printf("Hash test: t=%d, m=%d, p=%d, pass=%s, salt=%s: ", t, m, p, pwd,
32
+ salt);
33
+ ret = argon2_hash(t, 1 << m, p, pwd, strlen(pwd), salt, SALT_LEN, out,
34
+ OUT_LEN, encoded, ENCODED_LEN, Argon2_i);
35
+ assert(ret == ARGON2_OK);
36
+
37
+ for (i = 0; i < OUT_LEN; ++i)
38
+ sprintf((char *)(hex_out + i * 2), "%02x", out[i]);
39
+
40
+ assert(memcmp(hex_out, hexref, OUT_LEN * 2) == 0);
41
+ assert(memcmp(encoded, mcfref, strlen(mcfref)) == 0);
42
+ ret = argon2_verify(encoded, pwd, strlen(pwd), Argon2_i);
43
+ assert(ret == ARGON2_OK);
44
+ printf("PASS\n");
45
+ }
46
+
47
+ int main() {
48
+ int ret;
49
+ unsigned char out[OUT_LEN];
50
+ char const *msg;
51
+
52
+ memset(salt, 0x00, SALT_LEN); /* pad with null bytes */
53
+ memcpy(salt, "somesalt", 8);
54
+
55
+ /* Multiple test cases for various input values */
56
+ hashtest(2, 16, 1, "password",
57
+ "1c7eeef9e0e969b3024722fc864a1ca9f6ca20da73f9bf3f1731881beae2039e",
58
+ "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQAAAAAAAAAAA"
59
+ "$HH7u+eDpabMCRyL8hkocqfbKINpz+b8/FzGIG+riA54");
60
+ hashtest(2, 20, 1, "password",
61
+ "253068ce02908829f9c8a026dc7cf4bd4497fd781faa1665a0d0b10d699e0ebd",
62
+ "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQAAAAAAAAAAA"
63
+ "$JTBozgKQiCn5yKAm3Hz0vUSX/XgfqhZloNCxDWmeDr0");
64
+ hashtest(2, 18, 1, "password",
65
+ "5c6dfd2712110cf88f1426059b01d87f8210d5368da0e7ee68586e9d4af4954b",
66
+ "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQAAAAAAAAAAA"
67
+ "$XG39JxIRDPiPFCYFmwHYf4IQ1TaNoOfuaFhunUr0lUs");
68
+ hashtest(2, 8, 1, "password",
69
+ "dfebf9d4eadd6859f4cc6a9bb20043fd9da7e1e36bdacdbb05ca569f463269f8",
70
+ "$argon2i$m=256,t=2,p=1$c29tZXNhbHQAAAAAAAAAAA"
71
+ "$3+v51OrdaFn0zGqbsgBD/Z2n4eNr2s27BcpWn0Yyafg");
72
+ hashtest(2, 8, 2, "password",
73
+ "aea9db129d7f8c50d410a6599b0fb3d786a60ec16a3030b9ddd21ee7b6470f7f",
74
+ "$argon2i$m=256,t=2,p=2$c29tZXNhbHQAAAAAAAAAAA"
75
+ "$rqnbEp1/jFDUEKZZmw+z14amDsFqMDC53dIe57ZHD38");
76
+ hashtest(1, 16, 1, "password",
77
+ "fabd1ddbd86a101d326ac2abe79660202b10192925d2fd2483085df94df0c91a",
78
+ "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQAAAAAAAAAAA"
79
+ "$+r0d29hqEB0yasKr55ZgICsQGSkl0v0kgwhd+U3wyRo");
80
+ hashtest(4, 16, 1, "password",
81
+ "b3b4cb3d6e2c1cb1e7bffdb966ab3ceafae701d6b7789c3f1e6c6b22d82d99d5",
82
+ "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQAAAAAAAAAAA"
83
+ "$s7TLPW4sHLHnv/25Zqs86vrnAda3eJw/HmxrItgtmdU");
84
+ hashtest(2, 16, 1, "differentpassword",
85
+ "b2db9d7c0d1288951aec4b6e1cd3835ea29a7da2ac13e6f48554a26b127146f9",
86
+ "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQAAAAAAAAAAA"
87
+ "$studfA0SiJUa7EtuHNODXqKafaKsE+b0hVSiaxJxRvk");
88
+ memcpy(salt, "diffsalt", 8);
89
+ hashtest(2, 16, 1, "password",
90
+ "bb6686865f2c1093f70f543c9535f807d5b42d5dc6d71f14a4a7a291913e05e0",
91
+ "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQAAAAAAAAAAA"
92
+ "$u2aGhl8sEJP3D1Q8lTX4B9W0LV3G1x8UpKeikZE+BeA");
93
+
94
+ /* Error state tests */
95
+
96
+ ret = argon2_hash(2, 1, 1, "password", strlen("password"), salt, SALT_LEN,
97
+ out, OUT_LEN, NULL, 0, Argon2_i);
98
+ assert(ret == ARGON2_MEMORY_TOO_LITTLE);
99
+ printf("Fail on invalid memory: PASS\n");
100
+
101
+ ret = argon2_hash(2, 1 << 12, 1, NULL, strlen("password"), salt, SALT_LEN,
102
+ out, OUT_LEN, NULL, 0, Argon2_i);
103
+ assert(ret == ARGON2_PWD_PTR_MISMATCH);
104
+ printf("Fail on invalid null pointer: PASS\n");
105
+
106
+ ret = argon2_hash(2, 1 << 12, 1, "password", strlen("password"), salt, 1,
107
+ out, OUT_LEN, NULL, 0, Argon2_i);
108
+ assert(ret == ARGON2_SALT_TOO_SHORT);
109
+ printf("Fail on salt too short: PASS\n");
110
+
111
+ /* Handle an invalid encoding correctly (it is missing a $) */
112
+ ret = argon2_verify("$argon2i$m=65536,t=2,p=1$"
113
+ "c29tZXNhbHQAAAAAAAAAAA"
114
+ "HH7u+eDpabMCRyL8hkocqfbKINpz+b8/FzGIG+riA54",
115
+ "password", strlen("password"), Argon2_i);
116
+ assert(ret == ARGON2_DECODING_FAIL);
117
+ printf("Recognise an invalid encoding: PASS\n");
118
+
119
+ /* Handle an mismatching hash (the encoded password is "passwore") */
120
+ ret = argon2_verify("$argon2i$m=65536,t=2,p=1$c29tZXNhbHQAAAAAAAAAAA"
121
+ "$tiY53ekuxy5gUQV9pEgGgu3cfe2vKl3l+lKxTna33I4",
122
+ "password", strlen("password"), Argon2_i);
123
+ assert(ret == ARGON2_VERIFY_MISMATCH);
124
+ printf("Verify with mismatched password: PASS\n");
125
+
126
+ msg = argon2_error_message(ARGON2_DECODING_FAIL);
127
+ assert(strcmp(msg, "Decoding failed")==0);
128
+ printf("Decode an error message: PASS\n");
129
+
130
+ return 0;
131
+ }