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