openssl-custom 2.2.2

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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/BSDL +22 -0
  3. data/CONTRIBUTING.md +132 -0
  4. data/History.md +485 -0
  5. data/LICENSE.txt +56 -0
  6. data/README.md +66 -0
  7. data/ext/openssl/extconf.rb +190 -0
  8. data/ext/openssl/openssl_missing.c +106 -0
  9. data/ext/openssl/openssl_missing.h +257 -0
  10. data/ext/openssl/ossl.c +1282 -0
  11. data/ext/openssl/ossl.h +181 -0
  12. data/ext/openssl/ossl_asn1.c +1878 -0
  13. data/ext/openssl/ossl_asn1.h +62 -0
  14. data/ext/openssl/ossl_bio.c +42 -0
  15. data/ext/openssl/ossl_bio.h +16 -0
  16. data/ext/openssl/ossl_bn.c +1270 -0
  17. data/ext/openssl/ossl_bn.h +26 -0
  18. data/ext/openssl/ossl_cipher.c +1075 -0
  19. data/ext/openssl/ossl_cipher.h +20 -0
  20. data/ext/openssl/ossl_config.c +89 -0
  21. data/ext/openssl/ossl_config.h +19 -0
  22. data/ext/openssl/ossl_digest.c +425 -0
  23. data/ext/openssl/ossl_digest.h +20 -0
  24. data/ext/openssl/ossl_engine.c +567 -0
  25. data/ext/openssl/ossl_engine.h +19 -0
  26. data/ext/openssl/ossl_hmac.c +389 -0
  27. data/ext/openssl/ossl_hmac.h +18 -0
  28. data/ext/openssl/ossl_kdf.c +303 -0
  29. data/ext/openssl/ossl_kdf.h +6 -0
  30. data/ext/openssl/ossl_ns_spki.c +405 -0
  31. data/ext/openssl/ossl_ns_spki.h +19 -0
  32. data/ext/openssl/ossl_ocsp.c +2013 -0
  33. data/ext/openssl/ossl_ocsp.h +23 -0
  34. data/ext/openssl/ossl_pkcs12.c +257 -0
  35. data/ext/openssl/ossl_pkcs12.h +13 -0
  36. data/ext/openssl/ossl_pkcs7.c +1098 -0
  37. data/ext/openssl/ossl_pkcs7.h +36 -0
  38. data/ext/openssl/ossl_pkey.c +673 -0
  39. data/ext/openssl/ossl_pkey.h +241 -0
  40. data/ext/openssl/ossl_pkey_dh.c +650 -0
  41. data/ext/openssl/ossl_pkey_dsa.c +664 -0
  42. data/ext/openssl/ossl_pkey_ec.c +1827 -0
  43. data/ext/openssl/ossl_pkey_rsa.c +966 -0
  44. data/ext/openssl/ossl_rand.c +200 -0
  45. data/ext/openssl/ossl_rand.h +18 -0
  46. data/ext/openssl/ossl_ssl.c +3080 -0
  47. data/ext/openssl/ossl_ssl.h +36 -0
  48. data/ext/openssl/ossl_ssl_session.c +332 -0
  49. data/ext/openssl/ossl_ts.c +1524 -0
  50. data/ext/openssl/ossl_ts.h +16 -0
  51. data/ext/openssl/ossl_x509.c +262 -0
  52. data/ext/openssl/ossl_x509.h +115 -0
  53. data/ext/openssl/ossl_x509attr.c +324 -0
  54. data/ext/openssl/ossl_x509cert.c +846 -0
  55. data/ext/openssl/ossl_x509crl.c +542 -0
  56. data/ext/openssl/ossl_x509ext.c +491 -0
  57. data/ext/openssl/ossl_x509name.c +590 -0
  58. data/ext/openssl/ossl_x509req.c +441 -0
  59. data/ext/openssl/ossl_x509revoked.c +300 -0
  60. data/ext/openssl/ossl_x509store.c +902 -0
  61. data/ext/openssl/ruby_missing.h +24 -0
  62. data/lib/openssl/bn.rb +40 -0
  63. data/lib/openssl/buffering.rb +478 -0
  64. data/lib/openssl/cipher.rb +67 -0
  65. data/lib/openssl/config.rb +501 -0
  66. data/lib/openssl/digest.rb +73 -0
  67. data/lib/openssl/hmac.rb +13 -0
  68. data/lib/openssl/marshal.rb +30 -0
  69. data/lib/openssl/pkcs5.rb +22 -0
  70. data/lib/openssl/pkey.rb +42 -0
  71. data/lib/openssl/ssl.rb +542 -0
  72. data/lib/openssl/version.rb +5 -0
  73. data/lib/openssl/x509.rb +369 -0
  74. data/lib/openssl.rb +38 -0
  75. metadata +196 -0
