Botan  2.8.0
Crypto and TLS for C++11
pbes2.cpp
Go to the documentation of this file.
1 /*
2 * PKCS #5 PBES2
3 * (C) 1999-2008,2014 Jack Lloyd
4 * (C) 2018 Ribose Inc
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/pbes2.h>
10 #include <botan/cipher_mode.h>
11 #include <botan/pbkdf.h>
12 #include <botan/der_enc.h>
13 #include <botan/ber_dec.h>
14 #include <botan/parsing.h>
15 #include <botan/alg_id.h>
16 #include <botan/oids.h>
17 #include <botan/rng.h>
18 
19 #if defined(BOTAN_HAS_SCRYPT)
20  #include <botan/scrypt.h>
21 #endif
22 
23 namespace Botan {
24 
25 namespace {
26 
27 bool known_pbes_cipher_mode(const std::string& mode)
28  {
29  return (mode == "CBC" || mode == "GCM" || mode == "SIV");
30  }
31 
32 SymmetricKey derive_key(const std::string& passphrase,
33  const AlgorithmIdentifier& kdf_algo,
34  size_t default_key_size)
35  {
36  if(kdf_algo.get_oid() == OIDS::lookup("PKCS5.PBKDF2"))
37  {
38  secure_vector<uint8_t> salt;
39  size_t iterations = 0, key_length = 0;
40 
41  AlgorithmIdentifier prf_algo;
42  BER_Decoder(kdf_algo.get_parameters())
43  .start_cons(SEQUENCE)
44  .decode(salt, OCTET_STRING)
45  .decode(iterations)
46  .decode_optional(key_length, INTEGER, UNIVERSAL)
47  .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED,
48  AlgorithmIdentifier("HMAC(SHA-160)",
50  .end_cons();
51 
52  if(salt.size() < 8)
53  throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
54 
55  if(key_length == 0)
56  key_length = default_key_size;
57 
58  const std::string prf = OIDS::lookup(prf_algo.get_oid());
59  std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
60  return pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations);
61  }
62 #if defined(BOTAN_HAS_SCRYPT)
63  else if(kdf_algo.get_oid() == OIDS::lookup("Scrypt"))
64  {
65  secure_vector<uint8_t> salt;
66  size_t N = 0, r = 0, p = 0;
67  size_t key_length = 0;
68 
69  AlgorithmIdentifier prf_algo;
70  BER_Decoder(kdf_algo.get_parameters())
71  .start_cons(SEQUENCE)
72  .decode(salt, OCTET_STRING)
73  .decode(N)
74  .decode(r)
75  .decode(p)
76  .decode_optional(key_length, INTEGER, UNIVERSAL)
77  .end_cons();
78 
79  if(key_length == 0)
80  key_length = default_key_size;
81 
82  secure_vector<uint8_t> output(key_length);
83  scrypt(output.data(), output.size(), passphrase,
84  salt.data(), salt.size(), N, r, p);
85 
86  return SymmetricKey(output);
87  }
88 #endif
89  else
90  throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
91  kdf_algo.get_oid().as_string());
92  }
93 
94 secure_vector<uint8_t> derive_key(const std::string& passphrase,
95  const std::string& digest,
96  RandomNumberGenerator& rng,
97  size_t* msec_in_iterations_out,
98  size_t iterations_if_msec_null,
99  size_t key_length,
100  AlgorithmIdentifier& kdf_algo)
101  {
102  const secure_vector<uint8_t> salt = rng.random_vec(12);
103 
104  if(digest == "Scrypt")
105  {
106 #if defined(BOTAN_HAS_SCRYPT)
107 
108  std::unique_ptr<PasswordHashFamily> pwhash_fam = PasswordHashFamily::create_or_throw("Scrypt");
109 
110  std::unique_ptr<PasswordHash> pwhash;
111 
112  if(msec_in_iterations_out)
113  {
114  const std::chrono::milliseconds msec(*msec_in_iterations_out);
115  pwhash = pwhash_fam->tune(key_length, msec);
116  }
117  else
118  {
119  pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
120  }
121 
122  secure_vector<uint8_t> key(key_length);
123  pwhash->derive_key(key.data(), key.size(),
124  passphrase.c_str(), passphrase.size(),
125  salt.data(), salt.size());
126 
127  const size_t N = pwhash->memory_param();
128  const size_t r = pwhash->iterations();
129  const size_t p = pwhash->parallelism();
130 
131  if(msec_in_iterations_out)
132  *msec_in_iterations_out = 0;
133 
134  std::vector<uint8_t> scrypt_params;
135  DER_Encoder(scrypt_params)
136  .start_cons(SEQUENCE)
137  .encode(salt, OCTET_STRING)
138  .encode(N)
139  .encode(r)
140  .encode(p)
141  .encode(key_length)
142  .end_cons();
143 
144  kdf_algo = AlgorithmIdentifier(OIDS::lookup("Scrypt"), scrypt_params);
145  return key;
146 #else
147  throw Not_Implemented("Scrypt is not available in this build");
148 #endif
149  }
150  else
151  {
152  const std::string prf = "HMAC(" + digest + ")";
153  const std::string pbkdf_name = "PBKDF2(" + prf + ")";
154 
155  std::unique_ptr<PasswordHashFamily> pwhash_fam = PasswordHashFamily::create(pbkdf_name);
156  if(!pwhash_fam)
157  throw Invalid_Argument("Unknown password hash digest " + digest);
158 
159  std::unique_ptr<PasswordHash> pwhash;
160 
161  if(msec_in_iterations_out)
162  {
163  const std::chrono::milliseconds msec(*msec_in_iterations_out);
164  pwhash = pwhash_fam->tune(key_length, msec);
165  }
166  else
167  {
168  pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
169  }
170 
171  secure_vector<uint8_t> key(key_length);
172  pwhash->derive_key(key.data(), key.size(),
173  passphrase.c_str(), passphrase.size(),
174  salt.data(), salt.size());
175 
176  std::vector<uint8_t> pbkdf2_params;
177 
178  const size_t iterations = pwhash->iterations();
179 
180  if(msec_in_iterations_out)
181  *msec_in_iterations_out = iterations;
182 
183  DER_Encoder(pbkdf2_params)
184  .start_cons(SEQUENCE)
185  .encode(salt, OCTET_STRING)
186  .encode(iterations)
187  .encode(key_length)
188  .encode_if(prf != "HMAC(SHA-160)",
189  AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM))
190  .end_cons();
191 
192  kdf_algo = AlgorithmIdentifier("PKCS5.PBKDF2", pbkdf2_params);
193  return key;
194  }
195  }
196 
197 /*
198 * PKCS#5 v2.0 PBE Encryption
199 */
200 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
201 pbes2_encrypt_shared(const secure_vector<uint8_t>& key_bits,
202  const std::string& passphrase,
203  size_t* msec_in_iterations_out,
204  size_t iterations_if_msec_null,
205  const std::string& cipher,
206  const std::string& prf,
207  RandomNumberGenerator& rng)
208  {
209  const std::vector<std::string> cipher_spec = split_on(cipher, '/');
210  if(cipher_spec.size() != 2)
211  throw Encoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
212 
213  if(!known_pbes_cipher_mode(cipher_spec[1]))
214  throw Encoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
215 
216  const OID cipher_oid = OIDS::lookup(cipher);
217  if(cipher_oid.empty())
218  throw Encoding_Error("PBE-PKCS5 v2.0: No OID assigned for " + cipher);
219 
220  std::unique_ptr<Cipher_Mode> enc = Cipher_Mode::create(cipher, ENCRYPTION);
221 
222  if(!enc)
223  throw Decoding_Error("PBE-PKCS5 cannot encrypt no cipher " + cipher);
224 
225  const size_t key_length = enc->key_spec().maximum_keylength();
226 
227  const secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length());
228 
229  AlgorithmIdentifier kdf_algo;
230 
231  const secure_vector<uint8_t> derived_key =
232  derive_key(passphrase, prf, rng,
233  msec_in_iterations_out, iterations_if_msec_null,
234  key_length, kdf_algo);
235 
236  enc->set_key(derived_key);
237  enc->start(iv);
238  secure_vector<uint8_t> ctext = key_bits;
239  enc->finish(ctext);
240 
241  std::vector<uint8_t> pbes2_params;
242 
243  DER_Encoder(pbes2_params)
244  .start_cons(SEQUENCE)
245  .encode(kdf_algo)
246  .encode(
247  AlgorithmIdentifier(cipher,
248  DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked()
249  )
250  )
251  .end_cons();
252 
253  AlgorithmIdentifier id(OIDS::lookup("PBE-PKCS5v20"), pbes2_params);
254 
255  return std::make_pair(id, unlock(ctext));
256  }
257 
258 
259 }
260 
261 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
263  const std::string& passphrase,
264  std::chrono::milliseconds msec,
265  const std::string& cipher,
266  const std::string& digest,
268  {
269  size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
270  return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
271  // return value msec_in_iterations_out discarded
272  }
273 
274 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
276  const std::string& passphrase,
277  std::chrono::milliseconds msec,
278  size_t* out_iterations_if_nonnull,
279  const std::string& cipher,
280  const std::string& digest,
282  {
283  size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
284 
285  auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
286 
287  if(out_iterations_if_nonnull)
288  *out_iterations_if_nonnull = msec_in_iterations_out;
289 
290  return ret;
291  }
292 
293 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
295  const std::string& passphrase,
296  size_t pbkdf_iter,
297  const std::string& cipher,
298  const std::string& digest,
300  {
301  return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng);
302  }
303 
304 secure_vector<uint8_t>
306  const std::string& passphrase,
307  const std::vector<uint8_t>& params)
308  {
309  AlgorithmIdentifier kdf_algo, enc_algo;
310 
311  BER_Decoder(params)
313  .decode(kdf_algo)
314  .decode(enc_algo)
315  .end_cons();
316 
317  const std::string cipher = OIDS::lookup(enc_algo.get_oid());
318  const std::vector<std::string> cipher_spec = split_on(cipher, '/');
319  if(cipher_spec.size() != 2)
320  throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
321  if(!known_pbes_cipher_mode(cipher_spec[1]))
322  throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
323 
325  BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end();
326 
327  std::unique_ptr<Cipher_Mode> dec = Cipher_Mode::create(cipher, DECRYPTION);
328  if(!dec)
329  throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher);
330 
331  dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength()));
332 
333  dec->start(iv);
334 
335  secure_vector<uint8_t> buf = key_bits;
336  dec->finish(buf);
337 
338  return buf;
339  }
340 
341 }
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:144
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_msec(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, std::chrono::milliseconds msec, size_t *out_iterations_if_nonnull, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:275
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
static std::unique_ptr< PasswordHashFamily > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: pwdhash.cpp:73
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
PBKDF * get_pbkdf(const std::string &algo_spec, const std::string &provider="")
Definition: pbkdf.h:232
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt_iter(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, size_t pbkdf_iter, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:294
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
std::pair< AlgorithmIdentifier, std::vector< uint8_t > > pbes2_encrypt(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, std::chrono::milliseconds msec, const std::string &cipher, const std::string &digest, RandomNumberGenerator &rng)
Definition: pbes2.cpp:262
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
Definition: alg_id.cpp:13
static std::unique_ptr< PasswordHashFamily > create(const std::string &algo_spec, const std::string &provider="")
Definition: pwdhash.cpp:25
OctetString SymmetricKey
Definition: symkey.h:136
secure_vector< uint8_t > pbes2_decrypt(const secure_vector< uint8_t > &key_bits, const std::string &passphrase, const std::vector< uint8_t > &params)
Definition: pbes2.cpp:305
const std::vector< uint8_t > & get_parameters() const
Definition: alg_id.h:38
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:95
static std::unique_ptr< Cipher_Mode > create(const std::string &algo, Cipher_Dir direction, const std::string &provider="")
Definition: cipher_mode.cpp:54
const OID & get_oid() const
Definition: alg_id.h:37
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
std::string lookup(const OID &oid)
Definition: oids.cpp:113
void scrypt(uint8_t output[], size_t output_len, const char *password, size_t password_len, const uint8_t salt[], size_t salt_len, size_t N, size_t r, size_t p)
Definition: scrypt.cpp:211