argon2 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +66 -0
- data/.travis.yml +4 -0
- data/README.md +60 -5
- data/Rakefile +3 -0
- data/argon2.gemspec +10 -12
- data/ext/argon2_wrap/Makefile +4 -4
- data/ext/argon2_wrap/argon_wrap.c +57 -5
- data/ext/argon2_wrap/test.c +84 -12
- data/ext/phc-winner-argon2/.gitignore +1 -0
- data/ext/phc-winner-argon2/Makefile +1 -1
- data/ext/phc-winner-argon2/README.md +31 -26
- data/ext/phc-winner-argon2/src/argon2.c +133 -188
- data/ext/phc-winner-argon2/src/argon2.h +76 -42
- data/ext/phc-winner-argon2/src/core.c +0 -1
- data/ext/phc-winner-argon2/src/core.h +2 -3
- data/ext/phc-winner-argon2/src/encoding.c +435 -0
- data/ext/phc-winner-argon2/src/encoding.h +7 -0
- data/ext/phc-winner-argon2/src/run.c +43 -58
- data/lib/argon2.rb +21 -2
- data/lib/argon2/constants.rb +3 -0
- data/lib/argon2/engine.rb +1 -1
- data/lib/argon2/errors.rb +35 -30
- data/lib/argon2/ffi_engine.rb +43 -21
- data/lib/argon2/version.rb +2 -2
- metadata +51 -7
@@ -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
|
-
|
40
|
-
|
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
|
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
|
-
|
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
|
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
|
93
|
-
uint8_t
|
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 *
|
99
|
-
uint32_t
|
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
|
-
|
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 =
|
110
|
-
uint32_t threads =
|
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
|
-
|
114
|
-
|
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,
|
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(
|
123
|
+
free(pwd);
|
124
124
|
|
125
|
-
for( int i=0; i<
|
126
|
-
if (memcmp(
|
127
|
-
for( int i=0; i<
|
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 `
|
137
|
-
`
|
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
|
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/
|
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
|
103
|
-
|
104
|
-
|
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 (
|
120
|
+
if (pwdlen > UINT32_MAX) {
|
111
121
|
return ARGON2_PWD_TOO_LONG;
|
112
122
|
}
|
113
123
|
|
114
|
-
if (
|
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)
|
124
|
-
context.pwd = (uint8_t *)
|
125
|
-
context.pwdlen = (uint32_t)
|
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 =
|
135
|
-
context.threads =
|
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
|
-
|
141
|
-
}
|
152
|
+
result = argon2_core(&context, type);
|
142
153
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
154
|
+
if (result != ARGON2_OK) {
|
155
|
+
memset(out, 0x00, hashlen);
|
156
|
+
free(out);
|
157
|
+
return result;
|
158
|
+
}
|
147
159
|
|
148
|
-
/*
|
149
|
-
|
150
|
-
|
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
|
155
|
-
|
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
|
-
|
159
|
-
|
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
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
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
|
-
}
|