argon2 0.1.4 → 1.0.0

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