Ruby  2.5.0dev(2017-10-22revision60238)
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 
7 static VALUE mKDF, eKDF;
8 
9 /*
10  * call-seq:
11  * KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString
12  *
13  * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in combination
14  * with HMAC. Takes _pass_, _salt_ and _iterations_, and then derives a key
15  * of _length_ bytes.
16  *
17  * For more information about PBKDF2, see RFC 2898 Section 5.2
18  * (https://tools.ietf.org/html/rfc2898#section-5.2).
19  *
20  * === Parameters
21  * pass :: The passphrase.
22  * salt :: The salt. Salts prevent attacks based on dictionaries of common
23  * passwords and attacks based on rainbow tables. It is a public
24  * value that can be safely stored along with the password (e.g.
25  * if the derived value is used for password storage).
26  * iterations :: The iteration count. This provides the ability to tune the
27  * algorithm. It is better to use the highest count possible for
28  * the maximum resistance to brute-force attacks.
29  * length :: The desired length of the derived key in octets.
30  * hash :: The hash algorithm used with HMAC for the PRF. May be a String
31  * representing the algorithm name, or an instance of
32  * OpenSSL::Digest.
33  */
34 static VALUE
35 kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
36 {
37  VALUE pass, salt, opts, kwargs[4], str;
38  static ID kwargs_ids[4];
39  int iters, len;
40  const EVP_MD *md;
41 
42  if (!kwargs_ids[0]) {
43  kwargs_ids[0] = rb_intern_const("salt");
44  kwargs_ids[1] = rb_intern_const("iterations");
45  kwargs_ids[2] = rb_intern_const("length");
46  kwargs_ids[3] = rb_intern_const("hash");
47  }
48  rb_scan_args(argc, argv, "1:", &pass, &opts);
49  rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
50 
51  StringValue(pass);
52  salt = StringValue(kwargs[0]);
53  iters = NUM2INT(kwargs[1]);
54  len = NUM2INT(kwargs[2]);
55  md = ossl_evp_get_digestbyname(kwargs[3]);
56 
57  str = rb_str_new(0, len);
58  if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
59  (unsigned char *)RSTRING_PTR(salt),
60  RSTRING_LENINT(salt), iters, md, len,
61  (unsigned char *)RSTRING_PTR(str)))
62  ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
63 
64  return str;
65 }
66 
67 #if defined(HAVE_EVP_PBE_SCRYPT)
68 /*
69  * call-seq:
70  * KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString
71  *
72  * Derives a key from _pass_ using given parameters with the scrypt
73  * password-based key derivation function. The result can be used for password
74  * storage.
75  *
76  * scrypt is designed to be memory-hard and more secure against brute-force
77  * attacks using custom hardwares than alternative KDFs such as PBKDF2 or
78  * bcrypt.
79  *
80  * The keyword arguments _N_, _r_ and _p_ can be used to tune scrypt. RFC 7914
81  * (published on 2016-08, https://tools.ietf.org/html/rfc7914#section-2) states
82  * that using values r=8 and p=1 appears to yield good results.
83  *
84  * See RFC 7914 (https://tools.ietf.org/html/rfc7914) for more information.
85  *
86  * === Parameters
87  * pass :: Passphrase.
88  * salt :: Salt.
89  * N :: CPU/memory cost parameter. This must be a power of 2.
90  * r :: Block size parameter.
91  * p :: Parallelization parameter.
92  * length :: Length in octets of the derived key.
93  *
94  * === Example
95  * pass = "password"
96  * salt = SecureRandom.random_bytes(16)
97  * dk = OpenSSL::KDF.scrypt(pass, salt: salt, N: 2**14, r: 8, p: 1, length: 32)
98  * p dk #=> "\xDA\xE4\xE2...\x7F\xA1\x01T"
99  */
100 static VALUE
101 kdf_scrypt(int argc, VALUE *argv, VALUE self)
102 {
103  VALUE pass, salt, opts, kwargs[5], str;
104  static ID kwargs_ids[5];
105  size_t len;
106  uint64_t N, r, p, maxmem;
107 
108  if (!kwargs_ids[0]) {
109  kwargs_ids[0] = rb_intern_const("salt");
110  kwargs_ids[1] = rb_intern_const("N");
111  kwargs_ids[2] = rb_intern_const("r");
112  kwargs_ids[3] = rb_intern_const("p");
113  kwargs_ids[4] = rb_intern_const("length");
114  }
115  rb_scan_args(argc, argv, "1:", &pass, &opts);
116  rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);
117 
118  StringValue(pass);
119  salt = StringValue(kwargs[0]);
120  N = NUM2UINT64T(kwargs[1]);
121  r = NUM2UINT64T(kwargs[2]);
122  p = NUM2UINT64T(kwargs[3]);
123  len = NUM2LONG(kwargs[4]);
124  /*
125  * OpenSSL uses 32MB by default (if zero is specified), which is too small.
126  * Let's not limit memory consumption but just let malloc() fail inside
127  * OpenSSL. The amount is controllable by other parameters.
128  */
129  maxmem = SIZE_MAX;
130 
131  str = rb_str_new(0, len);
132  if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
133  (unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
134  N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
135  ossl_raise(eKDF, "EVP_PBE_scrypt");
136 
137  return str;
138 }
139 #endif
140 
141 void
143 {
144 #if 0
145  mOSSL = rb_define_module("OpenSSL");
147 #endif
148 
149  /*
150  * Document-module: OpenSSL::KDF
151  *
152  * Provides functionality of various KDFs (key derivation function).
153  *
154  * KDF is typically used for securely deriving arbitrary length symmetric
155  * keys to be used with an OpenSSL::Cipher from passwords. Another use case
156  * is for storing passwords: Due to the ability to tweak the effort of
157  * computation by increasing the iteration count, computation can be slowed
158  * down artificially in order to render possible attacks infeasible.
159  *
160  * Currently, OpenSSL::KDF provides implementations for the following KDF:
161  *
162  * * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
163  * combination with HMAC
164  * * scrypt
165  *
166  * == Examples
167  * === Generating a 128 bit key for a Cipher (e.g. AES)
168  * pass = "secret"
169  * salt = OpenSSL::Random.random_bytes(16)
170  * iter = 20_000
171  * key_len = 16
172  * key = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
173  * length: key_len, hash: "sha1")
174  *
175  * === Storing Passwords
176  * pass = "secret"
177  * # store this with the generated value
178  * salt = OpenSSL::Random.random_bytes(16)
179  * iter = 20_000
180  * hash = OpenSSL::Digest::SHA256.new
181  * len = hash.digest_length
182  * # the final value to be stored
183  * value = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
184  * length: len, hash: hash)
185  *
186  * == Important Note on Checking Passwords
187  * When comparing passwords provided by the user with previously stored
188  * values, a common mistake made is comparing the two values using "==".
189  * Typically, "==" short-circuits on evaluation, and is therefore
190  * vulnerable to timing attacks. The proper way is to use a method that
191  * always takes the same amount of time when comparing two values, thus
192  * not leaking any information to potential attackers. To compare two
193  * values, the following could be used:
194  *
195  * def eql_time_cmp(a, b)
196  * unless a.length == b.length
197  * return false
198  * end
199  * cmp = b.bytes
200  * result = 0
201  * a.bytes.each_with_index {|c,i|
202  * result |= c ^ cmp[i]
203  * }
204  * result == 0
205  * end
206  *
207  * Please note that the premature return in case of differing lengths
208  * typically does not leak valuable information - when using PBKDF2, the
209  * length of the values to be compared is of fixed size.
210  */
211  mKDF = rb_define_module_under(mOSSL, "KDF");
212  /*
213  * Generic exception class raised if an error occurs in OpenSSL::KDF module.
214  */
215  eKDF = rb_define_class_under(mKDF, "KDFError", eOSSLError);
216 
217  rb_define_module_function(mKDF, "pbkdf2_hmac", kdf_pbkdf2_hmac, -1);
218 #if defined(HAVE_EVP_PBE_SCRYPT)
219  rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
220 #endif
221 }
VALUE mOSSL
Definition: ossl.c:231
void Init_ossl_kdf(void)
Definition: ossl_kdf.c:142
#define NUM2INT(x)
Definition: ruby.h:684
#define N
Definition: lgamma_r.c:20
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:1847
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:693
unsigned long long uint64_t
Definition: sha2.h:102
VALUE eOSSLError
Definition: ossl.c:236
int argc
Definition: ruby.c:187
#define RSTRING_LEN(str)
Definition: ruby.h:971
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1731
const EVP_MD * ossl_evp_get_digestbyname(VALUE obj)
Definition: ossl_digest.c:45
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1908
unsigned long ID
Definition: ruby.h:86
VALUE rb_eStandardError
Definition: error.c:799
unsigned long VALUE
Definition: ruby.h:85
register unsigned int len
Definition: zonetab.h:51
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:790
#define RSTRING_PTR(str)
Definition: ruby.h:975
#define SIZE_MAX
Definition: ruby.h:276
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:293
#define RSTRING_LENINT(str)
Definition: ruby.h:983
#define rb_intern_const(str)
Definition: ruby.h:1777
VALUE rb_define_module(const char *name)
Definition: class.c:768
#define NUM2LONG(x)
Definition: ruby.h:648
char ** argv
Definition: ruby.c:188
#define StringValue(v)
Definition: ruby.h:569
VALUE rb_str_new(const char *, long)
Definition: string.c:737