argon2id 0.1.0-aarch64-linux
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 +7 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +9 -0
- data/LICENSE +11 -0
- data/README.md +248 -0
- data/Rakefile +57 -0
- data/argon2id.gemspec +58 -0
- data/ext/argon2id/argon2id.c +69 -0
- data/ext/argon2id/extconf.rb +17 -0
- data/ext/argon2id/libargon2/LICENSE +314 -0
- data/ext/argon2id/libargon2/argon2.c +452 -0
- data/ext/argon2id/libargon2/argon2.h +437 -0
- data/ext/argon2id/libargon2/blake2/blake2-impl.h +156 -0
- data/ext/argon2id/libargon2/blake2/blake2.h +89 -0
- data/ext/argon2id/libargon2/blake2/blake2b.c +390 -0
- data/ext/argon2id/libargon2/blake2/blamka-round-opt.h +471 -0
- data/ext/argon2id/libargon2/blake2/blamka-round-ref.h +56 -0
- data/ext/argon2id/libargon2/core.c +648 -0
- data/ext/argon2id/libargon2/core.h +228 -0
- data/ext/argon2id/libargon2/encoding.c +463 -0
- data/ext/argon2id/libargon2/encoding.h +57 -0
- data/ext/argon2id/libargon2/ref.c +194 -0
- data/ext/argon2id/libargon2/thread.c +57 -0
- data/ext/argon2id/libargon2/thread.h +67 -0
- data/lib/2.6/argon2id.so +0 -0
- data/lib/2.7/argon2id.so +0 -0
- data/lib/3.0/argon2id.so +0 -0
- data/lib/3.1/argon2id.so +0 -0
- data/lib/3.2/argon2id.so +0 -0
- data/lib/3.3/argon2id.so +0 -0
- data/lib/argon2id/password.rb +36 -0
- data/lib/argon2id/version.rb +5 -0
- data/lib/argon2id.rb +29 -0
- data/test/test_hash_encoded.rb +90 -0
- data/test/test_password.rb +86 -0
- data/test/test_verify.rb +24 -0
- metadata +129 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
/*
|
2
|
+
* Argon2 reference source code package - reference C implementations
|
3
|
+
*
|
4
|
+
* Copyright 2015
|
5
|
+
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
6
|
+
*
|
7
|
+
* You may use this work under the terms of a Creative Commons CC0 1.0
|
8
|
+
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
9
|
+
* these licenses can be found at:
|
10
|
+
*
|
11
|
+
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
12
|
+
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
*
|
14
|
+
* You should have received a copy of both of these licenses along with this
|
15
|
+
* software. If not, they may be obtained at the above URLs.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#ifndef ENCODING_H
|
19
|
+
#define ENCODING_H
|
20
|
+
#include "argon2.h"
|
21
|
+
|
22
|
+
#define ARGON2_MAX_DECODED_LANES UINT32_C(255)
|
23
|
+
#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8)
|
24
|
+
#define ARGON2_MIN_DECODED_OUT_LEN UINT32_C(12)
|
25
|
+
|
26
|
+
/*
|
27
|
+
* encode an Argon2 hash string into the provided buffer. 'dst_len'
|
28
|
+
* contains the size, in characters, of the 'dst' buffer; if 'dst_len'
|
29
|
+
* is less than the number of required characters (including the
|
30
|
+
* terminating 0), then this function returns ARGON2_ENCODING_ERROR.
|
31
|
+
*
|
32
|
+
* on success, ARGON2_OK is returned.
|
33
|
+
*/
|
34
|
+
int encode_string(char *dst, size_t dst_len, argon2_context *ctx,
|
35
|
+
argon2_type type);
|
36
|
+
|
37
|
+
/*
|
38
|
+
* Decodes an Argon2 hash string into the provided structure 'ctx'.
|
39
|
+
* The only fields that must be set prior to this call are ctx.saltlen and
|
40
|
+
* ctx.outlen (which must be the maximal salt and out length values that are
|
41
|
+
* allowed), ctx.salt and ctx.out (which must be buffers of the specified
|
42
|
+
* length), and ctx.pwd and ctx.pwdlen which must hold a valid password.
|
43
|
+
*
|
44
|
+
* Invalid input string causes an error. On success, the ctx is valid and all
|
45
|
+
* fields have been initialized.
|
46
|
+
*
|
47
|
+
* Returned value is ARGON2_OK on success, other ARGON2_ codes on error.
|
48
|
+
*/
|
49
|
+
int decode_string(argon2_context *ctx, const char *str, argon2_type type);
|
50
|
+
|
51
|
+
/* Returns the length of the encoded byte stream with length len */
|
52
|
+
size_t b64len(uint32_t len);
|
53
|
+
|
54
|
+
/* Returns the length of the encoded number num */
|
55
|
+
size_t numlen(uint32_t num);
|
56
|
+
|
57
|
+
#endif
|
@@ -0,0 +1,194 @@
|
|
1
|
+
/*
|
2
|
+
* Argon2 reference source code package - reference C implementations
|
3
|
+
*
|
4
|
+
* Copyright 2015
|
5
|
+
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
6
|
+
*
|
7
|
+
* You may use this work under the terms of a Creative Commons CC0 1.0
|
8
|
+
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
9
|
+
* these licenses can be found at:
|
10
|
+
*
|
11
|
+
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
12
|
+
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
*
|
14
|
+
* You should have received a copy of both of these licenses along with this
|
15
|
+
* software. If not, they may be obtained at the above URLs.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include <stdint.h>
|
19
|
+
#include <string.h>
|
20
|
+
#include <stdlib.h>
|
21
|
+
|
22
|
+
#include "argon2.h"
|
23
|
+
#include "core.h"
|
24
|
+
|
25
|
+
#include "blake2/blamka-round-ref.h"
|
26
|
+
#include "blake2/blake2-impl.h"
|
27
|
+
#include "blake2/blake2.h"
|
28
|
+
|
29
|
+
|
30
|
+
/*
|
31
|
+
* Function fills a new memory block and optionally XORs the old block over the new one.
|
32
|
+
* @next_block must be initialized.
|
33
|
+
* @param prev_block Pointer to the previous block
|
34
|
+
* @param ref_block Pointer to the reference block
|
35
|
+
* @param next_block Pointer to the block to be constructed
|
36
|
+
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
|
37
|
+
* @pre all block pointers must be valid
|
38
|
+
*/
|
39
|
+
static void fill_block(const block *prev_block, const block *ref_block,
|
40
|
+
block *next_block, int with_xor) {
|
41
|
+
block blockR, block_tmp;
|
42
|
+
unsigned i;
|
43
|
+
|
44
|
+
copy_block(&blockR, ref_block);
|
45
|
+
xor_block(&blockR, prev_block);
|
46
|
+
copy_block(&block_tmp, &blockR);
|
47
|
+
/* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */
|
48
|
+
if (with_xor) {
|
49
|
+
/* Saving the next block contents for XOR over: */
|
50
|
+
xor_block(&block_tmp, next_block);
|
51
|
+
/* Now blockR = ref_block + prev_block and
|
52
|
+
block_tmp = ref_block + prev_block + next_block */
|
53
|
+
}
|
54
|
+
|
55
|
+
/* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
|
56
|
+
(16,17,..31)... finally (112,113,...127) */
|
57
|
+
for (i = 0; i < 8; ++i) {
|
58
|
+
BLAKE2_ROUND_NOMSG(
|
59
|
+
blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
|
60
|
+
blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
|
61
|
+
blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
|
62
|
+
blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
|
63
|
+
blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
|
64
|
+
blockR.v[16 * i + 15]);
|
65
|
+
}
|
66
|
+
|
67
|
+
/* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
|
68
|
+
(2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */
|
69
|
+
for (i = 0; i < 8; i++) {
|
70
|
+
BLAKE2_ROUND_NOMSG(
|
71
|
+
blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
|
72
|
+
blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
|
73
|
+
blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
|
74
|
+
blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
|
75
|
+
blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
|
76
|
+
blockR.v[2 * i + 113]);
|
77
|
+
}
|
78
|
+
|
79
|
+
copy_block(next_block, &block_tmp);
|
80
|
+
xor_block(next_block, &blockR);
|
81
|
+
}
|
82
|
+
|
83
|
+
static void next_addresses(block *address_block, block *input_block,
|
84
|
+
const block *zero_block) {
|
85
|
+
input_block->v[6]++;
|
86
|
+
fill_block(zero_block, input_block, address_block, 0);
|
87
|
+
fill_block(zero_block, address_block, address_block, 0);
|
88
|
+
}
|
89
|
+
|
90
|
+
void fill_segment(const argon2_instance_t *instance,
|
91
|
+
argon2_position_t position) {
|
92
|
+
block *ref_block = NULL, *curr_block = NULL;
|
93
|
+
block address_block, input_block, zero_block;
|
94
|
+
uint64_t pseudo_rand, ref_index, ref_lane;
|
95
|
+
uint32_t prev_offset, curr_offset;
|
96
|
+
uint32_t starting_index;
|
97
|
+
uint32_t i;
|
98
|
+
int data_independent_addressing;
|
99
|
+
|
100
|
+
if (instance == NULL) {
|
101
|
+
return;
|
102
|
+
}
|
103
|
+
|
104
|
+
data_independent_addressing =
|
105
|
+
(instance->type == Argon2_i) ||
|
106
|
+
(instance->type == Argon2_id && (position.pass == 0) &&
|
107
|
+
(position.slice < ARGON2_SYNC_POINTS / 2));
|
108
|
+
|
109
|
+
if (data_independent_addressing) {
|
110
|
+
init_block_value(&zero_block, 0);
|
111
|
+
init_block_value(&input_block, 0);
|
112
|
+
|
113
|
+
input_block.v[0] = position.pass;
|
114
|
+
input_block.v[1] = position.lane;
|
115
|
+
input_block.v[2] = position.slice;
|
116
|
+
input_block.v[3] = instance->memory_blocks;
|
117
|
+
input_block.v[4] = instance->passes;
|
118
|
+
input_block.v[5] = instance->type;
|
119
|
+
}
|
120
|
+
|
121
|
+
starting_index = 0;
|
122
|
+
|
123
|
+
if ((0 == position.pass) && (0 == position.slice)) {
|
124
|
+
starting_index = 2; /* we have already generated the first two blocks */
|
125
|
+
|
126
|
+
/* Don't forget to generate the first block of addresses: */
|
127
|
+
if (data_independent_addressing) {
|
128
|
+
next_addresses(&address_block, &input_block, &zero_block);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
/* Offset of the current block */
|
133
|
+
curr_offset = position.lane * instance->lane_length +
|
134
|
+
position.slice * instance->segment_length + starting_index;
|
135
|
+
|
136
|
+
if (0 == curr_offset % instance->lane_length) {
|
137
|
+
/* Last block in this lane */
|
138
|
+
prev_offset = curr_offset + instance->lane_length - 1;
|
139
|
+
} else {
|
140
|
+
/* Previous block */
|
141
|
+
prev_offset = curr_offset - 1;
|
142
|
+
}
|
143
|
+
|
144
|
+
for (i = starting_index; i < instance->segment_length;
|
145
|
+
++i, ++curr_offset, ++prev_offset) {
|
146
|
+
/*1.1 Rotating prev_offset if needed */
|
147
|
+
if (curr_offset % instance->lane_length == 1) {
|
148
|
+
prev_offset = curr_offset - 1;
|
149
|
+
}
|
150
|
+
|
151
|
+
/* 1.2 Computing the index of the reference block */
|
152
|
+
/* 1.2.1 Taking pseudo-random value from the previous block */
|
153
|
+
if (data_independent_addressing) {
|
154
|
+
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
|
155
|
+
next_addresses(&address_block, &input_block, &zero_block);
|
156
|
+
}
|
157
|
+
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
|
158
|
+
} else {
|
159
|
+
pseudo_rand = instance->memory[prev_offset].v[0];
|
160
|
+
}
|
161
|
+
|
162
|
+
/* 1.2.2 Computing the lane of the reference block */
|
163
|
+
ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
|
164
|
+
|
165
|
+
if ((position.pass == 0) && (position.slice == 0)) {
|
166
|
+
/* Can not reference other lanes yet */
|
167
|
+
ref_lane = position.lane;
|
168
|
+
}
|
169
|
+
|
170
|
+
/* 1.2.3 Computing the number of possible reference block within the
|
171
|
+
* lane.
|
172
|
+
*/
|
173
|
+
position.index = i;
|
174
|
+
ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
|
175
|
+
ref_lane == position.lane);
|
176
|
+
|
177
|
+
/* 2 Creating a new block */
|
178
|
+
ref_block =
|
179
|
+
instance->memory + instance->lane_length * ref_lane + ref_index;
|
180
|
+
curr_block = instance->memory + curr_offset;
|
181
|
+
if (ARGON2_VERSION_10 == instance->version) {
|
182
|
+
/* version 1.2.1 and earlier: overwrite, not XOR */
|
183
|
+
fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);
|
184
|
+
} else {
|
185
|
+
if(0 == position.pass) {
|
186
|
+
fill_block(instance->memory + prev_offset, ref_block,
|
187
|
+
curr_block, 0);
|
188
|
+
} else {
|
189
|
+
fill_block(instance->memory + prev_offset, ref_block,
|
190
|
+
curr_block, 1);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/*
|
2
|
+
* Argon2 reference source code package - reference C implementations
|
3
|
+
*
|
4
|
+
* Copyright 2015
|
5
|
+
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
6
|
+
*
|
7
|
+
* You may use this work under the terms of a Creative Commons CC0 1.0
|
8
|
+
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
9
|
+
* these licenses can be found at:
|
10
|
+
*
|
11
|
+
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
12
|
+
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
*
|
14
|
+
* You should have received a copy of both of these licenses along with this
|
15
|
+
* software. If not, they may be obtained at the above URLs.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#if !defined(ARGON2_NO_THREADS)
|
19
|
+
|
20
|
+
#include "thread.h"
|
21
|
+
#if defined(_WIN32)
|
22
|
+
#include <windows.h>
|
23
|
+
#endif
|
24
|
+
|
25
|
+
int argon2_thread_create(argon2_thread_handle_t *handle,
|
26
|
+
argon2_thread_func_t func, void *args) {
|
27
|
+
if (NULL == handle || func == NULL) {
|
28
|
+
return -1;
|
29
|
+
}
|
30
|
+
#if defined(_WIN32)
|
31
|
+
*handle = _beginthreadex(NULL, 0, func, args, 0, NULL);
|
32
|
+
return *handle != 0 ? 0 : -1;
|
33
|
+
#else
|
34
|
+
return pthread_create(handle, NULL, func, args);
|
35
|
+
#endif
|
36
|
+
}
|
37
|
+
|
38
|
+
int argon2_thread_join(argon2_thread_handle_t handle) {
|
39
|
+
#if defined(_WIN32)
|
40
|
+
if (WaitForSingleObject((HANDLE)handle, INFINITE) == WAIT_OBJECT_0) {
|
41
|
+
return CloseHandle((HANDLE)handle) != 0 ? 0 : -1;
|
42
|
+
}
|
43
|
+
return -1;
|
44
|
+
#else
|
45
|
+
return pthread_join(handle, NULL);
|
46
|
+
#endif
|
47
|
+
}
|
48
|
+
|
49
|
+
void argon2_thread_exit(void) {
|
50
|
+
#if defined(_WIN32)
|
51
|
+
_endthreadex(0);
|
52
|
+
#else
|
53
|
+
pthread_exit(NULL);
|
54
|
+
#endif
|
55
|
+
}
|
56
|
+
|
57
|
+
#endif /* ARGON2_NO_THREADS */
|
@@ -0,0 +1,67 @@
|
|
1
|
+
/*
|
2
|
+
* Argon2 reference source code package - reference C implementations
|
3
|
+
*
|
4
|
+
* Copyright 2015
|
5
|
+
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
6
|
+
*
|
7
|
+
* You may use this work under the terms of a Creative Commons CC0 1.0
|
8
|
+
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
|
9
|
+
* these licenses can be found at:
|
10
|
+
*
|
11
|
+
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
12
|
+
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
*
|
14
|
+
* You should have received a copy of both of these licenses along with this
|
15
|
+
* software. If not, they may be obtained at the above URLs.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#ifndef ARGON2_THREAD_H
|
19
|
+
#define ARGON2_THREAD_H
|
20
|
+
|
21
|
+
#if !defined(ARGON2_NO_THREADS)
|
22
|
+
|
23
|
+
/*
|
24
|
+
Here we implement an abstraction layer for the simpĺe requirements
|
25
|
+
of the Argon2 code. We only require 3 primitives---thread creation,
|
26
|
+
joining, and termination---so full emulation of the pthreads API
|
27
|
+
is unwarranted. Currently we wrap pthreads and Win32 threads.
|
28
|
+
|
29
|
+
The API defines 2 types: the function pointer type,
|
30
|
+
argon2_thread_func_t,
|
31
|
+
and the type of the thread handle---argon2_thread_handle_t.
|
32
|
+
*/
|
33
|
+
#if defined(_WIN32)
|
34
|
+
#include <process.h>
|
35
|
+
typedef unsigned(__stdcall *argon2_thread_func_t)(void *);
|
36
|
+
typedef uintptr_t argon2_thread_handle_t;
|
37
|
+
#else
|
38
|
+
#include <pthread.h>
|
39
|
+
typedef void *(*argon2_thread_func_t)(void *);
|
40
|
+
typedef pthread_t argon2_thread_handle_t;
|
41
|
+
#endif
|
42
|
+
|
43
|
+
/* Creates a thread
|
44
|
+
* @param handle pointer to a thread handle, which is the output of this
|
45
|
+
* function. Must not be NULL.
|
46
|
+
* @param func A function pointer for the thread's entry point. Must not be
|
47
|
+
* NULL.
|
48
|
+
* @param args Pointer that is passed as an argument to @func. May be NULL.
|
49
|
+
* @return 0 if @handle and @func are valid pointers and a thread is successfully
|
50
|
+
* created.
|
51
|
+
*/
|
52
|
+
int argon2_thread_create(argon2_thread_handle_t *handle,
|
53
|
+
argon2_thread_func_t func, void *args);
|
54
|
+
|
55
|
+
/* Waits for a thread to terminate
|
56
|
+
* @param handle Handle to a thread created with argon2_thread_create.
|
57
|
+
* @return 0 if @handle is a valid handle, and joining completed successfully.
|
58
|
+
*/
|
59
|
+
int argon2_thread_join(argon2_thread_handle_t handle);
|
60
|
+
|
61
|
+
/* Terminate the current thread. Must be run inside a thread created by
|
62
|
+
* argon2_thread_create.
|
63
|
+
*/
|
64
|
+
void argon2_thread_exit(void);
|
65
|
+
|
66
|
+
#endif /* ARGON2_NO_THREADS */
|
67
|
+
#endif
|
data/lib/2.6/argon2id.so
ADDED
Binary file
|
data/lib/2.7/argon2id.so
ADDED
Binary file
|
data/lib/3.0/argon2id.so
ADDED
Binary file
|
data/lib/3.1/argon2id.so
ADDED
Binary file
|
data/lib/3.2/argon2id.so
ADDED
Binary file
|
data/lib/3.3/argon2id.so
ADDED
Binary file
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
|
5
|
+
module Argon2id
|
6
|
+
class Password
|
7
|
+
attr_reader :encoded
|
8
|
+
|
9
|
+
def self.create(pwd, t_cost: Argon2id.t_cost, m_cost: Argon2id.m_cost, parallelism: Argon2id.parallelism, salt_len: Argon2id.salt_len, output_len: Argon2id.output_len)
|
10
|
+
new(
|
11
|
+
Argon2id.hash_encoded(
|
12
|
+
Integer(t_cost),
|
13
|
+
Integer(m_cost),
|
14
|
+
Integer(parallelism),
|
15
|
+
String(pwd),
|
16
|
+
OpenSSL::Random.random_bytes(Integer(salt_len)),
|
17
|
+
Integer(output_len)
|
18
|
+
)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(encoded)
|
23
|
+
@encoded = encoded
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
encoded
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
Argon2id.verify(encoded, String(other))
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :is_password?, :==
|
35
|
+
end
|
36
|
+
end
|
data/lib/argon2id.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
::RUBY_VERSION =~ /(\d+\.\d+)/
|
5
|
+
require_relative "#{Regexp.last_match(1)}/argon2id.so"
|
6
|
+
rescue LoadError
|
7
|
+
require "argon2id.so"
|
8
|
+
end
|
9
|
+
|
10
|
+
require "argon2id/version"
|
11
|
+
require "argon2id/password"
|
12
|
+
|
13
|
+
module Argon2id
|
14
|
+
DEFAULT_T_COST = 2
|
15
|
+
DEFAULT_M_COST = 19456
|
16
|
+
DEFAULT_PARALLELISM = 1
|
17
|
+
DEFAULT_SALT_LEN = 16
|
18
|
+
DEFAULT_OUTPUT_LEN = 32
|
19
|
+
|
20
|
+
@t_cost = DEFAULT_T_COST
|
21
|
+
@m_cost = DEFAULT_M_COST
|
22
|
+
@parallelism = DEFAULT_PARALLELISM
|
23
|
+
@salt_len = DEFAULT_SALT_LEN
|
24
|
+
@output_len = DEFAULT_OUTPUT_LEN
|
25
|
+
|
26
|
+
class << self
|
27
|
+
attr_accessor :t_cost, :m_cost, :parallelism, :salt_len, :output_len
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "argon2id"
|
5
|
+
|
6
|
+
class TestHashEncoded < Minitest::Test
|
7
|
+
def test_valid_password_and_salt_encodes_successfully
|
8
|
+
encoded = Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
9
|
+
|
10
|
+
assert encoded.start_with?("$argon2id$")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_valid_password_does_not_include_trailing_null_byte
|
14
|
+
encoded = Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
15
|
+
|
16
|
+
refute encoded.end_with?("\x00")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_raises_with_too_short_output
|
20
|
+
error = assert_raises(Argon2id::Error) do
|
21
|
+
Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 1)
|
22
|
+
end
|
23
|
+
|
24
|
+
assert_equal "Output is too short", error.message
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_raises_with_too_large_output
|
28
|
+
assert_raises(RangeError) do
|
29
|
+
Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 4294967296)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_raises_with_too_few_lanes
|
34
|
+
error = assert_raises(Argon2id::Error) do
|
35
|
+
Argon2id.hash_encoded(2, 19456, 0, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_equal "Too few lanes", error.message
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_raises_with_too_small_memory_cost
|
42
|
+
error = assert_raises(Argon2id::Error) do
|
43
|
+
Argon2id.hash_encoded(2, 0, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_equal "Memory cost is too small", error.message
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_raises_with_too_large_memory_cost
|
50
|
+
assert_raises(RangeError) do
|
51
|
+
Argon2id.hash_encoded(2, 4294967296, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_raises_with_too_small_time_cost
|
56
|
+
error = assert_raises(Argon2id::Error) do
|
57
|
+
Argon2id.hash_encoded(0, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
58
|
+
end
|
59
|
+
|
60
|
+
assert_equal "Time cost is too small", error.message
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_raises_with_too_large_time_cost
|
64
|
+
assert_raises(RangeError) do
|
65
|
+
Argon2id.hash_encoded(4294967296, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_raises_with_too_long_password
|
70
|
+
error = assert_raises(Argon2id::Error) do
|
71
|
+
Argon2id.hash_encoded(2, 19456, 1, "a" * 4294967296, OpenSSL::Random.random_bytes(16), 32)
|
72
|
+
end
|
73
|
+
|
74
|
+
assert_equal "Password is too long", error.message
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_raises_with_too_short_salt
|
78
|
+
error = assert_raises(Argon2id::Error) do
|
79
|
+
Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(1), 32)
|
80
|
+
end
|
81
|
+
|
82
|
+
assert_equal "Salt is too short", error.message
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_raises_with_too_long_salt
|
86
|
+
assert_raises(RangeError) do
|
87
|
+
Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(4294967296), 32)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "argon2id"
|
5
|
+
|
6
|
+
class TestPassword < Minitest::Test
|
7
|
+
def test_create_returns_encoded_password_with_defaults
|
8
|
+
password = Argon2id::Password.create("opensesame")
|
9
|
+
|
10
|
+
assert password.to_s.start_with?("$argon2id$")
|
11
|
+
assert password.to_s.include?("t=2")
|
12
|
+
assert password.to_s.include?("m=19456")
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_create_options_can_override_parameters
|
16
|
+
password = Argon2id::Password.create("opensesame", t_cost: 3, m_cost: 12288)
|
17
|
+
|
18
|
+
assert password.to_s.include?("t=3")
|
19
|
+
assert password.to_s.include?("m=12288")
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_create_uses_argon2id_configuration
|
23
|
+
Argon2id.parallelism = 4
|
24
|
+
Argon2id.m_cost = 9216
|
25
|
+
|
26
|
+
password = Argon2id::Password.create("opensesame")
|
27
|
+
|
28
|
+
assert password.to_s.include?("p=4")
|
29
|
+
assert password.to_s.include?("m=9216")
|
30
|
+
ensure
|
31
|
+
Argon2id.parallelism = Argon2id::DEFAULT_PARALLELISM
|
32
|
+
Argon2id.m_cost = Argon2id::DEFAULT_M_COST
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_create_coerces_pwd_to_string
|
36
|
+
password = Argon2id::Password.create(123)
|
37
|
+
|
38
|
+
assert password.to_s.start_with?("$argon2id$")
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_create_coerces_costs_to_integer
|
42
|
+
password = Argon2id::Password.create("opensesame", t_cost: "5", m_cost: "7168", parallelism: "1", salt_len: "16", output_len: "32")
|
43
|
+
|
44
|
+
assert password.to_s.start_with?("$argon2id$")
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_create_raises_if_given_non_integer_costs
|
48
|
+
assert_raises(ArgumentError) do
|
49
|
+
Argon2id::Password.create("opensesame", t_cost: "not an integer")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_equals_correct_password
|
54
|
+
password = Argon2id::Password.create("opensesame")
|
55
|
+
|
56
|
+
assert password == "opensesame"
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_does_not_equal_invalid_password
|
60
|
+
password = Argon2id::Password.create("opensesame")
|
61
|
+
|
62
|
+
refute password == "notopensesame"
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_is_password_returns_true_with_correct_password
|
66
|
+
password = Argon2id::Password.create("opensesame")
|
67
|
+
|
68
|
+
assert password.is_password?("opensesame")
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_is_password_returns_false_with_incorrect_password
|
72
|
+
password = Argon2id::Password.create("opensesame")
|
73
|
+
|
74
|
+
refute password.is_password?("notopensesame")
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_raises_if_verifying_with_invalid_encoded_password
|
78
|
+
password = Argon2id::Password.new("invalid")
|
79
|
+
|
80
|
+
error = assert_raises(Argon2id::Error) do
|
81
|
+
password.is_password?("opensesame")
|
82
|
+
end
|
83
|
+
|
84
|
+
assert_equal "Decoding failed", error.message
|
85
|
+
end
|
86
|
+
end
|
data/test/test_verify.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "argon2id"
|
5
|
+
|
6
|
+
class TestVerify < Minitest::Test
|
7
|
+
def test_returns_true_with_correct_password
|
8
|
+
encoded = Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
9
|
+
|
10
|
+
assert Argon2id.verify(encoded, "opensesame")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_returns_false_with_incorrect_password
|
14
|
+
encoded = Argon2id.hash_encoded(2, 19456, 1, "opensesame", OpenSSL::Random.random_bytes(16), 32)
|
15
|
+
|
16
|
+
refute Argon2id.verify(encoded, "notopensesame")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_raises_if_given_invalid_encoded
|
20
|
+
assert_raises(Argon2id::Error) do
|
21
|
+
Argon2id.verify("", "opensesame")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|