Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
ossl_kdf.c
Go to the documentation of this file.
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
237 {
238 #if 0
239  mOSSL = rb_define_module("OpenSSL");
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::SHA256.new
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 compare two
288  * values, the following could be used:
289  *
290  * def eql_time_cmp(a, b)
291  * unless a.length == b.length
292  * return false
293  * end
294  * cmp = b.bytes
295  * result = 0
296  * a.bytes.each_with_index {|c,i|
297  * result |= c ^ cmp[i]
298  * }
299  * result == 0
300  * end
301  *
302  * Please note that the premature return in case of differing lengths
303  * typically does not leak valuable information - when using PBKDF2, the
304  * length of the values to be compared is of fixed size.
305  */
306  mKDF = rb_define_module_under(mOSSL, "KDF");
307  /*
308  * Generic exception class raised if an error occurs in OpenSSL::KDF module.
309  */
310  eKDF = rb_define_class_under(mKDF, "KDFError", eOSSLError);
311 
312  rb_define_module_function(mKDF, "pbkdf2_hmac", kdf_pbkdf2_hmac, -1);
313 #if defined(HAVE_EVP_PBE_SCRYPT)
314  rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
315 #endif
316 #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
317  rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
318 #endif
319 }
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:1886
ID
unsigned long ID
Definition: ruby.h:103
LONG_MAX
#define LONG_MAX
Definition: ruby.h:220
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:797
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
SIZE_MAX
#define SIZE_MAX
Definition: ruby.h:307
NUM2LONG
#define NUM2LONG(x)
Definition: ruby.h:679
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_eArgError
VALUE rb_eArgError
Definition: error.c:925
rb_intern_const
#define rb_intern_const(str)
Definition: ruby.h:1879
RSTRING_LENINT
#define RSTRING_LENINT(str)
Definition: ruby.h:1017
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:772
uint64_t
unsigned long long uint64_t
Definition: sha2.h:102
ossl.h
NULL
#define NULL
Definition: _sdbm.c:101
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
mOSSL
VALUE mOSSL
Definition: ossl.c:231
ossl_raise
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:293
rb_str_set_len
void rb_str_set_len(VALUE, long)
Definition: string.c:2692
N
#define N
Definition: lgamma_r.c:20
rb_scan_args
#define rb_scan_args(argc, argvp, fmt,...)
Definition: rb_mjit_min_header-2.7.2.h:6368
rb_define_module_function
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1771
argv
char ** argv
Definition: ruby.c:223
StringValue
use StringValue() instead")))
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
argc
int argc
Definition: ruby.c:222
size_t
unsigned int size_t
Definition: rb_mjit_min_header-2.7.2.h:663
Init_ossl_kdf
void Init_ossl_kdf(void)
Definition: ossl_kdf.c:236
len
uint8_t len
Definition: escape.c:17
eOSSLError
VALUE eOSSLError
Definition: ossl.c:236
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:698
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
rb_str_new
#define rb_str_new(str, len)
Definition: rb_mjit_min_header-2.7.2.h:6112
ossl_evp_get_digestbyname
const EVP_MD * ossl_evp_get_digestbyname(VALUE obj)
Definition: ossl_digest.c:45
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:921
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005