openssl-custom 2.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/BSDL +22 -0
- data/CONTRIBUTING.md +132 -0
- data/History.md +485 -0
- data/LICENSE.txt +56 -0
- data/README.md +66 -0
- data/ext/openssl/extconf.rb +190 -0
- data/ext/openssl/openssl_missing.c +106 -0
- data/ext/openssl/openssl_missing.h +257 -0
- data/ext/openssl/ossl.c +1282 -0
- data/ext/openssl/ossl.h +181 -0
- data/ext/openssl/ossl_asn1.c +1878 -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 +1270 -0
- data/ext/openssl/ossl_bn.h +26 -0
- data/ext/openssl/ossl_cipher.c +1075 -0
- data/ext/openssl/ossl_cipher.h +20 -0
- data/ext/openssl/ossl_config.c +89 -0
- data/ext/openssl/ossl_config.h +19 -0
- data/ext/openssl/ossl_digest.c +425 -0
- data/ext/openssl/ossl_digest.h +20 -0
- data/ext/openssl/ossl_engine.c +567 -0
- data/ext/openssl/ossl_engine.h +19 -0
- data/ext/openssl/ossl_hmac.c +389 -0
- data/ext/openssl/ossl_hmac.h +18 -0
- data/ext/openssl/ossl_kdf.c +303 -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 +2013 -0
- data/ext/openssl/ossl_ocsp.h +23 -0
- data/ext/openssl/ossl_pkcs12.c +257 -0
- data/ext/openssl/ossl_pkcs12.h +13 -0
- data/ext/openssl/ossl_pkcs7.c +1098 -0
- data/ext/openssl/ossl_pkcs7.h +36 -0
- data/ext/openssl/ossl_pkey.c +673 -0
- data/ext/openssl/ossl_pkey.h +241 -0
- data/ext/openssl/ossl_pkey_dh.c +650 -0
- data/ext/openssl/ossl_pkey_dsa.c +664 -0
- data/ext/openssl/ossl_pkey_ec.c +1827 -0
- data/ext/openssl/ossl_pkey_rsa.c +966 -0
- data/ext/openssl/ossl_rand.c +200 -0
- data/ext/openssl/ossl_rand.h +18 -0
- data/ext/openssl/ossl_ssl.c +3080 -0
- data/ext/openssl/ossl_ssl.h +36 -0
- data/ext/openssl/ossl_ssl_session.c +332 -0
- data/ext/openssl/ossl_ts.c +1524 -0
- data/ext/openssl/ossl_ts.h +16 -0
- data/ext/openssl/ossl_x509.c +262 -0
- data/ext/openssl/ossl_x509.h +115 -0
- data/ext/openssl/ossl_x509attr.c +324 -0
- data/ext/openssl/ossl_x509cert.c +846 -0
- data/ext/openssl/ossl_x509crl.c +542 -0
- data/ext/openssl/ossl_x509ext.c +491 -0
- data/ext/openssl/ossl_x509name.c +590 -0
- data/ext/openssl/ossl_x509req.c +441 -0
- data/ext/openssl/ossl_x509revoked.c +300 -0
- data/ext/openssl/ossl_x509store.c +902 -0
- data/ext/openssl/ruby_missing.h +24 -0
- data/lib/openssl/bn.rb +40 -0
- data/lib/openssl/buffering.rb +478 -0
- data/lib/openssl/cipher.rb +67 -0
- data/lib/openssl/config.rb +501 -0
- data/lib/openssl/digest.rb +73 -0
- data/lib/openssl/hmac.rb +13 -0
- data/lib/openssl/marshal.rb +30 -0
- data/lib/openssl/pkcs5.rb +22 -0
- data/lib/openssl/pkey.rb +42 -0
- data/lib/openssl/ssl.rb +542 -0
- data/lib/openssl/version.rb +5 -0
- data/lib/openssl/x509.rb +369 -0
- data/lib/openssl.rb +38 -0
- 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
|
+
}
|