yescrypt 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1ba0d0c9b88163285669166982ad7cb47cfcd51ad07935b30d5215b51a8c2c8b
4
+ data.tar.gz: 14f1b653e6c920e6c0f1e973b877c7d146c68006018bddbfcf5728ac33b6aeda
5
+ SHA512:
6
+ metadata.gz: 412ec3b20fd3180dfac8fe5e8b5851d645027055f9f9752056059f1fb6443febec4969498b4061500e4f2664503ce41c2bebdc4590c966a239422c8e565054b8
7
+ data.tar.gz: 45314045bb1f25679b68336b17aa4a59e9bfa5725ef8ca5c9548bfed2d91d9b4330f1deeb34b596ee70579c98e277334bc48268b406f96865552891e33bd4e76
data/LICENSE ADDED
@@ -0,0 +1,42 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Suleyman Musayev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ The yescrypt C implementation is based on work by:
26
+
27
+ Copyright (c) 2009 Colin Percival (scrypt)
28
+ Copyright (c) 2013-2021 Alexander Peslyak (yescrypt)
29
+
30
+ Redistribution and use in source and binary forms, with or without
31
+ modification, are permitted provided that the following conditions
32
+ are met:
33
+ 1. Redistributions of source code must retain the above copyright
34
+ notice, this list of conditions and the following disclaimer.
35
+ 2. Redistributions in binary form must reproduce the above copyright
36
+ notice, this list of conditions and the following disclaimer in the
37
+ documentation and/or other materials provided with the distribution.
38
+
39
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
40
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42
+ ARE DISCLAIMED.
data/README.md ADDED
@@ -0,0 +1,325 @@
1
+ # yescrypt
2
+
3
+ A Ruby C extension wrapping the [yescrypt](https://www.openwall.com/yescrypt/) password hashing algorithm.
4
+
5
+ yescrypt is the default password hash in modern Linux distributions (glibc 2.36+). It extends [scrypt](https://www.tarsnap.com/scrypt.html) with pwxform for stronger time-memory tradeoff resistance, making it significantly more costly for attackers using GPUs or custom hardware.
6
+
7
+ ## Features
8
+
9
+ - High-level `create` / `verify` API modeled after bcrypt-ruby
10
+ - Low-level `kdf` access for custom use cases
11
+ - Constant-time hash comparison via `OpenSSL.fixed_length_secure_compare`
12
+ - Thread-safe: releases the GVL during hashing so other Ruby threads can run
13
+ - GC-compaction safe with pinned string references
14
+ - Sensitive buffers are zeroed after use
15
+ - Supports all three yescrypt flavors: WORM, RW, and DEFAULTS
16
+
17
+ ## Requirements
18
+
19
+ - Ruby >= 2.7.2
20
+ - A C99-compatible compiler (gcc, clang, etc.)
21
+
22
+ ## Installation
23
+
24
+ Add to your Gemfile:
25
+
26
+ ```ruby
27
+ gem "yescrypt"
28
+ ```
29
+
30
+ Then run:
31
+
32
+ ```
33
+ bundle install
34
+ ```
35
+
36
+ Or install directly:
37
+
38
+ ```
39
+ gem install yescrypt
40
+ ```
41
+
42
+ The C extension compiles automatically during installation. No external libraries are needed -- yescrypt, SHA-256, HMAC, and PBKDF2 are all bundled.
43
+
44
+ ## Quick Start
45
+
46
+ ```ruby
47
+ require "yescrypt"
48
+
49
+ # Hash a password (uses secure defaults: N=2^12, r=32, p=1)
50
+ hash = Yescrypt.create("my secret password")
51
+ # => "$y$j..."
52
+
53
+ # Verify a password against a stored hash
54
+ Yescrypt.verify("my secret password", hash) # => true
55
+ Yescrypt.verify("wrong password", hash) # => false
56
+
57
+ # Check if a hash needs rehashing (e.g., after changing cost parameters)
58
+ Yescrypt.cost_matches?(hash) # => true (matches current defaults)
59
+ Yescrypt.cost_matches?(hash, n_log2: 14, r: 32, p: 1) # => false
60
+ ```
61
+
62
+ ## API Reference
63
+
64
+ ### `Yescrypt.create(password, **options)`
65
+
66
+ Hash a password and return an encoded string suitable for storage.
67
+
68
+ ```ruby
69
+ hash = Yescrypt.create("password")
70
+ hash = Yescrypt.create("password", n_log2: 14, r: 32, p: 1, t: 0, flags: Yescrypt::DEFAULTS)
71
+ ```
72
+
73
+ **Parameters:**
74
+
75
+ | Parameter | Type | Default | Description |
76
+ |-----------|---------|--------------------------|------------------------------------------------|
77
+ | password | String | *(required)* | The plaintext password |
78
+ | n_log2: | Integer | `12` | Log2 of the block count (memory cost). N = 2^n_log2 |
79
+ | r: | Integer | `32` | Block size parameter (affects memory per block) |
80
+ | p: | Integer | `1` | Parallelism parameter |
81
+ | t: | Integer | `0` | Time parameter (extra mixing rounds) |
82
+ | flags: | Integer | `Yescrypt::DEFAULTS` (2) | Flavor flags (see [Flavors](#flavors)) |
83
+
84
+ **Returns:** A frozen, US-ASCII encoded string starting with `$y$`.
85
+
86
+ A random 16-byte salt is generated automatically using `SecureRandom`.
87
+
88
+ ### `Yescrypt.verify(password, hash)`
89
+
90
+ Verify a plaintext password against an encoded hash.
91
+
92
+ ```ruby
93
+ Yescrypt.verify("password", hash) # => true or false
94
+ ```
95
+
96
+ Returns `false` for any invalid input (wrong types, malformed hash, wrong password) rather than raising exceptions. Uses constant-time comparison to prevent timing attacks.
97
+
98
+ ### `Yescrypt.cost_matches?(hash, **options)`
99
+
100
+ Check whether an existing hash was generated with the given parameters. Useful for determining if a password needs rehashing after a cost parameter change.
101
+
102
+ ```ruby
103
+ if Yescrypt.verify(password, stored_hash)
104
+ unless Yescrypt.cost_matches?(stored_hash, n_log2: 14)
105
+ # Rehash with new cost parameters
106
+ new_hash = Yescrypt.create(password, n_log2: 14)
107
+ save_hash(new_hash)
108
+ end
109
+ end
110
+ ```
111
+
112
+ **Parameters:** Same keyword arguments as `create`. Omitted parameters default to the current defaults.
113
+
114
+ **Returns:** `true` if all parameters (n_log2, r, p, t, flags) match, `false` otherwise.
115
+
116
+ ### `Yescrypt.default_params`
117
+
118
+ Returns a frozen hash of the current default parameters:
119
+
120
+ ```ruby
121
+ Yescrypt.default_params
122
+ # => { n_log2: 12, r: 32, p: 1, t: 0, flags: 2 }
123
+ ```
124
+
125
+ ### `Yescrypt.decode_params(hash)`
126
+
127
+ Parse the parameters from an encoded yescrypt hash string.
128
+
129
+ ```ruby
130
+ params = Yescrypt.decode_params(hash)
131
+ # => { n_log2: 12, r: 32, p: 1, t: 0, flags: 2 }
132
+ ```
133
+
134
+ **Returns:** A frozen hash with `:n_log2`, `:r`, `:p`, `:t`, `:flags` keys, or `nil` if the string is not a valid yescrypt hash.
135
+
136
+ ### `Yescrypt.gensalt(**options)`
137
+
138
+ Generate a setting/salt string for low-level use. You typically don't need this directly -- `create` calls it internally.
139
+
140
+ ```ruby
141
+ salt = SecureRandom.random_bytes(16)
142
+ setting = Yescrypt.gensalt(n_log2: 12, r: 32, p: 1, t: 0, flags: Yescrypt::DEFAULTS, salt: salt)
143
+ ```
144
+
145
+ The `salt:` keyword is required and must be a binary String (typically 16 random bytes).
146
+
147
+ ### `Yescrypt.kdf(password, salt, **options)`
148
+
149
+ Low-level KDF function that returns raw hash bytes. Unlike `create`, this gives you direct control over all parameters and returns unencoded binary output.
150
+
151
+ ```ruby
152
+ raw = Yescrypt.kdf("password", "salt" * 4,
153
+ n: 4096, r: 32, p: 1, flags: Yescrypt::DEFAULTS, t: 0, outlen: 32)
154
+ raw.bytesize # => 32
155
+ ```
156
+
157
+ **Parameters:**
158
+
159
+ | Parameter | Type | Default | Description |
160
+ |-----------|---------|--------------|------------------------------------------|
161
+ | password | String | *(required)* | The plaintext password |
162
+ | salt | String | *(required)* | Salt bytes (any length) |
163
+ | n: | Integer | *(required)* | Block count (must be a power of 2, >= 2) |
164
+ | r: | Integer | *(required)* | Block size parameter |
165
+ | p: | Integer | *(required)* | Parallelism parameter |
166
+ | flags: | Integer | *(required)* | Flavor flags |
167
+ | t: | Integer | `0` | Time parameter |
168
+ | outlen: | Integer | `32` | Output length in bytes (1..1024) |
169
+
170
+ **Returns:** A binary String of `outlen` bytes.
171
+
172
+ Note: `n` here is the actual block count (e.g., `4096`), not the log2 value used in `create` (where you'd use `n_log2: 12`).
173
+
174
+ ## Flavors
175
+
176
+ yescrypt supports three operational flavors:
177
+
178
+ | Constant | Value | Description |
179
+ |-----------------------|-------|-------------------------------------------------------------------------|
180
+ | `Yescrypt::WORM` | 0 | Classic scrypt-compatible mode. Read-only memory access pattern. |
181
+ | `Yescrypt::RW` | 1 | yescrypt with read-write memory access. Stronger against TMTO attacks. |
182
+ | `Yescrypt::DEFAULTS` | 2 | Recommended mode. Includes RW access plus pwxform strengthening. |
183
+
184
+ `DEFAULTS` is recommended for new applications. `WORM` is useful if you need scrypt compatibility.
185
+
186
+ ## Choosing Parameters
187
+
188
+ The cost parameters control the trade-off between security and performance:
189
+
190
+ - **n_log2** (memory cost): Each increment doubles memory usage and time. Start with `12` (4096 blocks) and increase if your server can handle it. `14` (16384 blocks) is a good choice for higher security.
191
+ - **r** (block size): Controls memory per block (128 * r bytes). The default `32` (4 KB per block) is well-suited for modern CPUs. Increasing `r` increases memory bandwidth requirements.
192
+ - **p** (parallelism): Number of independent mixing operations. Keep at `1` unless you specifically need parallel computation. Increasing `p` scales CPU time linearly without increasing memory.
193
+ - **t** (time): Extra mixing rounds. Each increment of `t` adds N more mixing iterations. Keep at `0` unless you want to increase CPU time without increasing memory.
194
+
195
+ ### Memory usage
196
+
197
+ Approximate memory per hash operation: `128 * r * N` bytes, where `N = 2^n_log2`.
198
+
199
+ | n_log2 | r | Memory |
200
+ |--------|-----|------------|
201
+ | 10 | 8 | 1 MB |
202
+ | 12 | 32 | 16 MB |
203
+ | 14 | 32 | 64 MB |
204
+ | 16 | 32 | 256 MB |
205
+
206
+ ### Benchmarking
207
+
208
+ Test different parameters to find the right trade-off for your application:
209
+
210
+ ```ruby
211
+ require "benchmark"
212
+
213
+ [10, 12, 14].each do |n|
214
+ time = Benchmark.realtime { Yescrypt.create("test", n_log2: n, r: 32, p: 1) }
215
+ puts "n_log2=#{n}: #{(time * 1000).round}ms"
216
+ end
217
+ ```
218
+
219
+ ## Thread Safety
220
+
221
+ yescrypt releases the Ruby GVL (Global VM Lock) during the CPU-intensive hashing computation. This means other Ruby threads can execute while a hash is being computed:
222
+
223
+ ```ruby
224
+ threads = 4.times.map do |i|
225
+ Thread.new { Yescrypt.create("password_#{i}", n_log2: 4, r: 1, p: 1) }
226
+ end
227
+ hashes = threads.map(&:value) # all 4 run concurrently
228
+ ```
229
+
230
+ Each call allocates its own working memory, so there is no shared mutable state between threads.
231
+
232
+ ## Hash Format
233
+
234
+ The encoded hash string follows the crypt(3) modular format:
235
+
236
+ ```
237
+ $y$j<params>$<salt>$<hash>
238
+ ```
239
+
240
+ - `$y$` -- yescrypt identifier prefix
241
+ - `j` -- flavor indicator
242
+ - `<params>` -- base64-encoded N_log2, r, p, t, and flags
243
+ - `<salt>` -- base64-encoded salt
244
+ - `<hash>` -- base64-encoded 256-bit derived key
245
+
246
+ Example:
247
+ ```
248
+ $y$jD5.7C....$aBcDeFgHiJkLmNoPqR..$xYzAbCdEfGhIjKlMnOpQrStUvWxYz01234567890AB
249
+ ```
250
+
251
+ ## Error Handling
252
+
253
+ The gem defines a single exception class:
254
+
255
+ ```ruby
256
+ Yescrypt::Error < StandardError
257
+ ```
258
+
259
+ Raised by low-level functions (`kdf`, `gensalt`, `_hash_password`) when the C library reports a failure (e.g., memory allocation failure, invalid setting string).
260
+
261
+ The high-level `verify` method never raises -- it returns `false` on any error. The high-level `create` method raises `TypeError` if the password is not a String, and may raise `Yescrypt::Error` on internal failures.
262
+
263
+ ## Comparison with Other Password Hashing Gems
264
+
265
+ | Feature | yescrypt | bcrypt-ruby | scrypt |
266
+ |------------------------|--------------------|--------------------|--------------------|
267
+ | Memory-hard | Yes | No | Yes |
268
+ | TMTO resistance | Strong (pwxform) | N/A | Moderate |
269
+ | Linux default (2024+) | Yes | No | No |
270
+ | GVL released | Yes | Yes | Yes |
271
+ | Constant-time verify | Yes | Yes | Yes |
272
+
273
+ ## Development
274
+
275
+ ```bash
276
+ # Clone the repository
277
+ git clone https://github.com/msuliq/yescrypt.git
278
+ cd yescrypt
279
+
280
+ # Install dependencies
281
+ bundle install
282
+
283
+ # Compile the C extension
284
+ bundle exec rake compile
285
+
286
+ # Run tests
287
+ bundle exec rake test
288
+
289
+ # Run both (compile + test)
290
+ bundle exec rake
291
+ ```
292
+
293
+ ### Project Structure
294
+
295
+ ```
296
+ yescrypt/
297
+ ext/yescrypt/ # C extension source
298
+ extconf.rb # Build configuration
299
+ yescrypt_ext.c # Ruby/C bridge
300
+ yescrypt-opt.c # Core yescrypt algorithm (smix, salsa20, pwxform)
301
+ yescrypt-common.c # Encoding, decoding, salt generation, yescrypt_r
302
+ yescrypt.h # Public C API header
303
+ sha256.c # SHA-256 / HMAC / PBKDF2 implementation
304
+ sha256.h # SHA-256 header
305
+ insecure_memzero.h # Secure memory zeroing
306
+ lib/
307
+ yescrypt.rb # High-level Ruby API (create, verify, cost_matches?)
308
+ yescrypt/version.rb # Version constant
309
+ test/
310
+ yescrypt_test.rb # Minitest test suite
311
+ test_helper.rb # Test setup
312
+ ```
313
+
314
+ ## License
315
+
316
+ MIT License. See [LICENSE](LICENSE) for details.
317
+
318
+ The bundled yescrypt C implementation is based on work by Colin Percival and Alexander Peslyak, used under a permissive BSD-style license.
319
+
320
+ ## References
321
+
322
+ - [yescrypt - password hashing competition](https://www.openwall.com/yescrypt/)
323
+ - [yescrypt specification (PDF)](https://www.openwall.com/yescrypt/yescrypt-v2.pdf)
324
+ - [scrypt: A new key derivation function](https://www.tarsnap.com/scrypt.html) by Colin Percival
325
+ - [glibc yescrypt support (2.36+)](https://sourceware.org/glibc/wiki/Release/2.36)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ $CFLAGS << " -O2 -Wall -Wextra -std=c99"
6
+
7
+ create_makefile("yescrypt/yescrypt_ext")
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright (c) 2014 Alexander Peslyak
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted.
7
+ *
8
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
9
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11
+ * ARE DISCLAIMED.
12
+ */
13
+
14
+ #ifndef INSECURE_MEMZERO_H
15
+ #define INSECURE_MEMZERO_H
16
+
17
+ #include <string.h>
18
+
19
+ /*
20
+ * Securely zero memory - uses volatile pointer writes to prevent
21
+ * the compiler from optimizing away the clearing operation.
22
+ *
23
+ * Note: explicit_bzero/memset_s would be preferred but are not
24
+ * reliably available across platforms under strict C99 mode.
25
+ */
26
+ static void insecure_memzero(void *buf, size_t len)
27
+ {
28
+ volatile unsigned char *p = (volatile unsigned char *)buf;
29
+ while (len--) {
30
+ *p++ = 0;
31
+ }
32
+ }
33
+
34
+ #endif /* INSECURE_MEMZERO_H */
@@ -0,0 +1,256 @@
1
+ /*
2
+ * SHA-256 / HMAC-SHA256 / PBKDF2-HMAC-SHA256 implementation.
3
+ * Based on the public domain implementation by Colin Percival.
4
+ *
5
+ * Copyright (c) 2009 Colin Percival
6
+ * Copyright (c) 2013-2021 Alexander Peslyak
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted.
10
+ */
11
+
12
+ #include <string.h>
13
+ #include <stdint.h>
14
+
15
+ #include "sha256.h"
16
+ #include "insecure_memzero.h"
17
+
18
+ static inline uint32_t be32dec(const void *pp)
19
+ {
20
+ const uint8_t *p = (const uint8_t *)pp;
21
+ return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
22
+ ((uint32_t)p[2] << 8) | (uint32_t)p[3];
23
+ }
24
+
25
+ static inline void be32enc(void *pp, uint32_t x)
26
+ {
27
+ uint8_t *p = (uint8_t *)pp;
28
+ p[0] = (x >> 24) & 0xff;
29
+ p[1] = (x >> 16) & 0xff;
30
+ p[2] = (x >> 8) & 0xff;
31
+ p[3] = x & 0xff;
32
+ }
33
+
34
+ static inline void be64enc(void *pp, uint64_t x)
35
+ {
36
+ uint8_t *p = (uint8_t *)pp;
37
+ p[0] = (x >> 56) & 0xff;
38
+ p[1] = (x >> 48) & 0xff;
39
+ p[2] = (x >> 40) & 0xff;
40
+ p[3] = (x >> 32) & 0xff;
41
+ p[4] = (x >> 24) & 0xff;
42
+ p[5] = (x >> 16) & 0xff;
43
+ p[6] = (x >> 8) & 0xff;
44
+ p[7] = x & 0xff;
45
+ }
46
+
47
+ #define ROR32(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
48
+ #define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
49
+ #define Maj(x, y, z) (((x) & (y)) | ((z) & ((x) | (y))))
50
+ #define S0(x) (ROR32(x, 2) ^ ROR32(x, 13) ^ ROR32(x, 22))
51
+ #define S1(x) (ROR32(x, 6) ^ ROR32(x, 11) ^ ROR32(x, 25))
52
+ #define s0(x) (ROR32(x, 7) ^ ROR32(x, 18) ^ ((x) >> 3))
53
+ #define s1(x) (ROR32(x, 17) ^ ROR32(x, 19) ^ ((x) >> 10))
54
+
55
+ #define RND(a, b, c, d, e, f, g, h, k) \
56
+ h += S1(e) + Ch(e, f, g) + k; \
57
+ d += h; \
58
+ h += S0(a) + Maj(a, b, c);
59
+
60
+ #define RNDr(S, W, i, ii) \
61
+ RND(S[(64 - i) % 8], S[(65 - i) % 8], S[(66 - i) % 8], \
62
+ S[(67 - i) % 8], S[(68 - i) % 8], S[(69 - i) % 8], \
63
+ S[(70 - i) % 8], S[(71 - i) % 8], \
64
+ W[i + ii] + K[i + ii])
65
+
66
+ static const uint32_t K[64] = {
67
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
68
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
69
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
70
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
71
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
72
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
73
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
74
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
75
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
76
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
77
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
78
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
79
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
80
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
81
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
82
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
83
+ };
84
+
85
+ static void SHA256_Transform(uint32_t state[8], const uint8_t block[64])
86
+ {
87
+ uint32_t W[64];
88
+ uint32_t S[8];
89
+ int i;
90
+
91
+ for (i = 0; i < 16; i++)
92
+ W[i] = be32dec(&block[i * 4]);
93
+ for (i = 16; i < 64; i++)
94
+ W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
95
+
96
+ memcpy(S, state, sizeof(S));
97
+
98
+ for (i = 0; i < 64; i += 8) {
99
+ RNDr(S, W, 0, i);
100
+ RNDr(S, W, 1, i);
101
+ RNDr(S, W, 2, i);
102
+ RNDr(S, W, 3, i);
103
+ RNDr(S, W, 4, i);
104
+ RNDr(S, W, 5, i);
105
+ RNDr(S, W, 6, i);
106
+ RNDr(S, W, 7, i);
107
+ }
108
+
109
+ for (i = 0; i < 8; i++)
110
+ state[i] += S[i];
111
+
112
+ insecure_memzero(W, sizeof(W));
113
+ insecure_memzero(S, sizeof(S));
114
+ }
115
+
116
+ void SHA256_Init(SHA256_CTX *ctx)
117
+ {
118
+ ctx->count = 0;
119
+ ctx->state[0] = 0x6a09e667;
120
+ ctx->state[1] = 0xbb67ae85;
121
+ ctx->state[2] = 0x3c6ef372;
122
+ ctx->state[3] = 0xa54ff53a;
123
+ ctx->state[4] = 0x510e527f;
124
+ ctx->state[5] = 0x9b05688c;
125
+ ctx->state[6] = 0x1f83d9ab;
126
+ ctx->state[7] = 0x5be0cd19;
127
+ }
128
+
129
+ void SHA256_Update(SHA256_CTX *ctx, const void *in, size_t len)
130
+ {
131
+ uint64_t bitcount = ctx->count;
132
+ size_t r = (bitcount >> 3) & 0x3f;
133
+ const uint8_t *src = (const uint8_t *)in;
134
+
135
+ ctx->count = bitcount + ((uint64_t)len << 3);
136
+
137
+ if (len < 64 - r) {
138
+ memcpy(&ctx->buf[r], src, len);
139
+ return;
140
+ }
141
+
142
+ memcpy(&ctx->buf[r], src, 64 - r);
143
+ SHA256_Transform(ctx->state, ctx->buf);
144
+ src += 64 - r;
145
+ len -= 64 - r;
146
+
147
+ while (len >= 64) {
148
+ SHA256_Transform(ctx->state, src);
149
+ src += 64;
150
+ len -= 64;
151
+ }
152
+
153
+ memcpy(ctx->buf, src, len);
154
+ }
155
+
156
+ void SHA256_Final(uint8_t digest[32], SHA256_CTX *ctx)
157
+ {
158
+ uint8_t len[8];
159
+
160
+ be64enc(len, ctx->count);
161
+
162
+ SHA256_Update(ctx, "\x80", 1);
163
+ while ((ctx->count >> 3) % 64 != 56)
164
+ SHA256_Update(ctx, "\0", 1);
165
+ SHA256_Update(ctx, len, 8);
166
+
167
+ for (int i = 0; i < 8; i++)
168
+ be32enc(&digest[i * 4], ctx->state[i]);
169
+
170
+ insecure_memzero(ctx, sizeof(*ctx));
171
+ }
172
+
173
+ /* HMAC-SHA256 */
174
+ void HMAC_SHA256_Init(HMAC_SHA256_CTX *ctx, const void *key, size_t keylen)
175
+ {
176
+ uint8_t khash[32];
177
+ uint8_t pad[64];
178
+ size_t i;
179
+
180
+ if (keylen > 64) {
181
+ SHA256_CTX shactx;
182
+ SHA256_Init(&shactx);
183
+ SHA256_Update(&shactx, key, keylen);
184
+ SHA256_Final(khash, &shactx);
185
+ key = khash;
186
+ keylen = 32;
187
+ }
188
+
189
+ SHA256_Init(&ctx->ictx);
190
+ memset(pad, 0x36, 64);
191
+ for (i = 0; i < keylen; i++)
192
+ pad[i] ^= ((const uint8_t *)key)[i];
193
+ SHA256_Update(&ctx->ictx, pad, 64);
194
+
195
+ SHA256_Init(&ctx->octx);
196
+ memset(pad, 0x5c, 64);
197
+ for (i = 0; i < keylen; i++)
198
+ pad[i] ^= ((const uint8_t *)key)[i];
199
+ SHA256_Update(&ctx->octx, pad, 64);
200
+
201
+ insecure_memzero(khash, sizeof(khash));
202
+ insecure_memzero(pad, sizeof(pad));
203
+ }
204
+
205
+ void HMAC_SHA256_Update(HMAC_SHA256_CTX *ctx, const void *in, size_t len)
206
+ {
207
+ SHA256_Update(&ctx->ictx, in, len);
208
+ }
209
+
210
+ void HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX *ctx)
211
+ {
212
+ uint8_t ihash[32];
213
+ SHA256_Final(ihash, &ctx->ictx);
214
+ SHA256_Update(&ctx->octx, ihash, 32);
215
+ SHA256_Final(digest, &ctx->octx);
216
+ insecure_memzero(ihash, sizeof(ihash));
217
+ }
218
+
219
+ /* PBKDF2-HMAC-SHA256 */
220
+ void PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
221
+ const uint8_t *salt, size_t saltlen,
222
+ uint64_t c, uint8_t *buf, size_t dkLen)
223
+ {
224
+ HMAC_SHA256_CTX PShctx, hctx;
225
+ uint8_t U[32], T[32];
226
+ uint8_t ivec[4];
227
+ size_t i, j, k, clen;
228
+
229
+ HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
230
+ HMAC_SHA256_Update(&PShctx, salt, saltlen);
231
+
232
+ for (i = 0; i * 32 < dkLen; i++) {
233
+ be32enc(ivec, (uint32_t)(i + 1));
234
+ memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
235
+ HMAC_SHA256_Update(&hctx, ivec, 4);
236
+ HMAC_SHA256_Final(U, &hctx);
237
+ memcpy(T, U, 32);
238
+
239
+ for (j = 2; j <= c; j++) {
240
+ HMAC_SHA256_Init(&hctx, passwd, passwdlen);
241
+ HMAC_SHA256_Update(&hctx, U, 32);
242
+ HMAC_SHA256_Final(U, &hctx);
243
+ for (k = 0; k < 32; k++)
244
+ T[k] ^= U[k];
245
+ }
246
+
247
+ clen = dkLen - i * 32;
248
+ if (clen > 32)
249
+ clen = 32;
250
+ memcpy(&buf[i * 32], T, clen);
251
+ }
252
+
253
+ insecure_memzero(&PShctx, sizeof(PShctx));
254
+ insecure_memzero(U, sizeof(U));
255
+ insecure_memzero(T, sizeof(T));
256
+ }