@@ -0,0 +1,389 @@
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(OPENSSL_NO_HMAC)
11
+
12
+ #include "ossl.h"
13
+
14
+ #define NewHMAC(klass) \
15
+ TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0)
16
+ #define GetHMAC(obj, ctx) do { \
17
+ TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \
18
+ if (!(ctx)) { \
19
+ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
20
+ } \
21
+ } while (0)
22
+
23
+ /*
24
+ * Classes
25
+ */
26
+ VALUE cHMAC;
27
+ VALUE eHMACError;
28
+
29
+ /*
30
+ * Public
31
+ */
32
+
33
+ /*
34
+ * Private
35
+ */
36
+ static void
37
+ ossl_hmac_free(void *ctx)
38
+ {
39
+ HMAC_CTX_free(ctx);
40
+ }
41
+
42
+ static const rb_data_type_t ossl_hmac_type = {
43
+ "OpenSSL/HMAC",
44
+ {
45
+ 0, ossl_hmac_free,
46
+ },
47
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
48
+ };
49
+
50
+ static VALUE
51
+ ossl_hmac_alloc(VALUE klass)
52
+ {
53
+ VALUE obj;
54
+ HMAC_CTX *ctx;
55
+
56
+ obj = NewHMAC(klass);
57
+ ctx = HMAC_CTX_new();
58
+ if (!ctx)
59
+ ossl_raise(eHMACError, NULL);
60
+ RTYPEDDATA_DATA(obj) = ctx;
61
+
62
+ return obj;
63
+ }
64
+
65
+
66
+ /*
67
+ * call-seq:
68
+ * HMAC.new(key, digest) -> hmac
69
+ *
70
+ * Returns an instance of OpenSSL::HMAC set with the key and digest
71
+ * algorithm to be used. The instance represents the initial state of
72
+ * the message authentication code before any data has been processed.
73
+ * To process data with it, use the instance method #update with your
74
+ * data as an argument.
75
+ *
76
+ * === Example
77
+ *
78
+ * key = 'key'
79
+ * digest = OpenSSL::Digest.new('sha1')
80
+ * instance = OpenSSL::HMAC.new(key, digest)
81
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
82
+ * instance.class
83
+ * #=> OpenSSL::HMAC
84
+ *
85
+ * === A note about comparisons
86
+ *
87
+ * Two instances can be securely compared with #== in constant time:
88
+ *
89
+ * other_instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
90
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
91
+ * instance == other_instance
92
+ * #=> true
93
+ *
94
+ */
95
+ static VALUE
96
+ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
97
+ {
98
+ HMAC_CTX *ctx;
99
+
100
+ StringValue(key);
101
+ GetHMAC(self, ctx);
102
+ HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key),
103
+ ossl_evp_get_digestbyname(digest), NULL);
104
+
105
+ return self;
106
+ }
107
+
108
+ static VALUE
109
+ ossl_hmac_copy(VALUE self, VALUE other)
110
+ {
111
+ HMAC_CTX *ctx1, *ctx2;
112
+
113
+ rb_check_frozen(self);
114
+ if (self == other) return self;
115
+
116
+ GetHMAC(self, ctx1);
117
+ GetHMAC(other, ctx2);
118
+
119
+ if (!HMAC_CTX_copy(ctx1, ctx2))
120
+ ossl_raise(eHMACError, "HMAC_CTX_copy");
121
+ return self;
122
+ }
123
+
124
+ /*
125
+ * call-seq:
126
+ * hmac.update(string) -> self
127
+ *
128
+ * Returns _hmac_ updated with the message to be authenticated.
129
+ * Can be called repeatedly with chunks of the message.
130
+ *
131
+ * === Example
132
+ *
133
+ * first_chunk = 'The quick brown fox jumps '
134
+ * second_chunk = 'over the lazy dog'
135
+ *
136
+ * instance.update(first_chunk)
137
+ * #=> 5b9a8038a65d571076d97fe783989e52278a492a
138
+ * instance.update(second_chunk)
139
+ * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
140
+ *
141
+ */
142
+ static VALUE
143
+ ossl_hmac_update(VALUE self, VALUE data)
144
+ {
145
+ HMAC_CTX *ctx;
146
+
147
+ StringValue(data);
148
+ GetHMAC(self, ctx);
149
+ HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data));
150
+
151
+ return self;
152
+ }
153
+
154
+ static void
155
+ hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len)
156
+ {
157
+ HMAC_CTX *final;
158
+
159
+ final = HMAC_CTX_new();
160
+ if (!final)
161
+ ossl_raise(eHMACError, "HMAC_CTX_new");
162
+
163
+ if (!HMAC_CTX_copy(final, ctx)) {
164
+ HMAC_CTX_free(final);
165
+ ossl_raise(eHMACError, "HMAC_CTX_copy");
166
+ }
167
+
168
+ HMAC_Final(final, buf, buf_len);
169
+ HMAC_CTX_free(final);
170
+ }
171
+
172
+ /*
173
+ * call-seq:
174
+ * hmac.digest -> string
175
+ *
176
+ * Returns the authentication code an instance represents as a binary string.
177
+ *
178
+ * === Example
179
+ * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
180
+ * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
181
+ * instance.digest
182
+ * #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?"
183
+ */
184
+ static VALUE
185
+ ossl_hmac_digest(VALUE self)
186
+ {
187
+ HMAC_CTX *ctx;
188
+ unsigned int buf_len;
189
+ VALUE ret;
190
+
191
+ GetHMAC(self, ctx);
192
+ ret = rb_str_new(NULL, EVP_MAX_MD_SIZE);
193
+ hmac_final(ctx, (unsigned char *)RSTRING_PTR(ret), &buf_len);
194
+ assert(buf_len <= EVP_MAX_MD_SIZE);
195
+ rb_str_set_len(ret, buf_len);
196
+
197
+ return ret;
198
+ }
199
+
200
+ /*
201
+ * call-seq:
202
+ * hmac.hexdigest -> string
203
+ *
204
+ * Returns the authentication code an instance represents as a hex-encoded
205
+ * string.
206
+ */
207
+ static VALUE
208
+ ossl_hmac_hexdigest(VALUE self)
209
+ {
210
+ HMAC_CTX *ctx;
211
+ unsigned char buf[EVP_MAX_MD_SIZE];
212
+ unsigned int buf_len;
213
+ VALUE ret;
214
+
215
+ GetHMAC(self, ctx);
216
+ hmac_final(ctx, buf, &buf_len);
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', OpenSSL::Digest.new('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
+ HMAC_CTX *ctx;
246
+
247
+ GetHMAC(self, ctx);
248
+ HMAC_Init_ex(ctx, NULL, 0, NULL, NULL);
249
+
250
+ return self;
251
+ }
252
+
253
+ /*
254
+ * call-seq:
255
+ * HMAC.digest(digest, key, data) -> aString
256
+ *
257
+ * Returns the authentication code as a binary string. The _digest_ parameter
258
+ * specifies the digest algorithm to use. This may be a String representing
259
+ * the algorithm name or an instance of OpenSSL::Digest.
260
+ *
261
+ * === Example
262
+ *
263
+ * key = 'key'
264
+ * data = 'The quick brown fox jumps over the lazy dog'
265
+ *
266
+ * hmac = OpenSSL::HMAC.digest('sha1', key, data)
267
+ * #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9"
268
+ *
269
+ */
270
+ static VALUE
271
+ ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
272
+ {
273
+ unsigned char *buf;
274
+ unsigned int buf_len;
275
+
276
+ StringValue(key);
277
+ StringValue(data);
278
+ buf = HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key),
279
+ RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data),
280
+ RSTRING_LEN(data), NULL, &buf_len);
281
+
282
+ return rb_str_new((const char *)buf, buf_len);
283
+ }
284
+
285
+ /*
286
+ * call-seq:
287
+ * HMAC.hexdigest(digest, key, data) -> aString
288
+ *
289
+ * Returns the authentication code as a hex-encoded string. The _digest_
290
+ * parameter specifies the digest algorithm to use. This may be a String
291
+ * representing the algorithm name or an instance of OpenSSL::Digest.
292
+ *
293
+ * === Example
294
+ *
295
+ * key = 'key'
296
+ * data = 'The quick brown fox jumps over the lazy dog'
297
+ *
298
+ * hmac = OpenSSL::HMAC.hexdigest('sha1', key, data)
299
+ * #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
300
+ *
301
+ */
302
+ static VALUE
303
+ ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
304
+ {
305
+ unsigned char buf[EVP_MAX_MD_SIZE];
306
+ unsigned int buf_len;
307
+ VALUE ret;
308
+
309
+ StringValue(key);
310
+ StringValue(data);
311
+
312
+ if (!HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key),
313
+ RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data),
314
+ RSTRING_LEN(data), buf, &buf_len))
315
+ ossl_raise(eHMACError, "HMAC");
316
+
317
+ ret = rb_str_new(NULL, buf_len * 2);
318
+ ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
319
+
320
+ return ret;
321
+ }
322
+
323
+ /*
324
+ * INIT
325
+ */
326
+ void
327
+ Init_ossl_hmac(void)
328
+ {
329
+ #if 0
330
+ mOSSL = rb_define_module("OpenSSL");
331
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
332
+ #endif
333
+
334
+ /*
335
+ * Document-class: OpenSSL::HMAC
336
+ *
337
+ * OpenSSL::HMAC allows computing Hash-based Message Authentication Code
338
+ * (HMAC). It is a type of message authentication code (MAC) involving a
339
+ * hash function in combination with a key. HMAC can be used to verify the
340
+ * integrity of a message as well as the authenticity.
341
+ *
342
+ * OpenSSL::HMAC has a similar interface to OpenSSL::Digest.
343
+ *
344
+ * === HMAC-SHA256 using one-shot interface
345
+ *
346
+ * key = "key"
347
+ * data = "message-to-be-authenticated"
348
+ * mac = OpenSSL::HMAC.hexdigest("SHA256", key, data)
349
+ * #=> "cddb0db23f469c8bf072b21fd837149bd6ace9ab771cceef14c9e517cc93282e"
350
+ *
351
+ * === HMAC-SHA256 using incremental interface
352
+ *
353
+ * data1 = File.read("file1")
354
+ * data2 = File.read("file2")
355
+ * key = "key"
356
+ * digest = OpenSSL::Digest.new('SHA256')
357
+ * hmac = OpenSSL::HMAC.new(key, digest)
358
+ * hmac << data1
359
+ * hmac << data2
360
+ * mac = hmac.digest
361
+ */
362
+ eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError);
363
+
364
+ cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
365
+
366
+ rb_define_alloc_func(cHMAC, ossl_hmac_alloc);
367
+ rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3);
368
+ rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3);
369
+
370
+ rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
371
+ rb_define_method(cHMAC, "initialize_copy", ossl_hmac_copy, 1);
372
+
373
+ rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0);
374
+ rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
375
+ rb_define_alias(cHMAC, "<<", "update");
376
+ rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0);
377
+ rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
378
+ rb_define_alias(cHMAC, "inspect", "hexdigest");
379
+ rb_define_alias(cHMAC, "to_s", "hexdigest");
380
+ }
381
+
382
+ #else /* NO_HMAC */
383
+ # warning >>> OpenSSL is compiled without HMAC support <<<
384
+ void
385
+ Init_ossl_hmac(void)
386
+ {
387
+ rb_warning("HMAC is not available: OpenSSL is compiled without HMAC.");
388
+ }
389
+ #endif /* NO_HMAC */
@@ -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,303 @@
1
+ /*
2
+ * Ruby/OpenSSL Project
3
+ * Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
4
+ */
5
+ #include "ossl.h"
6
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
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 OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
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
+ static VALUE
168
+ kdf_hkdf(int argc, VALUE *argv, VALUE self)
169
+ {
170
+ VALUE ikm, salt, info, opts, kwargs[4], str;
171
+ static ID kwargs_ids[4];
172
+ int saltlen, ikmlen, infolen;
173
+ size_t len;
174
+ const EVP_MD *md;
175
+ EVP_PKEY_CTX *pctx;
176
+
177
+ if (!kwargs_ids[0]) {
178
+ kwargs_ids[0] = rb_intern_const("salt");
179
+ kwargs_ids[1] = rb_intern_const("info");
180
+ kwargs_ids[2] = rb_intern_const("length");
181
+ kwargs_ids[3] = rb_intern_const("hash");
182
+ }
183
+ rb_scan_args(argc, argv, "1:", &ikm, &opts);
184
+ rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
185
+
186
+ StringValue(ikm);
187
+ ikmlen = RSTRING_LENINT(ikm);
188
+ salt = StringValue(kwargs[0]);
189
+ saltlen = RSTRING_LENINT(salt);
190
+ info = StringValue(kwargs[1]);
191
+ infolen = RSTRING_LENINT(info);
192
+ len = (size_t)NUM2LONG(kwargs[2]);
193
+ if (len > LONG_MAX)
194
+ rb_raise(rb_eArgError, "length must be non-negative");
195
+ md = ossl_evp_get_digestbyname(kwargs[3]);
196
+
197
+ str = rb_str_new(NULL, (long)len);
198
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
199
+ if (!pctx)
200
+ ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
201
+ if (EVP_PKEY_derive_init(pctx) <= 0) {
202
+ EVP_PKEY_CTX_free(pctx);
203
+ ossl_raise(eKDF, "EVP_PKEY_derive_init");
204
+ }
205
+ if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
206
+ EVP_PKEY_CTX_free(pctx);
207
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
208
+ }
209
+ if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
210
+ saltlen) <= 0) {
211
+ EVP_PKEY_CTX_free(pctx);
212
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
213
+ }
214
+ if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
215
+ ikmlen) <= 0) {
216
+ EVP_PKEY_CTX_free(pctx);
217
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
218
+ }
219
+ if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
220
+ infolen) <= 0) {
221
+ EVP_PKEY_CTX_free(pctx);
222
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
223
+ }
224
+ if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
225
+ EVP_PKEY_CTX_free(pctx);
226
+ ossl_raise(eKDF, "EVP_PKEY_derive");
227
+ }
228
+ rb_str_set_len(str, (long)len);
229
+ EVP_PKEY_CTX_free(pctx);
230
+
231
+ return str;
232
+ }
233
+ #endif
234
+
235
+ void
236
+ Init_ossl_kdf(void)
237
+ {
238
+ #if 0
239
+ mOSSL = rb_define_module("OpenSSL");
240
+ eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
241
+ #endif
242
+
243
+ /*
244
+ * Document-module: OpenSSL::KDF
245
+ *
246
+ * Provides functionality of various KDFs (key derivation function).
247
+ *
248
+ * KDF is typically used for securely deriving arbitrary length symmetric
249
+ * keys to be used with an OpenSSL::Cipher from passwords. Another use case
250
+ * is for storing passwords: Due to the ability to tweak the effort of
251
+ * computation by increasing the iteration count, computation can be slowed
252
+ * down artificially in order to render possible attacks infeasible.
253
+ *
254
+ * Currently, OpenSSL::KDF provides implementations for the following KDF:
255
+ *
256
+ * * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
257
+ * combination with HMAC
258
+ * * scrypt
259
+ * * HKDF
260
+ *
261
+ * == Examples
262
+ * === Generating a 128 bit key for a Cipher (e.g. AES)
263
+ * pass = "secret"
264
+ * salt = OpenSSL::Random.random_bytes(16)
265
+ * iter = 20_000
266
+ * key_len = 16
267
+ * key = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
268
+ * length: key_len, hash: "sha1")
269
+ *
270
+ * === Storing Passwords
271
+ * pass = "secret"
272
+ * # store this with the generated value
273
+ * salt = OpenSSL::Random.random_bytes(16)
274
+ * iter = 20_000
275
+ * hash = OpenSSL::Digest.new('SHA256')
276
+ * len = hash.digest_length
277
+ * # the final value to be stored
278
+ * value = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
279
+ * length: len, hash: hash)
280
+ *
281
+ * == Important Note on Checking Passwords
282
+ * When comparing passwords provided by the user with previously stored
283
+ * values, a common mistake made is comparing the two values using "==".
284
+ * Typically, "==" short-circuits on evaluation, and is therefore
285
+ * vulnerable to timing attacks. The proper way is to use a method that
286
+ * always takes the same amount of time when comparing two values, thus
287
+ * not leaking any information to potential attackers. To do this, use
288
+ * +OpenSSL.fixed_length_secure_compare+.
289
+ */
290
+ mKDF = rb_define_module_under(mOSSL, "KDF");
291
+ /*
292
+ * Generic exception class raised if an error occurs in OpenSSL::KDF module.
293
+ */
294
+ eKDF = rb_define_class_under(mKDF, "KDFError", eOSSLError);
295
+
296
+ rb_define_module_function(mKDF, "pbkdf2_hmac", kdf_pbkdf2_hmac, -1);
297
+ #if defined(HAVE_EVP_PBE_SCRYPT)
298
+ rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
299
+ #endif
300
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
301
+ rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
302
+ #endif
303
+ }
@@ -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