Coverage Report

Created: 2020-08-01 06:18

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