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