argon2 0.0.2 → 0.1.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.
- 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
|
-
}
|