Botan  1.10.9
pbes2.cpp
Go to the documentation of this file.
1 /*
2 * PKCS #5 PBES2
3 * (C) 1999-2008 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/pbes2.h>
9 #include <botan/pbkdf2.h>
10 #include <botan/hmac.h>
11 #include <botan/cbc.h>
12 #include <botan/algo_factory.h>
13 #include <botan/libstate.h>
14 #include <botan/der_enc.h>
15 #include <botan/ber_dec.h>
16 #include <botan/parsing.h>
17 #include <botan/asn1_obj.h>
18 #include <botan/oids.h>
19 #include <algorithm>
20 #include <memory>
21 
22 namespace Botan {
23 
24 /*
25 * Encrypt some bytes using PBES2
26 */
27 void PBE_PKCS5v20::write(const byte input[], size_t length)
28  {
29  pipe.write(input, length);
30  flush_pipe(true);
31  }
32 
33 /*
34 * Start encrypting with PBES2
35 */
37  {
38  if(direction == ENCRYPTION)
39  pipe.append(new CBC_Encryption(block_cipher->clone(),
40  new PKCS7_Padding,
41  key, iv));
42  else
43  pipe.append(new CBC_Decryption(block_cipher->clone(),
44  new PKCS7_Padding,
45  key, iv));
46 
47  pipe.start_msg();
48  if(pipe.message_count() > 1)
49  pipe.set_default_msg(pipe.default_msg() + 1);
50  }
51 
52 /*
53 * Finish encrypting with PBES2
54 */
56  {
57  pipe.end_msg();
58  flush_pipe(false);
59  pipe.reset();
60  }
61 
62 /*
63 * Flush the pipe
64 */
65 void PBE_PKCS5v20::flush_pipe(bool safe_to_skip)
66  {
67  if(safe_to_skip && pipe.remaining() < 64)
68  return;
69 
70  SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
71  while(pipe.remaining())
72  {
73  size_t got = pipe.read(&buffer[0], buffer.size());
74  send(buffer, got);
75  }
76  }
77 
78 /*
79 * Set the passphrase to use
80 */
81 void PBE_PKCS5v20::set_key(const std::string& passphrase)
82  {
83  PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->clone()));
84 
85  key = pbkdf.derive_key(key_length, passphrase,
86  &salt[0], salt.size(),
87  iterations).bits_of();
88  }
89 
90 /*
91 * Create a new set of PBES2 parameters
92 */
93 void PBE_PKCS5v20::new_params(RandomNumberGenerator& rng)
94  {
95  iterations = 50000;
96  key_length = block_cipher->maximum_keylength();
97 
98  salt = rng.random_vec(12);
99  iv = rng.random_vec(block_cipher->block_size());
100  }
101 
102 /*
103 * Encode PKCS#5 PBES2 parameters
104 */
105 MemoryVector<byte> PBE_PKCS5v20::encode_params() const
106  {
107  return DER_Encoder()
108  .start_cons(SEQUENCE)
109  .encode(
110  AlgorithmIdentifier("PKCS5.PBKDF2",
111  DER_Encoder()
112  .start_cons(SEQUENCE)
113  .encode(salt, OCTET_STRING)
114  .encode(iterations)
115  .encode(key_length)
116  .end_cons()
117  .get_contents()
118  )
119  )
120  .encode(
121  AlgorithmIdentifier(block_cipher->name() + "/CBC",
122  DER_Encoder()
123  .encode(iv, OCTET_STRING)
124  .get_contents()
125  )
126  )
127  .end_cons()
128  .get_contents();
129  }
130 
131 /*
132 * Decode PKCS#5 PBES2 parameters
133 */
134 void PBE_PKCS5v20::decode_params(DataSource& source)
135  {
136  AlgorithmIdentifier kdf_algo, enc_algo;
137 
138  BER_Decoder(source)
139  .start_cons(SEQUENCE)
140  .decode(kdf_algo)
141  .decode(enc_algo)
142  .verify_end()
143  .end_cons();
144 
145  if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2"))
146  {
147  BER_Decoder(kdf_algo.parameters)
148  .start_cons(SEQUENCE)
149  .decode(salt, OCTET_STRING)
150  .decode(iterations)
151  .decode_optional(key_length, INTEGER, UNIVERSAL)
152  .verify_end()
153  .end_cons();
154  }
155  else
156  throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
157  kdf_algo.oid.as_string());
158 
159  Algorithm_Factory& af = global_state().algorithm_factory();
160 
161  std::string cipher = OIDS::lookup(enc_algo.oid);
162  std::vector<std::string> cipher_spec = split_on(cipher, '/');
163  if(cipher_spec.size() != 2)
164  throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
165 
166  if(!known_cipher(cipher_spec[0]) || cipher_spec[1] != "CBC")
167  throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " +
168  cipher);
169 
170  BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end();
171 
172  block_cipher = af.make_block_cipher(cipher_spec[0]);
173  hash_function = af.make_hash_function("SHA-160");
174 
175  if(key_length == 0)
176  key_length = block_cipher->maximum_keylength();
177 
178  if(salt.size() < 8)
179  throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
180  }
181 
182 /*
183 * Return an OID for PBES2
184 */
185 OID PBE_PKCS5v20::get_oid() const
186  {
187  return OIDS::lookup("PBE-PKCS5v20");
188  }
189 
190 /*
191 * Check if this is a known PBES2 cipher
192 */
193 bool PBE_PKCS5v20::known_cipher(const std::string& algo)
194  {
195  if(algo == "AES-128" || algo == "AES-192" || algo == "AES-256")
196  return true;
197  if(algo == "DES" || algo == "TripleDES")
198  return true;
199  return false;
200  }
201 
202 std::string PBE_PKCS5v20::name() const
203  {
204  return "PBE-PKCS5v20(" + block_cipher->name() + "," +
205  hash_function->name() + ")";
206  }
207 
208 /*
209 * PKCS#5 v2.0 PBE Constructor
210 */
212  HashFunction* digest) :
213  direction(ENCRYPTION),
214  block_cipher(cipher),
215  hash_function(digest),
216  iterations(0),
217  key_length(0)
218  {
219  if(!known_cipher(block_cipher->name()))
220  throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher->name());
221  if(hash_function->name() != "SHA-160")
222  throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid digest " + digest->name());
223  }
224 
225 /*
226 * PKCS#5 v2.0 PBE Constructor
227 */
229  {
230  hash_function = 0;
231  block_cipher = 0;
232  decode_params(params);
233  }
234 
236  {
237  delete hash_function;
238  delete block_cipher;
239  }
240 
241 }
void start_msg()
Definition: pipe.cpp:152
void append(Filter *filt)
Definition: pipe.cpp:215
size_t read(byte output[], size_t length)
Definition: pipe_rw.cpp:89
void write(const byte in[], size_t length)
Definition: pipe_rw.cpp:34
virtual BlockCipher * clone() const =0
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:152
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
void reset()
Definition: pipe.cpp:76
void start_msg()
Definition: pbes2.cpp:36
virtual HashFunction * clone() const =0
size_t remaining(message_id msg=DEFAULT_MESSAGE) const
Definition: pipe_rw.cpp:138
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
unsigned char byte
Definition: types.h:22
void send(const byte in[], size_t length)
Definition: filter.cpp:28
void end_msg()
Definition: pipe.cpp:166
RandomNumberGenerator * rng
Definition: global_rng.cpp:165
Library_State & global_state()
std::string lookup(const OID &oid)
Definition: oids.cpp:31
size_t size() const
Definition: secmem.h:29
virtual std::string name() const =0
std::string encode(const byte der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:19
static bool known_cipher(const std::string &cipher)
Definition: pbes2.cpp:193
size_t default_msg() const
Definition: pipe.h:206
std::string name() const
Definition: pbes2.cpp:202
void set_default_msg(message_id msg)
Definition: pipe.cpp:106
PBE_PKCS5v20(DataSource &input)
Definition: pbes2.cpp:228
size_t maximum_keylength() const
Definition: sym_algo.h:33
message_id message_count() const
Definition: pipe.cpp:282
virtual size_t block_size() const =0
void write(const byte[], size_t)
Definition: pbes2.cpp:27