Botan  2.6.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 namespace Botan {
19 
20 namespace {
21 
22 /*
23 * Encode PKCS#5 PBES2 parameters
24 */
25 std::vector<uint8_t> encode_pbes2_params(const std::string& cipher,
26  const std::string& prf,
27  const secure_vector<uint8_t>& salt,
28  const secure_vector<uint8_t>& iv,
29  size_t iterations,
30  size_t key_length)
31  {
32  return DER_Encoder()
33  .start_cons(SEQUENCE)
34  .encode(
35  AlgorithmIdentifier("PKCS5.PBKDF2",
36  DER_Encoder()
37  .start_cons(SEQUENCE)
38  .encode(salt, OCTET_STRING)
39  .encode(iterations)
40  .encode(key_length)
41  .encode_if(
42  prf != "HMAC(SHA-160)",
43  AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM))
44  .end_cons()
45  .get_contents_unlocked()
46  )
47  )
48  .encode(
49  AlgorithmIdentifier(cipher,
50  DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked()
51  )
52  )
53  .end_cons()
54  .get_contents_unlocked();
55  }
56 
57 /*
58 * PKCS#5 v2.0 PBE Encryption
59 */
60 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
61 pbes2_encrypt_shared(const secure_vector<uint8_t>& key_bits,
62  const std::string& passphrase,
63  size_t* msec_in_iterations_out,
64  size_t iterations_if_msec_null,
65  const std::string& cipher,
66  const std::string& digest,
67  RandomNumberGenerator& rng)
68  {
69  const std::string prf = "HMAC(" + digest + ")";
70 
71  const std::vector<std::string> cipher_spec = split_on(cipher, '/');
72  if(cipher_spec.size() != 2)
73  throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
74 
75  const secure_vector<uint8_t> salt = rng.random_vec(12);
76 
77  if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM")
78  throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
79 
80  std::unique_ptr<Cipher_Mode> enc = Cipher_Mode::create(cipher, ENCRYPTION);
81 
82  if(!enc)
83  throw Decoding_Error("PBE-PKCS5 cannot encrypt no cipher " + cipher);
84 
85  std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
86 
87  const size_t key_length = enc->key_spec().maximum_keylength();
88 
89 
90  secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length());
91 
92  size_t iterations = iterations_if_msec_null;
93 
94  if(msec_in_iterations_out)
95  {
96  std::chrono::milliseconds msec(*msec_in_iterations_out);
97  enc->set_key(pbkdf->derive_key(key_length, passphrase, salt.data(), salt.size(), msec, iterations).bits_of());
98  *msec_in_iterations_out = iterations;
99  }
100  else
101  {
102  enc->set_key(pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations));
103  }
104 
105  enc->start(iv);
106  secure_vector<uint8_t> buf = key_bits;
107  enc->finish(buf);
108 
109  AlgorithmIdentifier id(
110  OIDS::lookup("PBE-PKCS5v20"),
111  encode_pbes2_params(cipher, prf, salt, iv, iterations, key_length));
112 
113  return std::make_pair(id, unlock(buf));
114  }
115 
116 
117 }
118 
119 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
121  const std::string& passphrase,
122  std::chrono::milliseconds msec,
123  const std::string& cipher,
124  const std::string& digest,
126  {
127  size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
128  return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
129  // return value msec_in_iterations_out discarded
130  }
131 
132 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
134  const std::string& passphrase,
135  std::chrono::milliseconds msec,
136  size_t* out_iterations_if_nonnull,
137  const std::string& cipher,
138  const std::string& digest,
140  {
141  size_t msec_in_iterations_out = static_cast<size_t>(msec.count());
142 
143  auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng);
144 
145  if(out_iterations_if_nonnull)
146  *out_iterations_if_nonnull = msec_in_iterations_out;
147 
148  return ret;
149  }
150 
151 std::pair<AlgorithmIdentifier, std::vector<uint8_t>>
153  const std::string& passphrase,
154  size_t pbkdf_iter,
155  const std::string& cipher,
156  const std::string& digest,
158  {
159  return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng);
160  }
161 
162 secure_vector<uint8_t>
164  const std::string& passphrase,
165  const std::vector<uint8_t>& params)
166  {
167  AlgorithmIdentifier kdf_algo, enc_algo;
168 
169  BER_Decoder(params)
171  .decode(kdf_algo)
172  .decode(enc_algo)
173  .end_cons();
174 
175  AlgorithmIdentifier prf_algo;
176 
177  if(kdf_algo.get_oid() != OIDS::lookup("PKCS5.PBKDF2"))
178  throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
179  kdf_algo.get_oid().as_string());
180 
182  size_t iterations = 0, key_length = 0;
183 
184  BER_Decoder(kdf_algo.get_parameters())
185  .start_cons(SEQUENCE)
186  .decode(salt, OCTET_STRING)
187  .decode(iterations)
188  .decode_optional(key_length, INTEGER, UNIVERSAL)
190  AlgorithmIdentifier("HMAC(SHA-160)",
192  .end_cons();
193 
194  const std::string cipher = OIDS::lookup(enc_algo.get_oid());
195  const std::vector<std::string> cipher_spec = split_on(cipher, '/');
196  if(cipher_spec.size() != 2)
197  throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
198  if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM")
199  throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
200 
201  if(salt.size() < 8)
202  throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
203 
205  BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end();
206 
207  const std::string prf = OIDS::lookup(prf_algo.get_oid());
208 
209  std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
210 
211  std::unique_ptr<Cipher_Mode> dec = Cipher_Mode::create(cipher, DECRYPTION);
212  if(!dec)
213  throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher);
214 
215  if(key_length == 0)
216  key_length = dec->key_spec().maximum_keylength();
217 
218  dec->set_key(pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations));
219 
220  dec->start(iv);
221 
222  secure_vector<uint8_t> buf = key_bits;
223  dec->finish(buf);
224 
225  return buf;
226  }
227 
228 }
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:144
std::string as_string() const
Definition: asn1_oid.h:48
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:133
BER_Decoder & decode(bool &v)
Definition: ber_dec.cpp:338
BER_Decoder & decode_optional(T &out, ASN1_Tag type_tag, ASN1_Tag class_tag, const T &default_value=T())
Definition: ber_dec.h:232
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:253
PBKDF * get_pbkdf(const std::string &algo_spec, const std::string &provider="")
Definition: pbkdf.h:230
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:152
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:120
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:239
Definition: alg_id.cpp:13
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:163
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