argon2id 0.1.0-x64-mingw32

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.
@@ -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
Binary file
Binary file
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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Argon2id
4
+ VERSION = "0.1.0"
5
+ 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
@@ -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