zig_example 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 +53 -0
- data/ext/zigrb_lucas_lehmer/extconf.rb +3 -0
- data/ext/zigrb_lucas_lehmer/src/lucas_lehmer.c +60 -0
- data/ext/zigrb_lucas_lehmer/src/lucas_lehmer.h +1 -0
- data/ext/zigrb_lucas_lehmer/src/wrapper.zig +42 -0
- data/lib/zig_example/version.rb +1 -1
- data/lib/zig_example.rb +1 -0
- metadata +63 -3
@@ -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
|
+
}
|