zig_example 0.3.0 → 0.3.1
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/ext/mkmf.rb +2734 -0
- data/ext/openssl/openssl_missing.c +40 -0
- data/ext/openssl/openssl_missing.h +238 -0
- data/ext/openssl/ossl.c +1295 -0
- data/ext/openssl/ossl.h +201 -0
- data/ext/openssl/ossl_asn1.c +1891 -0
- data/ext/openssl/ossl_asn1.h +62 -0
- data/ext/openssl/ossl_bio.c +42 -0
- data/ext/openssl/ossl_bio.h +16 -0
- data/ext/openssl/ossl_bn.c +1344 -0
- data/ext/openssl/ossl_bn.h +26 -0
- data/ext/openssl/ossl_cipher.c +1074 -0
- data/ext/openssl/ossl_cipher.h +20 -0
- data/ext/openssl/ossl_config.c +460 -0
- data/ext/openssl/ossl_config.h +16 -0
- data/ext/openssl/ossl_digest.c +425 -0
- data/ext/openssl/ossl_digest.h +20 -0
- data/ext/openssl/ossl_engine.c +568 -0
- data/ext/openssl/ossl_engine.h +19 -0
- data/ext/openssl/ossl_hmac.c +310 -0
- data/ext/openssl/ossl_hmac.h +18 -0
- data/ext/openssl/ossl_kdf.c +311 -0
- data/ext/openssl/ossl_kdf.h +6 -0
- data/ext/openssl/ossl_ns_spki.c +405 -0
- data/ext/openssl/ossl_ns_spki.h +19 -0
- data/ext/openssl/ossl_ocsp.c +1965 -0
- data/ext/openssl/ossl_ocsp.h +23 -0
- data/ext/openssl/ossl_pkcs12.c +275 -0
- data/ext/openssl/ossl_pkcs12.h +13 -0
- data/ext/openssl/ossl_pkcs7.c +1081 -0
- data/ext/openssl/ossl_pkcs7.h +36 -0
- data/ext/openssl/ossl_pkey.c +1624 -0
- data/ext/openssl/ossl_pkey.h +204 -0
- data/ext/openssl/ossl_pkey_dh.c +440 -0
- data/ext/openssl/ossl_pkey_dsa.c +359 -0
- data/ext/openssl/ossl_pkey_ec.c +1655 -0
- data/ext/openssl/ossl_pkey_rsa.c +579 -0
- data/ext/openssl/ossl_rand.c +200 -0
- data/ext/openssl/ossl_rand.h +18 -0
- data/ext/openssl/ossl_ssl.c +3142 -0
- data/ext/openssl/ossl_ssl.h +36 -0
- data/ext/openssl/ossl_ssl_session.c +331 -0
- data/ext/openssl/ossl_ts.c +1539 -0
- data/ext/openssl/ossl_ts.h +16 -0
- data/ext/openssl/ossl_x509.c +256 -0
- data/ext/openssl/ossl_x509.h +115 -0
- data/ext/openssl/ossl_x509attr.c +324 -0
- data/ext/openssl/ossl_x509cert.c +1002 -0
- data/ext/openssl/ossl_x509crl.c +545 -0
- data/ext/openssl/ossl_x509ext.c +490 -0
- data/ext/openssl/ossl_x509name.c +597 -0
- data/ext/openssl/ossl_x509req.c +444 -0
- data/ext/openssl/ossl_x509revoked.c +300 -0
- data/ext/openssl/ossl_x509store.c +986 -0
- data/ext/zigrb_100doors/build.zig +0 -12
- data/ext/zigrb_100doors/extconf.rb +2 -19
- data/ext/zigrb_ackermann/build.zig +0 -12
- data/ext/zigrb_ackermann/extconf.rb +2 -19
- data/ext/zigrb_lucas_lehmer/build.zig +0 -12
- data/ext/zigrb_lucas_lehmer/extconf.rb +2 -19
- data/lib/zig_example/version.rb +1 -1
- metadata +56 -2
@@ -0,0 +1,310 @@
|
|
1
|
+
/*
|
2
|
+
* 'OpenSSL for Ruby' project
|
3
|
+
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
4
|
+
* All rights reserved.
|
5
|
+
*/
|
6
|
+
/*
|
7
|
+
* This program is licensed under the same licence as Ruby.
|
8
|
+
* (See the file 'LICENCE'.)
|
9
|
+
*/
|
10
|
+
#include "ossl.h"
|
11
|
+
|
12
|
+
#define NewHMAC(klass) \
|
13
|
+
TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0)
|
14
|
+
#define GetHMAC(obj, ctx) do { \
|
15
|
+
TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \
|
16
|
+
if (!(ctx)) { \
|
17
|
+
ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
|
18
|
+
} \
|
19
|
+
} while (0)
|
20
|
+
|
21
|
+
/*
|
22
|
+
* Classes
|
23
|
+
*/
|
24
|
+
VALUE cHMAC;
|
25
|
+
VALUE eHMACError;
|
26
|
+
|
27
|
+
/*
|
28
|
+
* Public
|
29
|
+
*/
|
30
|
+
|
31
|
+
/*
|
32
|
+
* Private
|
33
|
+
*/
|
34
|
+
static void
|
35
|
+
ossl_hmac_free(void *ctx)
|
36
|
+
{
|
37
|
+
EVP_MD_CTX_free(ctx);
|
38
|
+
}
|
39
|
+
|
40
|
+
static const rb_data_type_t ossl_hmac_type = {
|
41
|
+
"OpenSSL/HMAC",
|
42
|
+
{
|
43
|
+
0, ossl_hmac_free,
|
44
|
+
},
|
45
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
|
46
|
+
};
|
47
|
+
|
48
|
+
static VALUE
|
49
|
+
ossl_hmac_alloc(VALUE klass)
|
50
|
+
{
|
51
|
+
VALUE obj;
|
52
|
+
EVP_MD_CTX *ctx;
|
53
|
+
|
54
|
+
obj = NewHMAC(klass);
|
55
|
+
ctx = EVP_MD_CTX_new();
|
56
|
+
if (!ctx)
|
57
|
+
ossl_raise(eHMACError, "EVP_MD_CTX");
|
58
|
+
RTYPEDDATA_DATA(obj) = ctx;
|
59
|
+
|
60
|
+
return obj;
|
61
|
+
}
|
62
|
+
|
63
|
+
|
64
|
+
/*
|
65
|
+
* call-seq:
|
66
|
+
* HMAC.new(key, digest) -> hmac
|
67
|
+
*
|
68
|
+
* Returns an instance of OpenSSL::HMAC set with the key and digest
|
69
|
+
* algorithm to be used. The instance represents the initial state of
|
70
|
+
* the message authentication code before any data has been processed.
|
71
|
+
* To process data with it, use the instance method #update with your
|
72
|
+
* data as an argument.
|
73
|
+
*
|
74
|
+
* === Example
|
75
|
+
*
|
76
|
+
* key = 'key'
|
77
|
+
* instance = OpenSSL::HMAC.new(key, 'SHA1')
|
78
|
+
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
|
79
|
+
* instance.class
|
80
|
+
* #=> OpenSSL::HMAC
|
81
|
+
*
|
82
|
+
* === A note about comparisons
|
83
|
+
*
|
84
|
+
* Two instances can be securely compared with #== in constant time:
|
85
|
+
*
|
86
|
+
* other_instance = OpenSSL::HMAC.new('key', 'SHA1')
|
87
|
+
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
|
88
|
+
* instance == other_instance
|
89
|
+
* #=> true
|
90
|
+
*
|
91
|
+
*/
|
92
|
+
static VALUE
|
93
|
+
ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
|
94
|
+
{
|
95
|
+
EVP_MD_CTX *ctx;
|
96
|
+
EVP_PKEY *pkey;
|
97
|
+
|
98
|
+
GetHMAC(self, ctx);
|
99
|
+
StringValue(key);
|
100
|
+
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
|
101
|
+
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
|
102
|
+
(unsigned char *)RSTRING_PTR(key),
|
103
|
+
RSTRING_LENINT(key));
|
104
|
+
if (!pkey)
|
105
|
+
ossl_raise(eHMACError, "EVP_PKEY_new_raw_private_key");
|
106
|
+
#else
|
107
|
+
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
|
108
|
+
(unsigned char *)RSTRING_PTR(key),
|
109
|
+
RSTRING_LENINT(key));
|
110
|
+
if (!pkey)
|
111
|
+
ossl_raise(eHMACError, "EVP_PKEY_new_mac_key");
|
112
|
+
#endif
|
113
|
+
if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest),
|
114
|
+
NULL, pkey) != 1) {
|
115
|
+
EVP_PKEY_free(pkey);
|
116
|
+
ossl_raise(eHMACError, "EVP_DigestSignInit");
|
117
|
+
}
|
118
|
+
/* Decrement reference counter; EVP_MD_CTX still keeps it */
|
119
|
+
EVP_PKEY_free(pkey);
|
120
|
+
|
121
|
+
return self;
|
122
|
+
}
|
123
|
+
|
124
|
+
static VALUE
|
125
|
+
ossl_hmac_copy(VALUE self, VALUE other)
|
126
|
+
{
|
127
|
+
EVP_MD_CTX *ctx1, *ctx2;
|
128
|
+
|
129
|
+
rb_check_frozen(self);
|
130
|
+
if (self == other) return self;
|
131
|
+
|
132
|
+
GetHMAC(self, ctx1);
|
133
|
+
GetHMAC(other, ctx2);
|
134
|
+
if (EVP_MD_CTX_copy(ctx1, ctx2) != 1)
|
135
|
+
ossl_raise(eHMACError, "EVP_MD_CTX_copy");
|
136
|
+
return self;
|
137
|
+
}
|
138
|
+
|
139
|
+
/*
|
140
|
+
* call-seq:
|
141
|
+
* hmac.update(string) -> self
|
142
|
+
*
|
143
|
+
* Returns _hmac_ updated with the message to be authenticated.
|
144
|
+
* Can be called repeatedly with chunks of the message.
|
145
|
+
*
|
146
|
+
* === Example
|
147
|
+
*
|
148
|
+
* first_chunk = 'The quick brown fox jumps '
|
149
|
+
* second_chunk = 'over the lazy dog'
|
150
|
+
*
|
151
|
+
* instance.update(first_chunk)
|
152
|
+
* #=> 5b9a8038a65d571076d97fe783989e52278a492a
|
153
|
+
* instance.update(second_chunk)
|
154
|
+
* #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
|
155
|
+
*
|
156
|
+
*/
|
157
|
+
static VALUE
|
158
|
+
ossl_hmac_update(VALUE self, VALUE data)
|
159
|
+
{
|
160
|
+
EVP_MD_CTX *ctx;
|
161
|
+
|
162
|
+
StringValue(data);
|
163
|
+
GetHMAC(self, ctx);
|
164
|
+
if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
|
165
|
+
ossl_raise(eHMACError, "EVP_DigestSignUpdate");
|
166
|
+
|
167
|
+
return self;
|
168
|
+
}
|
169
|
+
|
170
|
+
/*
|
171
|
+
* call-seq:
|
172
|
+
* hmac.digest -> string
|
173
|
+
*
|
174
|
+
* Returns the authentication code an instance represents as a binary string.
|
175
|
+
*
|
176
|
+
* === Example
|
177
|
+
* instance = OpenSSL::HMAC.new('key', 'SHA1')
|
178
|
+
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
|
179
|
+
* instance.digest
|
180
|
+
* #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?"
|
181
|
+
*/
|
182
|
+
static VALUE
|
183
|
+
ossl_hmac_digest(VALUE self)
|
184
|
+
{
|
185
|
+
EVP_MD_CTX *ctx;
|
186
|
+
size_t buf_len = EVP_MAX_MD_SIZE;
|
187
|
+
VALUE ret;
|
188
|
+
|
189
|
+
GetHMAC(self, ctx);
|
190
|
+
ret = rb_str_new(NULL, EVP_MAX_MD_SIZE);
|
191
|
+
if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(ret),
|
192
|
+
&buf_len) != 1)
|
193
|
+
ossl_raise(eHMACError, "EVP_DigestSignFinal");
|
194
|
+
rb_str_set_len(ret, (long)buf_len);
|
195
|
+
|
196
|
+
return ret;
|
197
|
+
}
|
198
|
+
|
199
|
+
/*
|
200
|
+
* call-seq:
|
201
|
+
* hmac.hexdigest -> string
|
202
|
+
*
|
203
|
+
* Returns the authentication code an instance represents as a hex-encoded
|
204
|
+
* string.
|
205
|
+
*/
|
206
|
+
static VALUE
|
207
|
+
ossl_hmac_hexdigest(VALUE self)
|
208
|
+
{
|
209
|
+
EVP_MD_CTX *ctx;
|
210
|
+
unsigned char buf[EVP_MAX_MD_SIZE];
|
211
|
+
size_t buf_len = EVP_MAX_MD_SIZE;
|
212
|
+
VALUE ret;
|
213
|
+
|
214
|
+
GetHMAC(self, ctx);
|
215
|
+
if (EVP_DigestSignFinal(ctx, buf, &buf_len) != 1)
|
216
|
+
ossl_raise(eHMACError, "EVP_DigestSignFinal");
|
217
|
+
ret = rb_str_new(NULL, buf_len * 2);
|
218
|
+
ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
|
219
|
+
|
220
|
+
return ret;
|
221
|
+
}
|
222
|
+
|
223
|
+
/*
|
224
|
+
* call-seq:
|
225
|
+
* hmac.reset -> self
|
226
|
+
*
|
227
|
+
* Returns _hmac_ as it was when it was first initialized, with all processed
|
228
|
+
* data cleared from it.
|
229
|
+
*
|
230
|
+
* === Example
|
231
|
+
*
|
232
|
+
* data = "The quick brown fox jumps over the lazy dog"
|
233
|
+
* instance = OpenSSL::HMAC.new('key', 'SHA1')
|
234
|
+
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
|
235
|
+
*
|
236
|
+
* instance.update(data)
|
237
|
+
* #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
|
238
|
+
* instance.reset
|
239
|
+
* #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
|
240
|
+
*
|
241
|
+
*/
|
242
|
+
static VALUE
|
243
|
+
ossl_hmac_reset(VALUE self)
|
244
|
+
{
|
245
|
+
EVP_MD_CTX *ctx;
|
246
|
+
EVP_PKEY *pkey;
|
247
|
+
|
248
|
+
GetHMAC(self, ctx);
|
249
|
+
pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx));
|
250
|
+
if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1)
|
251
|
+
ossl_raise(eHMACError, "EVP_DigestSignInit");
|
252
|
+
|
253
|
+
return self;
|
254
|
+
}
|
255
|
+
|
256
|
+
/*
|
257
|
+
* INIT
|
258
|
+
*/
|
259
|
+
void
|
260
|
+
Init_ossl_hmac(void)
|
261
|
+
{
|
262
|
+
#if 0
|
263
|
+
mOSSL = rb_define_module("OpenSSL");
|
264
|
+
eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
|
265
|
+
#endif
|
266
|
+
|
267
|
+
/*
|
268
|
+
* Document-class: OpenSSL::HMAC
|
269
|
+
*
|
270
|
+
* OpenSSL::HMAC allows computing Hash-based Message Authentication Code
|
271
|
+
* (HMAC). It is a type of message authentication code (MAC) involving a
|
272
|
+
* hash function in combination with a key. HMAC can be used to verify the
|
273
|
+
* integrity of a message as well as the authenticity.
|
274
|
+
*
|
275
|
+
* OpenSSL::HMAC has a similar interface to OpenSSL::Digest.
|
276
|
+
*
|
277
|
+
* === HMAC-SHA256 using one-shot interface
|
278
|
+
*
|
279
|
+
* key = "key"
|
280
|
+
* data = "message-to-be-authenticated"
|
281
|
+
* mac = OpenSSL::HMAC.hexdigest("SHA256", key, data)
|
282
|
+
* #=> "cddb0db23f469c8bf072b21fd837149bd6ace9ab771cceef14c9e517cc93282e"
|
283
|
+
*
|
284
|
+
* === HMAC-SHA256 using incremental interface
|
285
|
+
*
|
286
|
+
* data1 = File.binread("file1")
|
287
|
+
* data2 = File.binread("file2")
|
288
|
+
* key = "key"
|
289
|
+
* hmac = OpenSSL::HMAC.new(key, 'SHA256')
|
290
|
+
* hmac << data1
|
291
|
+
* hmac << data2
|
292
|
+
* mac = hmac.digest
|
293
|
+
*/
|
294
|
+
eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError);
|
295
|
+
|
296
|
+
cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
|
297
|
+
|
298
|
+
rb_define_alloc_func(cHMAC, ossl_hmac_alloc);
|
299
|
+
|
300
|
+
rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
|
301
|
+
rb_define_method(cHMAC, "initialize_copy", ossl_hmac_copy, 1);
|
302
|
+
|
303
|
+
rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0);
|
304
|
+
rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
|
305
|
+
rb_define_alias(cHMAC, "<<", "update");
|
306
|
+
rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0);
|
307
|
+
rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
|
308
|
+
rb_define_alias(cHMAC, "inspect", "hexdigest");
|
309
|
+
rb_define_alias(cHMAC, "to_s", "hexdigest");
|
310
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
/*
|
2
|
+
* 'OpenSSL for Ruby' project
|
3
|
+
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
4
|
+
* All rights reserved.
|
5
|
+
*/
|
6
|
+
/*
|
7
|
+
* This program is licensed under the same licence as Ruby.
|
8
|
+
* (See the file 'LICENCE'.)
|
9
|
+
*/
|
10
|
+
#if !defined(_OSSL_HMAC_H_)
|
11
|
+
#define _OSSL_HMAC_H_
|
12
|
+
|
13
|
+
extern VALUE cHMAC;
|
14
|
+
extern VALUE eHMACError;
|
15
|
+
|
16
|
+
void Init_ossl_hmac(void);
|
17
|
+
|
18
|
+
#endif /* _OSSL_HMAC_H_ */
|
@@ -0,0 +1,311 @@
|
|
1
|
+
/*
|
2
|
+
* Ruby/OpenSSL Project
|
3
|
+
* Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
|
4
|
+
*/
|
5
|
+
#include "ossl.h"
|
6
|
+
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 6, 0)
|
7
|
+
# include <openssl/kdf.h>
|
8
|
+
#endif
|
9
|
+
|
10
|
+
static VALUE mKDF, eKDF;
|
11
|
+
|
12
|
+
/*
|
13
|
+
* call-seq:
|
14
|
+
* KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString
|
15
|
+
*
|
16
|
+
* PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in combination
|
17
|
+
* with HMAC. Takes _pass_, _salt_ and _iterations_, and then derives a key
|
18
|
+
* of _length_ bytes.
|
19
|
+
*
|
20
|
+
* For more information about PBKDF2, see RFC 2898 Section 5.2
|
21
|
+
* (https://tools.ietf.org/html/rfc2898#section-5.2).
|
22
|
+
*
|
23
|
+
* === Parameters
|
24
|
+
* pass :: The passphrase.
|
25
|
+
* salt :: The salt. Salts prevent attacks based on dictionaries of common
|
26
|
+
* passwords and attacks based on rainbow tables. It is a public
|
27
|
+
* value that can be safely stored along with the password (e.g.
|
28
|
+
* if the derived value is used for password storage).
|
29
|
+
* iterations :: The iteration count. This provides the ability to tune the
|
30
|
+
* algorithm. It is better to use the highest count possible for
|
31
|
+
* the maximum resistance to brute-force attacks.
|
32
|
+
* length :: The desired length of the derived key in octets.
|
33
|
+
* hash :: The hash algorithm used with HMAC for the PRF. May be a String
|
34
|
+
* representing the algorithm name, or an instance of
|
35
|
+
* OpenSSL::Digest.
|
36
|
+
*/
|
37
|
+
static VALUE
|
38
|
+
kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
|
39
|
+
{
|
40
|
+
VALUE pass, salt, opts, kwargs[4], str;
|
41
|
+
static ID kwargs_ids[4];
|
42
|
+
int iters, len;
|
43
|
+
const EVP_MD *md;
|
44
|
+
|
45
|
+
if (!kwargs_ids[0]) {
|
46
|
+
kwargs_ids[0] = rb_intern_const("salt");
|
47
|
+
kwargs_ids[1] = rb_intern_const("iterations");
|
48
|
+
kwargs_ids[2] = rb_intern_const("length");
|
49
|
+
kwargs_ids[3] = rb_intern_const("hash");
|
50
|
+
}
|
51
|
+
rb_scan_args(argc, argv, "1:", &pass, &opts);
|
52
|
+
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
|
53
|
+
|
54
|
+
StringValue(pass);
|
55
|
+
salt = StringValue(kwargs[0]);
|
56
|
+
iters = NUM2INT(kwargs[1]);
|
57
|
+
len = NUM2INT(kwargs[2]);
|
58
|
+
md = ossl_evp_get_digestbyname(kwargs[3]);
|
59
|
+
|
60
|
+
str = rb_str_new(0, len);
|
61
|
+
if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
|
62
|
+
(unsigned char *)RSTRING_PTR(salt),
|
63
|
+
RSTRING_LENINT(salt), iters, md, len,
|
64
|
+
(unsigned char *)RSTRING_PTR(str)))
|
65
|
+
ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
|
66
|
+
|
67
|
+
return str;
|
68
|
+
}
|
69
|
+
|
70
|
+
#if defined(HAVE_EVP_PBE_SCRYPT)
|
71
|
+
/*
|
72
|
+
* call-seq:
|
73
|
+
* KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString
|
74
|
+
*
|
75
|
+
* Derives a key from _pass_ using given parameters with the scrypt
|
76
|
+
* password-based key derivation function. The result can be used for password
|
77
|
+
* storage.
|
78
|
+
*
|
79
|
+
* scrypt is designed to be memory-hard and more secure against brute-force
|
80
|
+
* attacks using custom hardwares than alternative KDFs such as PBKDF2 or
|
81
|
+
* bcrypt.
|
82
|
+
*
|
83
|
+
* The keyword arguments _N_, _r_ and _p_ can be used to tune scrypt. RFC 7914
|
84
|
+
* (published on 2016-08, https://tools.ietf.org/html/rfc7914#section-2) states
|
85
|
+
* that using values r=8 and p=1 appears to yield good results.
|
86
|
+
*
|
87
|
+
* See RFC 7914 (https://tools.ietf.org/html/rfc7914) for more information.
|
88
|
+
*
|
89
|
+
* === Parameters
|
90
|
+
* pass :: Passphrase.
|
91
|
+
* salt :: Salt.
|
92
|
+
* N :: CPU/memory cost parameter. This must be a power of 2.
|
93
|
+
* r :: Block size parameter.
|
94
|
+
* p :: Parallelization parameter.
|
95
|
+
* length :: Length in octets of the derived key.
|
96
|
+
*
|
97
|
+
* === Example
|
98
|
+
* pass = "password"
|
99
|
+
* salt = SecureRandom.random_bytes(16)
|
100
|
+
* dk = OpenSSL::KDF.scrypt(pass, salt: salt, N: 2**14, r: 8, p: 1, length: 32)
|
101
|
+
* p dk #=> "\xDA\xE4\xE2...\x7F\xA1\x01T"
|
102
|
+
*/
|
103
|
+
static VALUE
|
104
|
+
kdf_scrypt(int argc, VALUE *argv, VALUE self)
|
105
|
+
{
|
106
|
+
VALUE pass, salt, opts, kwargs[5], str;
|
107
|
+
static ID kwargs_ids[5];
|
108
|
+
size_t len;
|
109
|
+
uint64_t N, r, p, maxmem;
|
110
|
+
|
111
|
+
if (!kwargs_ids[0]) {
|
112
|
+
kwargs_ids[0] = rb_intern_const("salt");
|
113
|
+
kwargs_ids[1] = rb_intern_const("N");
|
114
|
+
kwargs_ids[2] = rb_intern_const("r");
|
115
|
+
kwargs_ids[3] = rb_intern_const("p");
|
116
|
+
kwargs_ids[4] = rb_intern_const("length");
|
117
|
+
}
|
118
|
+
rb_scan_args(argc, argv, "1:", &pass, &opts);
|
119
|
+
rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);
|
120
|
+
|
121
|
+
StringValue(pass);
|
122
|
+
salt = StringValue(kwargs[0]);
|
123
|
+
N = NUM2UINT64T(kwargs[1]);
|
124
|
+
r = NUM2UINT64T(kwargs[2]);
|
125
|
+
p = NUM2UINT64T(kwargs[3]);
|
126
|
+
len = NUM2LONG(kwargs[4]);
|
127
|
+
/*
|
128
|
+
* OpenSSL uses 32MB by default (if zero is specified), which is too small.
|
129
|
+
* Let's not limit memory consumption but just let malloc() fail inside
|
130
|
+
* OpenSSL. The amount is controllable by other parameters.
|
131
|
+
*/
|
132
|
+
maxmem = SIZE_MAX;
|
133
|
+
|
134
|
+
str = rb_str_new(0, len);
|
135
|
+
if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
|
136
|
+
(unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
|
137
|
+
N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
|
138
|
+
ossl_raise(eKDF, "EVP_PBE_scrypt");
|
139
|
+
|
140
|
+
return str;
|
141
|
+
}
|
142
|
+
#endif
|
143
|
+
|
144
|
+
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 6, 0)
|
145
|
+
/*
|
146
|
+
* call-seq:
|
147
|
+
* KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String
|
148
|
+
*
|
149
|
+
* HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in
|
150
|
+
* {RFC 5869}[https://tools.ietf.org/html/rfc5869].
|
151
|
+
*
|
152
|
+
* New in OpenSSL 1.1.0.
|
153
|
+
*
|
154
|
+
* === Parameters
|
155
|
+
* _ikm_::
|
156
|
+
* The input keying material.
|
157
|
+
* _salt_::
|
158
|
+
* The salt.
|
159
|
+
* _info_::
|
160
|
+
* The context and application specific information.
|
161
|
+
* _length_::
|
162
|
+
* The output length in octets. Must be <= <tt>255 * HashLen</tt>, where
|
163
|
+
* HashLen is the length of the hash function output in octets.
|
164
|
+
* _hash_::
|
165
|
+
* The hash function.
|
166
|
+
*
|
167
|
+
* === Example
|
168
|
+
* # The values from https://datatracker.ietf.org/doc/html/rfc5869#appendix-A.1
|
169
|
+
* ikm = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*")
|
170
|
+
* salt = ["000102030405060708090a0b0c"].pack("H*")
|
171
|
+
* info = ["f0f1f2f3f4f5f6f7f8f9"].pack("H*")
|
172
|
+
* p OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: 42, hash: "SHA256").unpack1("H*")
|
173
|
+
* # => "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
|
174
|
+
*/
|
175
|
+
static VALUE
|
176
|
+
kdf_hkdf(int argc, VALUE *argv, VALUE self)
|
177
|
+
{
|
178
|
+
VALUE ikm, salt, info, opts, kwargs[4], str;
|
179
|
+
static ID kwargs_ids[4];
|
180
|
+
int saltlen, ikmlen, infolen;
|
181
|
+
size_t len;
|
182
|
+
const EVP_MD *md;
|
183
|
+
EVP_PKEY_CTX *pctx;
|
184
|
+
|
185
|
+
if (!kwargs_ids[0]) {
|
186
|
+
kwargs_ids[0] = rb_intern_const("salt");
|
187
|
+
kwargs_ids[1] = rb_intern_const("info");
|
188
|
+
kwargs_ids[2] = rb_intern_const("length");
|
189
|
+
kwargs_ids[3] = rb_intern_const("hash");
|
190
|
+
}
|
191
|
+
rb_scan_args(argc, argv, "1:", &ikm, &opts);
|
192
|
+
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
|
193
|
+
|
194
|
+
StringValue(ikm);
|
195
|
+
ikmlen = RSTRING_LENINT(ikm);
|
196
|
+
salt = StringValue(kwargs[0]);
|
197
|
+
saltlen = RSTRING_LENINT(salt);
|
198
|
+
info = StringValue(kwargs[1]);
|
199
|
+
infolen = RSTRING_LENINT(info);
|
200
|
+
len = (size_t)NUM2LONG(kwargs[2]);
|
201
|
+
if (len > LONG_MAX)
|
202
|
+
rb_raise(rb_eArgError, "length must be non-negative");
|
203
|
+
md = ossl_evp_get_digestbyname(kwargs[3]);
|
204
|
+
|
205
|
+
str = rb_str_new(NULL, (long)len);
|
206
|
+
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
207
|
+
if (!pctx)
|
208
|
+
ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
|
209
|
+
if (EVP_PKEY_derive_init(pctx) <= 0) {
|
210
|
+
EVP_PKEY_CTX_free(pctx);
|
211
|
+
ossl_raise(eKDF, "EVP_PKEY_derive_init");
|
212
|
+
}
|
213
|
+
if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
|
214
|
+
EVP_PKEY_CTX_free(pctx);
|
215
|
+
ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
|
216
|
+
}
|
217
|
+
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
|
218
|
+
saltlen) <= 0) {
|
219
|
+
EVP_PKEY_CTX_free(pctx);
|
220
|
+
ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
|
221
|
+
}
|
222
|
+
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
|
223
|
+
ikmlen) <= 0) {
|
224
|
+
EVP_PKEY_CTX_free(pctx);
|
225
|
+
ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
|
226
|
+
}
|
227
|
+
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
|
228
|
+
infolen) <= 0) {
|
229
|
+
EVP_PKEY_CTX_free(pctx);
|
230
|
+
ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
|
231
|
+
}
|
232
|
+
if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
|
233
|
+
EVP_PKEY_CTX_free(pctx);
|
234
|
+
ossl_raise(eKDF, "EVP_PKEY_derive");
|
235
|
+
}
|
236
|
+
rb_str_set_len(str, (long)len);
|
237
|
+
EVP_PKEY_CTX_free(pctx);
|
238
|
+
|
239
|
+
return str;
|
240
|
+
}
|
241
|
+
#endif
|
242
|
+
|
243
|
+
void
|
244
|
+
Init_ossl_kdf(void)
|
245
|
+
{
|
246
|
+
#if 0
|
247
|
+
mOSSL = rb_define_module("OpenSSL");
|
248
|
+
eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
|
249
|
+
#endif
|
250
|
+
|
251
|
+
/*
|
252
|
+
* Document-module: OpenSSL::KDF
|
253
|
+
*
|
254
|
+
* Provides functionality of various KDFs (key derivation function).
|
255
|
+
*
|
256
|
+
* KDF is typically used for securely deriving arbitrary length symmetric
|
257
|
+
* keys to be used with an OpenSSL::Cipher from passwords. Another use case
|
258
|
+
* is for storing passwords: Due to the ability to tweak the effort of
|
259
|
+
* computation by increasing the iteration count, computation can be slowed
|
260
|
+
* down artificially in order to render possible attacks infeasible.
|
261
|
+
*
|
262
|
+
* Currently, OpenSSL::KDF provides implementations for the following KDF:
|
263
|
+
*
|
264
|
+
* * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
|
265
|
+
* combination with HMAC
|
266
|
+
* * scrypt
|
267
|
+
* * HKDF
|
268
|
+
*
|
269
|
+
* == Examples
|
270
|
+
* === Generating a 128 bit key for a Cipher (e.g. AES)
|
271
|
+
* pass = "secret"
|
272
|
+
* salt = OpenSSL::Random.random_bytes(16)
|
273
|
+
* iter = 20_000
|
274
|
+
* key_len = 16
|
275
|
+
* key = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
|
276
|
+
* length: key_len, hash: "sha1")
|
277
|
+
*
|
278
|
+
* === Storing Passwords
|
279
|
+
* pass = "secret"
|
280
|
+
* # store this with the generated value
|
281
|
+
* salt = OpenSSL::Random.random_bytes(16)
|
282
|
+
* iter = 20_000
|
283
|
+
* hash = OpenSSL::Digest.new('SHA256')
|
284
|
+
* len = hash.digest_length
|
285
|
+
* # the final value to be stored
|
286
|
+
* value = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
|
287
|
+
* length: len, hash: hash)
|
288
|
+
*
|
289
|
+
* == Important Note on Checking Passwords
|
290
|
+
* When comparing passwords provided by the user with previously stored
|
291
|
+
* values, a common mistake made is comparing the two values using "==".
|
292
|
+
* Typically, "==" short-circuits on evaluation, and is therefore
|
293
|
+
* vulnerable to timing attacks. The proper way is to use a method that
|
294
|
+
* always takes the same amount of time when comparing two values, thus
|
295
|
+
* not leaking any information to potential attackers. To do this, use
|
296
|
+
* +OpenSSL.fixed_length_secure_compare+.
|
297
|
+
*/
|
298
|
+
mKDF = rb_define_module_under(mOSSL, "KDF");
|
299
|
+
/*
|
300
|
+
* Generic exception class raised if an error occurs in OpenSSL::KDF module.
|
301
|
+
*/
|
302
|
+
eKDF = rb_define_class_under(mKDF, "KDFError", eOSSLError);
|
303
|
+
|
304
|
+
rb_define_module_function(mKDF, "pbkdf2_hmac", kdf_pbkdf2_hmac, -1);
|
305
|
+
#if defined(HAVE_EVP_PBE_SCRYPT)
|
306
|
+
rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
|
307
|
+
#endif
|
308
|
+
#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_LIBRESSL_PREREQ(3, 6, 0)
|
309
|
+
rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
|
310
|
+
#endif
|
311
|
+
}
|