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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/ext/mkmf.rb +2734 -0
  3. data/ext/openssl/openssl_missing.c +40 -0
  4. data/ext/openssl/openssl_missing.h +238 -0
  5. data/ext/openssl/ossl.c +1295 -0
  6. data/ext/openssl/ossl.h +201 -0
  7. data/ext/openssl/ossl_asn1.c +1891 -0
  8. data/ext/openssl/ossl_asn1.h +62 -0
  9. data/ext/openssl/ossl_bio.c +42 -0
  10. data/ext/openssl/ossl_bio.h +16 -0
  11. data/ext/openssl/ossl_bn.c +1344 -0
  12. data/ext/openssl/ossl_bn.h +26 -0
  13. data/ext/openssl/ossl_cipher.c +1074 -0
  14. data/ext/openssl/ossl_cipher.h +20 -0
  15. data/ext/openssl/ossl_config.c +460 -0
  16. data/ext/openssl/ossl_config.h +16 -0
  17. data/ext/openssl/ossl_digest.c +425 -0
  18. data/ext/openssl/ossl_digest.h +20 -0
  19. data/ext/openssl/ossl_engine.c +568 -0
  20. data/ext/openssl/ossl_engine.h +19 -0
  21. data/ext/openssl/ossl_hmac.c +310 -0
  22. data/ext/openssl/ossl_hmac.h +18 -0
  23. data/ext/openssl/ossl_kdf.c +311 -0
  24. data/ext/openssl/ossl_kdf.h +6 -0
  25. data/ext/openssl/ossl_ns_spki.c +405 -0
  26. data/ext/openssl/ossl_ns_spki.h +19 -0
  27. data/ext/openssl/ossl_ocsp.c +1965 -0
  28. data/ext/openssl/ossl_ocsp.h +23 -0
  29. data/ext/openssl/ossl_pkcs12.c +275 -0
  30. data/ext/openssl/ossl_pkcs12.h +13 -0
  31. data/ext/openssl/ossl_pkcs7.c +1081 -0
  32. data/ext/openssl/ossl_pkcs7.h +36 -0
  33. data/ext/openssl/ossl_pkey.c +1624 -0
  34. data/ext/openssl/ossl_pkey.h +204 -0
  35. data/ext/openssl/ossl_pkey_dh.c +440 -0
  36. data/ext/openssl/ossl_pkey_dsa.c +359 -0
  37. data/ext/openssl/ossl_pkey_ec.c +1655 -0
  38. data/ext/openssl/ossl_pkey_rsa.c +579 -0
  39. data/ext/openssl/ossl_rand.c +200 -0
  40. data/ext/openssl/ossl_rand.h +18 -0
  41. data/ext/openssl/ossl_ssl.c +3142 -0
  42. data/ext/openssl/ossl_ssl.h +36 -0
  43. data/ext/openssl/ossl_ssl_session.c +331 -0
  44. data/ext/openssl/ossl_ts.c +1539 -0
  45. data/ext/openssl/ossl_ts.h +16 -0
  46. data/ext/openssl/ossl_x509.c +256 -0
  47. data/ext/openssl/ossl_x509.h +115 -0
  48. data/ext/openssl/ossl_x509attr.c +324 -0
  49. data/ext/openssl/ossl_x509cert.c +1002 -0
  50. data/ext/openssl/ossl_x509crl.c +545 -0
  51. data/ext/openssl/ossl_x509ext.c +490 -0
  52. data/ext/openssl/ossl_x509name.c +597 -0
  53. data/ext/openssl/ossl_x509req.c +444 -0
  54. data/ext/openssl/ossl_x509revoked.c +300 -0
  55. data/ext/openssl/ossl_x509store.c +986 -0
  56. data/ext/zigrb_100doors/build.zig +0 -12
  57. data/ext/zigrb_100doors/extconf.rb +2 -19
  58. data/ext/zigrb_ackermann/build.zig +0 -12
  59. data/ext/zigrb_ackermann/extconf.rb +2 -19
  60. data/ext/zigrb_lucas_lehmer/build.zig +53 -0
  61. data/ext/zigrb_lucas_lehmer/extconf.rb +3 -0
  62. data/ext/zigrb_lucas_lehmer/src/lucas_lehmer.c +60 -0
  63. data/ext/zigrb_lucas_lehmer/src/lucas_lehmer.h +1 -0
  64. data/ext/zigrb_lucas_lehmer/src/wrapper.zig +42 -0
  65. data/lib/zig_example/version.rb +1 -1
  66. data/lib/zig_example.rb +1 -0
  67. 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
+ }
@@ -0,0 +1,6 @@
1
+ #if !defined(OSSL_KDF_H)
2
+ #define OSSL_KDF_H
3
+
4
+ void Init_ossl_kdf(void);
5
+
6
+ #endif