argon2 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +2 -0
  4. data/README.md +25 -9
  5. data/argon2.gemspec +10 -2
  6. data/bin/console +1 -1
  7. data/bin/setup +3 -0
  8. data/ext/argon2_wrap/Makefile +72 -0
  9. data/ext/argon2_wrap/argon_wrap.c +65 -0
  10. data/ext/argon2_wrap/extconf.rb +1 -0
  11. data/ext/argon2_wrap/test.c +67 -0
  12. data/ext/phc-winner-argon2/.gitignore +7 -0
  13. data/ext/phc-winner-argon2/LICENSE +31 -0
  14. data/ext/phc-winner-argon2/Makefile +102 -0
  15. data/ext/phc-winner-argon2/README.md +193 -0
  16. data/ext/phc-winner-argon2/argon2-specs.pdf +0 -0
  17. data/ext/phc-winner-argon2/kats/argon2d +12302 -0
  18. data/ext/phc-winner-argon2/kats/argon2d.shasum +1 -0
  19. data/ext/phc-winner-argon2/kats/argon2i +12302 -0
  20. data/ext/phc-winner-argon2/kats/argon2i.shasum +1 -0
  21. data/ext/phc-winner-argon2/kats/check-sums.sh +13 -0
  22. data/ext/phc-winner-argon2/kats/test.sh +47 -0
  23. data/ext/phc-winner-argon2/src/argon2.c +360 -0
  24. data/ext/phc-winner-argon2/src/argon2.h +298 -0
  25. data/ext/phc-winner-argon2/src/bench.c +111 -0
  26. data/ext/phc-winner-argon2/src/blake2/blake2-impl.h +143 -0
  27. data/ext/phc-winner-argon2/src/blake2/blake2.h +74 -0
  28. data/ext/phc-winner-argon2/src/blake2/blake2b.c +372 -0
  29. data/ext/phc-winner-argon2/src/blake2/blamka-round-opt.h +162 -0
  30. data/ext/phc-winner-argon2/src/blake2/blamka-round-ref.h +39 -0
  31. data/ext/phc-winner-argon2/src/core.c +662 -0
  32. data/ext/phc-winner-argon2/src/core.h +226 -0
  33. data/ext/phc-winner-argon2/src/genkat.c +194 -0
  34. data/ext/phc-winner-argon2/src/genkat.h +45 -0
  35. data/ext/phc-winner-argon2/src/opt.c +173 -0
  36. data/ext/phc-winner-argon2/src/opt.h +49 -0
  37. data/ext/phc-winner-argon2/src/ref.c +175 -0
  38. data/ext/phc-winner-argon2/src/ref.h +49 -0
  39. data/ext/phc-winner-argon2/src/run.c +223 -0
  40. data/ext/phc-winner-argon2/src/thread.c +36 -0
  41. data/ext/phc-winner-argon2/src/thread.h +46 -0
  42. data/lib/argon2.rb +15 -32
  43. data/lib/argon2/constants.rb +6 -0
  44. data/lib/argon2/engine.rb +10 -0
  45. data/lib/argon2/errors.rb +36 -0
  46. data/lib/argon2/ffi_engine.rb +47 -0
  47. data/lib/argon2/version.rb +1 -1
  48. metadata +75 -11
