openssl-custom 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
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