@@ -0,0 +1,173 @@
1
+ /*
2
+ * Argon2 source code package
3
+ *
4
+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015
5
+ *
6
+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
7
+ *
8
+ * You should have received a copy of the CC0 Public Domain Dedication along
9
+ * with
10
+ * this software. If not, see
11
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
12
+ */
13
+
14
+ #include <stdint.h>
15
+ #include <string.h>
16
+ #include <stdlib.h>
17
+
18
+ #include <immintrin.h>
19
+
20
+ #include "argon2.h"
21
+ #include "core.h"
22
+ #include "opt.h"
23
+
24
+ #include "blake2/blake2.h"
25
+ #include "blake2/blamka-round-opt.h"
26
+
27
+ void fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block) {
28
+ __m128i block_XY[ARGON2_QWORDS_IN_BLOCK];
29
+ uint32_t i;
30
+
31
+ for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; i++) {
32
+ block_XY[i] = state[i] = _mm_xor_si128(
33
+ state[i], _mm_loadu_si128((__m128i const *)(&ref_block[16 * i])));
34
+ }
35
+
36
+ for (i = 0; i < 8; ++i) {
37
+ BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2],
38
+ state[8 * i + 3], state[8 * i + 4], state[8 * i + 5],
39
+ state[8 * i + 6], state[8 * i + 7]);
40
+ }
41
+
42
+ for (i = 0; i < 8; ++i) {
43
+ BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i],
44
+ state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i],
45
+ state[8 * 6 + i], state[8 * 7 + i]);
46
+ }
47
+
48
+ for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; i++) {
49
+ state[i] = _mm_xor_si128(state[i], block_XY[i]);
50
+ _mm_storeu_si128((__m128i *)(&next_block[16 * i]), state[i]);
51
+ }
52
+ }
53
+
54
+ void generate_addresses(const argon2_instance_t *instance,
55
+ const argon2_position_t *position,
56
+ uint64_t *pseudo_rands) {
57
+ block address_block, input_block;
58
+ uint32_t i;
59
+
60
+ init_block_value(&address_block, 0);
61
+ init_block_value(&input_block, 0);
62
+
63
+ if (instance != NULL && position != NULL) {
64
+ input_block.v[0] = position->pass;
65
+ input_block.v[1] = position->lane;
66
+ input_block.v[2] = position->slice;
67
+ input_block.v[3] = instance->memory_blocks;
68
+ input_block.v[4] = instance->passes;
69
+ input_block.v[5] = instance->type;
70
+
71
+ for (i = 0; i < instance->segment_length; ++i) {
72
+ if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
73
+ __m128i zero_block[ARGON2_QWORDS_IN_BLOCK];
74
+ __m128i zero2_block[ARGON2_QWORDS_IN_BLOCK];
75
+ memset(zero_block, 0, sizeof(zero_block));
76
+ memset(zero2_block, 0, sizeof(zero2_block));
77
+ input_block.v[6]++;
78
+ fill_block(zero_block, (uint8_t *)&input_block.v,
79
+ (uint8_t *)&address_block.v);
80
+ fill_block(zero2_block, (uint8_t *)&address_block.v,
81
+ (uint8_t *)&address_block.v);
82
+ }
83
+
84
+ pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
85
+ }
86
+ }
87
+ }
88
+
89
+ void fill_segment(const argon2_instance_t *instance,
90
+ argon2_position_t position) {
91
+ block *ref_block = NULL, *curr_block = NULL;
92
+ uint64_t pseudo_rand, ref_index, ref_lane;
93
+ uint32_t prev_offset, curr_offset;
94
+ uint32_t starting_index, i;
95
+ __m128i state[64];
96
+ int data_independent_addressing = (instance->type == Argon2_i);
97
+
98
+ /* Pseudo-random values that determine the reference block position */
99
+ uint64_t *pseudo_rands = NULL;
100
+
101
+ if (instance == NULL) {
102
+ return;
103
+ }
104
+
105
+ pseudo_rands =
106
+ (uint64_t *)malloc(sizeof(uint64_t) * instance->segment_length);
107
+ if (pseudo_rands == NULL) {
108
+ return;
109
+ }
110
+
111
+ if (data_independent_addressing) {
112
+ generate_addresses(instance, &position, pseudo_rands);
113
+ }
114
+
115
+ starting_index = 0;
116
+
117
+ if ((0 == position.pass) && (0 == position.slice)) {
118
+ starting_index = 2; /* we have already generated the first two blocks */
119
+ }
120
+
121
+ /* Offset of the current block */
122
+ curr_offset = position.lane * instance->lane_length +
123
+ position.slice * instance->segment_length + starting_index;
124
+
125
+ if (0 == curr_offset % instance->lane_length) {
126
+ /* Last block in this lane */
127
+ prev_offset = curr_offset + instance->lane_length - 1;
128
+ } else {
129
+ /* Previous block */
130
+ prev_offset = curr_offset - 1;
131
+ }
132
+
133
+ memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);
134
+
135
+ for (i = starting_index; i < instance->segment_length;
136
+ ++i, ++curr_offset, ++prev_offset) {
137
+ /*1.1 Rotating prev_offset if needed */
138
+ if (curr_offset % instance->lane_length == 1) {
139
+ prev_offset = curr_offset - 1;
140
+ }
141
+
142
+ /* 1.2 Computing the index of the reference block */
143
+ /* 1.2.1 Taking pseudo-random value from the previous block */
144
+ if (data_independent_addressing) {
145
+ pseudo_rand = pseudo_rands[i];
146
+ } else {
147
+ pseudo_rand = instance->memory[prev_offset].v[0];
148
+ }
149
+
150
+ /* 1.2.2 Computing the lane of the reference block */
151
+ ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
152
+
153
+ if ((position.pass == 0) && (position.slice == 0)) {
154
+ /* Can not reference other lanes yet */
155
+ ref_lane = position.lane;
156
+ }
157
+
158
+ /* 1.2.3 Computing the number of possible reference block within the
159
+ * lane.
160
+ */
161
+ position.index = i;
162
+ ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
163
+ ref_lane == position.lane);
164
+
165
+ /* 2 Creating a new block */
166
+ ref_block =
167
+ instance->memory + instance->lane_length * ref_lane + ref_index;
168
+ curr_block = instance->memory + curr_offset;
169
+ fill_block(state, (uint8_t *)ref_block->v, (uint8_t *)curr_block->v);
170
+ }
171
+
172
+ free(pseudo_rands);
173
+ }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Argon2 source code package
3
+ *
4
+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015
5
+ *
6
+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
7
+ *
8
+ * You should have received a copy of the CC0 Public Domain Dedication along
9
+ * with
10
+ * this software. If not, see
11
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
12
+ */
13
+
14
+ #ifndef ARGON2_OPT_H
15
+ #define ARGON2_OPT_H
16
+
17
+ /*
18
+ * Function fills a new memory block. Differs from the
19
+ * @param state Pointer to the just produced block. Content will be updated(!)
20
+ * @param ref_block Pointer to the reference block
21
+ * @param next_block Pointer to the block to be constructed
22
+ * @pre all block pointers must be valid
23
+ */
24
+ void fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block);
25
+
26
+ /*
27
+ * Generate pseudo-random values to reference blocks in the segment and puts
28
+ * them into the array
29
+ * @param instance Pointer to the current instance
30
+ * @param position Pointer to the current position
31
+ * @param pseudo_rands Pointer to the array of 64-bit values
32
+ * @pre pseudo_rands must point to @a instance->segment_length allocated values
33
+ */
34
+ void generate_addresses(const argon2_instance_t *instance,
35
+ const argon2_position_t *position,
36
+ uint64_t *pseudo_rands);
37
+
38
+ /*
39
+ * Function that fills the segment using previous segments also from other
40
+ * threads.
41
+ * Identical to the reference code except that it calls optimized FillBlock()
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
+ #endif /* ARGON2_OPT_H */
@@ -0,0 +1,175 @@
1
+ /*
2
+ * Argon2 source code package
3
+ *
4
+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015
5
+ *
6
+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
7
+ *
8
+ * You should have received a copy of the CC0 Public Domain Dedication along
9
+ * with
10
+ * this software. If not, see
11
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
12
+ */
13
+
14
+ #include <stdint.h>
15
+ #include <string.h>
16
+ #include <stdlib.h>
17
+
18
+ #include "argon2.h"
19
+ #include "core.h"
20
+ #include "ref.h"
21
+
22
+ #include "blake2/blamka-round-ref.h"
23
+ #include "blake2/blake2-impl.h"
24
+ #include "blake2/blake2.h"
25
+
26
+ void fill_block(const block *prev_block, const block *ref_block,
27
+ block *next_block) {
28
+ block blockR, block_tmp;
29
+ unsigned i;
30
+
31
+ copy_block(&blockR, ref_block);
32
+ xor_block(&blockR, prev_block);
33
+ copy_block(&block_tmp, &blockR);
34
+
35
+ /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
36
+ (16,17,..31)... finally (112,113,...127) */
37
+ for (i = 0; i < 8; ++i) {
38
+ BLAKE2_ROUND_NOMSG(
39
+ blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
40
+ blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
41
+ blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
42
+ blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
43
+ blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
44
+ blockR.v[16 * i + 15]);
45
+ }
46
+
47
+ /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
48
+ (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */
49
+ for (i = 0; i < 8; i++) {
50
+ BLAKE2_ROUND_NOMSG(
51
+ blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
52
+ blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
53
+ blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
54
+ blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
55
+ blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
56
+ blockR.v[2 * i + 113]);
57
+ }
58
+
59
+ copy_block(next_block, &block_tmp);
60
+ xor_block(next_block, &blockR);
61
+ }
62
+
63
+ void generate_addresses(const argon2_instance_t *instance,
64
+ const argon2_position_t *position,
65
+ uint64_t *pseudo_rands) {
66
+ block zero_block, input_block, address_block;
67
+ uint32_t i;
68
+
69
+ init_block_value(&zero_block, 0);
70
+ init_block_value(&input_block, 0);
71
+ init_block_value(&address_block, 0);
72
+
73
+ if (instance != NULL && position != NULL) {
74
+ input_block.v[0] = position->pass;
75
+ input_block.v[1] = position->lane;
76
+ input_block.v[2] = position->slice;
77
+ input_block.v[3] = instance->memory_blocks;
78
+ input_block.v[4] = instance->passes;
79
+ input_block.v[5] = instance->type;
80
+
81
+ for (i = 0; i < instance->segment_length; ++i) {
82
+ if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
83
+ input_block.v[6]++;
84
+ fill_block(&zero_block, &input_block, &address_block);
85
+ fill_block(&zero_block, &address_block, &address_block);
86
+ }
87
+
88
+ pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
89
+ }
90
+ }
91
+ }
92
+
93
+ void fill_segment(const argon2_instance_t *instance,
94
+ argon2_position_t position) {
95
+ block *ref_block = NULL, *curr_block = NULL;
96
+ uint64_t pseudo_rand, ref_index, ref_lane;
97
+ uint32_t prev_offset, curr_offset;
98
+ uint32_t starting_index;
99
+ uint32_t i;
100
+ int data_independent_addressing = (instance->type == Argon2_i);
101
+ /* Pseudo-random values that determine the reference block position */
102
+ uint64_t *pseudo_rands = NULL;
103
+
104
+ if (instance == NULL) {
105
+ return;
106
+ }
107
+
108
+ pseudo_rands =
109
+ (uint64_t *)malloc(sizeof(uint64_t) * (instance->segment_length));
110
+
111
+ if (pseudo_rands == NULL) {
112
+ return;
113
+ }
114
+
115
+ if (data_independent_addressing) {
116
+ generate_addresses(instance, &position, pseudo_rands);
117
+ }
118
+
119
+ starting_index = 0;
120
+
121
+ if ((0 == position.pass) && (0 == position.slice)) {
122
+ starting_index = 2; /* we have already generated the first two blocks */
123
+ }
124
+
125
+ /* Offset of the current block */
126
+ curr_offset = position.lane * instance->lane_length +
127
+ position.slice * instance->segment_length + starting_index;
128
+
129
+ if (0 == curr_offset % instance->lane_length) {
130
+ /* Last block in this lane */
131
+ prev_offset = curr_offset + instance->lane_length - 1;
132
+ } else {
133
+ /* Previous block */
134
+ prev_offset = curr_offset - 1;
135
+ }
136
+
137
+ for (i = starting_index; i < instance->segment_length;
138
+ ++i, ++curr_offset, ++prev_offset) {
139
+ /*1.1 Rotating prev_offset if needed */
140
+ if (curr_offset % instance->lane_length == 1) {
141
+ prev_offset = curr_offset - 1;
142
+ }
143
+
144
+ /* 1.2 Computing the index of the reference block */
145
+ /* 1.2.1 Taking pseudo-random value from the previous block */
146
+ if (data_independent_addressing) {
147
+ pseudo_rand = pseudo_rands[i];
148
+ } else {
149
+ pseudo_rand = instance->memory[prev_offset].v[0];
150
+ }
151
+
152
+ /* 1.2.2 Computing the lane of the reference block */
153
+ ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
154
+
155
+ if ((position.pass == 0) && (position.slice == 0)) {
156
+ /* Can not reference other lanes yet */
157
+ ref_lane = position.lane;
158
+ }
159
+
160
+ /* 1.2.3 Computing the number of possible reference block within the
161
+ * lane.
162
+ */
163
+ position.index = i;
164
+ ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
165
+ ref_lane == position.lane);
166
+
167
+ /* 2 Creating a new block */
168
+ ref_block =
169
+ instance->memory + instance->lane_length * ref_lane + ref_index;
170
+ curr_block = instance->memory + curr_offset;
171
+ fill_block(instance->memory + prev_offset, ref_block, curr_block);
172
+ }
173
+
174
+ free(pseudo_rands);
175
+ }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Argon2 source code package
3
+ *
4
+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015
5
+ *
6
+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
7
+ *
8
+ * You should have received a copy of the CC0 Public Domain Dedication along
9
+ * with
10
+ * this software. If not, see
11
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
12
+ */
13
+
14
+ #ifndef ARGON2_REF_H
15
+ #define ARGON2_REF_H
16
+
17
+ /*
18
+ * Function fills a new memory block
19
+ * @param prev_block Pointer to the previous block
20
+ * @param ref_block Pointer to the reference block
21
+ * @param next_block Pointer to the block to be constructed
22
+ * @pre all block pointers must be valid
23
+ */
24
+ void fill_block(const block *prev_block, const block *ref_block,
25
+ block *next_block);
26
+
27
+ /*
28
+ * Generate pseudo-random values to reference blocks in the segment and puts
29
+ * them into the array
30
+ * @param instance Pointer to the current instance
31
+ * @param position Pointer to the current position
32
+ * @param pseudo_rands Pointer to the array of 64-bit values
33
+ * @pre pseudo_rands must point to @a instance->segment_length allocated values
34
+ */
35
+ void generate_addresses(const argon2_instance_t *instance,
36
+ const argon2_position_t *position,
37
+ uint64_t *pseudo_rands);
38
+
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
+ #endif /* ARGON2_REF_H */
@@ -0,0 +1,223 @@
1
+ /*
2
+ * Argon2 source code package
3
+ *
4
+ * Written by Daniel Dinu and Dmitry Khovratovich, 2015
5
+ *
6
+ * This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
7
+ *
8
+ * You should have received a copy of the CC0 Public Domain Dedication along
9
+ * with
10
+ * this software. If not, see
11
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
12
+ */
13
+
14
+ #include <stdio.h>
15
+ #include <stdint.h>
16
+ #include <inttypes.h>
17
+ #include <stdlib.h>
18
+ #include <string.h>
19
+ #include <time.h>
20
+
21
+ #include "argon2.h"
22
+ #include "core.h"
23
+
24
+ #define T_COST_DEF 3
25
+ #define LOG_M_COST_DEF 12 /* 2^12 = 4 MiB */
26
+ #define LANES_DEF 1
27
+ #define THREADS_DEF 1
28
+ #define OUT_LEN 32
29
+ #define SALT_LEN 16
30
+
31
+ #define UNUSED_PARAMETER(x) (void)(x)
32
+
33
+ static void usage(const char *cmd) {
34
+ printf("Usage: %s pwd salt [-d] [-t iterations] [-m memory] "
35
+ "[-p parallelism]\n",
36
+ cmd);
37
+
38
+ printf("Parameters:\n");
39
+ printf("\tpwd\t\tThe password to hash\n");
40
+ printf("\tsalt\t\tThe salt to use, at most 16 characters\n");
41
+ printf("\t-d\t\tUse Argon2d instead of Argon2i (which is the default)\n");
42
+ printf("\t-t N\t\tSets the number of iterations to N (default = %d)\n",
43
+ T_COST_DEF);
44
+ printf("\t-m N\t\tSets the memory usage of 2^N KiB (default %d)\n",
45
+ LOG_M_COST_DEF);
46
+ printf("\t-p N\t\tSets parallelism to N threads (default %d)\n",
47
+ THREADS_DEF);
48
+ }
49
+
50
+ static void fatal(const char *error) {
51
+ fprintf(stderr, "Error: %s\n", error);
52
+ exit(1);
53
+ }
54
+
55
+ /*
56
+ Runs Argon2 with certain inputs and parameters, inputs not cleared. Prints the
57
+ Base64-encoded hash string
58
+ @out output array with at least 32 bytes allocated
59
+ @pwd NULL-terminated string, presumably from argv[]
60
+ @salt salt array with at least SALTLEN_DEF bytes allocated
61
+ @t_cost number of iterations
62
+ @m_cost amount of requested memory in KB
63
+ @lanes amount of requested parallelism
64
+ @threads actual parallelism
65
+ @type String, only "d" and "i" are accepted
66
+ */
67
+ static void run(uint8_t *out, char *pwd, uint8_t *salt, uint32_t t_cost,
68
+ uint32_t m_cost, uint32_t lanes, uint32_t threads,
69
+ const char *type) {
70
+ clock_t start_time, stop_time;
71
+ unsigned pwd_length;
72
+ argon2_context context;
73
+ uint32_t i;
74
+
75
+ start_time = clock();
76
+
77
+ if (!pwd) {
78
+ fatal("password missing");
79
+ }
80
+
81
+ if (!salt) {
82
+ secure_wipe_memory(pwd, strlen(pwd));
83
+ fatal("salt missing");
84
+ }
85
+
86
+ pwd_length = strlen(pwd);
87
+
88
+ UNUSED_PARAMETER(threads);
89
+
90
+ context.out = out;
91
+ context.outlen = OUT_LEN;
92
+ context.pwd = (uint8_t *)pwd;
93
+ context.pwdlen = pwd_length;
94
+ context.salt = salt;
95
+ context.saltlen = SALT_LEN;
96
+ context.secret = NULL;
97
+ context.secretlen = 0;
98
+ context.ad = NULL;
99
+ context.adlen = 0;
100
+ context.t_cost = t_cost;
101
+ context.m_cost = m_cost;
102
+ context.lanes = lanes;
103
+ context.threads = lanes;
104
+ context.allocate_cbk = NULL;
105
+ context.free_cbk = NULL;
106
+ context.flags = ARGON2_FLAG_CLEAR_PASSWORD;
107
+
108
+ if (!strcmp(type, "d")) {
109
+ int result = argon2d(&context);
110
+ if (result != ARGON2_OK)
111
+ fatal(error_message(result));
112
+ } else if (!strcmp(type, "i")) {
113
+ int result = argon2i(&context);
114
+ if (result != ARGON2_OK)
115
+ fatal(error_message(result));
116
+ } else {
117
+ secure_wipe_memory(pwd, strlen(pwd));
118
+ fatal("wrong Argon2 type");
119
+ }
120
+
121
+ stop_time = clock();
122
+
123
+ /* add back when proper decoding */
124
+ /*
125
+ char encoded[300];
126
+ encode_string(encoded, sizeof encoded, &context);
127
+ printf("%s\n", encoded);
128
+ */
129
+ printf("Hash:\t\t");
130
+ for (i = 0; i < context.outlen; ++i) {
131
+ printf("%02x", context.out[i]);
132
+ }
133
+ printf("\n");
134
+
135
+ printf("%2.3f seconds\n",
136
+ ((double)stop_time - start_time) / (CLOCKS_PER_SEC));
137
+ }
138
+
139
+ int main(int argc, char *argv[]) {
140
+ unsigned char out[OUT_LEN];
141
+ uint32_t m_cost = 1 << LOG_M_COST_DEF;
142
+ uint32_t t_cost = T_COST_DEF;
143
+ uint32_t lanes = LANES_DEF;
144
+ uint32_t threads = THREADS_DEF;
145
+ char *pwd = NULL;
146
+ uint8_t salt[SALT_LEN];
147
+ const char *type = "i";
148
+ int i;
149
+
150
+ if (argc < 3) {
151
+ usage(argv[0]);
152
+ return ARGON2_MISSING_ARGS;
153
+ }
154
+
155
+ /* get password and salt from command line */
156
+ pwd = argv[1];
157
+ if (strlen(argv[2]) > SALT_LEN) {
158
+ fatal("salt too long");
159
+ }
160
+ memset(salt, 0x00, SALT_LEN); /* pad with null bytes */
161
+ memcpy(salt, argv[2], strlen(argv[2]));
162
+
163
+ /* parse options */
164
+ for (i = 3; i < argc; i++) {
165
+ const char *a = argv[i];
166
+ unsigned long input = 0;
167
+ if (!strcmp(a, "-m")) {
168
+ if (i < argc - 1) {
169
+ i++;
170
+ input = strtoul(argv[i], NULL, 10);
171
+ if (input == 0 || input == ULONG_MAX ||
172
+ input > ARGON2_MAX_MEMORY_BITS) {
173
+ fatal("bad numeric input for -m");
174
+ }
175
+ m_cost = ARGON2_MIN(UINT64_C(1) << input, UINT32_C(0xFFFFFFFF));
176
+ if (m_cost > ARGON2_MAX_MEMORY) {
177
+ fatal("m_cost overflow");
178
+ }
179
+ continue;
180
+ } else {
181
+ fatal("missing -m argument");
182
+ }
183
+ } else if (!strcmp(a, "-t")) {
184
+ if (i < argc - 1) {
185
+ i++;
186
+ input = strtoul(argv[i], NULL, 10);
187
+ if (input == 0 || input == ULONG_MAX ||
188
+ input > ARGON2_MAX_TIME) {
189
+ fatal("bad numeric input for -t");
190
+ }
191
+ t_cost = input;
192
+ continue;
193
+ } else {
194
+ fatal("missing -t argument");
195
+ }
196
+ } else if (!strcmp(a, "-p")) {
197
+ if (i < argc - 1) {
198
+ i++;
199
+ input = strtoul(argv[i], NULL, 10);
200
+ if (input == 0 || input == ULONG_MAX ||
201
+ input > ARGON2_MAX_THREADS || input > ARGON2_MAX_LANES) {
202
+ fatal("bad numeric input for -p");
203
+ }
204
+ threads = input;
205
+ lanes = threads;
206
+ continue;
207
+ } else {
208
+ fatal("missing -p argument");
209
+ }
210
+ } else if (!strcmp(a, "-d")) {
211
+ type = "d";
212
+ } else {
213
+ fatal("unknown argument");
214
+ }
215
+ }
216
+ printf("Type:\t\tArgon2%c\n", type[0]);
217
+ printf("Iterations:\t%" PRIu32 " \n", t_cost);
218
+ printf("Memory:\t\t%" PRIu32 " KiB\n", m_cost);
219
+ printf("Parallelism:\t%" PRIu32 " \n", lanes);
220
+ run(out, pwd, salt, t_cost, m_cost, lanes, threads, type);
221
+
222
+ return ARGON2_OK;
223
+ }