Botan 1.10.17

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 */
36 void PBE_PKCS5v20::start_msg()
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 */
55 void PBE_PKCS5v20::end_msg()
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 */
211 PBE_PKCS5v20::PBE_PKCS5v20(BlockCipher* cipher,
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 */
228 PBE_PKCS5v20::PBE_PKCS5v20(DataSource& params) : direction(DECRYPTION)
229 {
230 hash_function = 0;
231 block_cipher = 0;
232 decode_params(params);
233 }
234
235 PBE_PKCS5v20::~PBE_PKCS5v20()
236 {
237 delete hash_function;
238 delete block_cipher;
239 }
240
241 }
Botan::INTEGER
Definition: asn1_int.h:29
Botan::Pipe::start_msg
void start_msg()
Definition: pipe.cpp:152
Botan::Pipe::remaining
size_t remaining(message_id msg=DEFAULT_MESSAGE) const
Definition: pipe_rw.cpp:138
Botan::Pipe::append
void append(Filter *filt)
Definition: pipe.cpp:215
Botan::Pipe::default_msg
size_t default_msg() const
Definition: pipe.h:209
Botan::Pipe::read
size_t read(byte output[], size_t length)
Definition: pipe_rw.cpp:89
Botan::Library_State::algorithm_factory
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
Botan::ENCRYPTION
Definition: sym_algo.h:87
Botan::Pipe::write
void write(const byte in[], size_t length)
Definition: pipe_rw.cpp:34
Botan::BlockCipher::clone
virtual BlockCipher * clone() const =0
Botan::split_on
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:152
Botan::Invalid_Argument
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
Botan::DataSource
Definition: data_src.h:20
Botan::Pipe::reset
void reset()
Definition: pipe.cpp:76
Botan::PBE_PKCS5v20::start_msg
void start_msg()
Definition: pbes2.cpp:36
Botan::HashFunction::clone
virtual HashFunction * clone() const =0
Botan::CBC_Decryption
Definition: cbc.h:61
Botan::PBE_PKCS5v20::name
std::string name() const
Definition: pbes2.cpp:202
Botan::DECRYPTION
Definition: sym_algo.h:87
Botan::UNIVERSAL
Definition: asn1_int.h:20
Botan::byte
unsigned char byte
Definition: types.h:22
Botan::CBC_Encryption
Definition: cbc.h:21
Botan::SymmetricAlgorithm::maximum_keylength
size_t maximum_keylength() const
Definition: sym_algo.h:33
Botan::Filter::send
void send(const byte in[], size_t length)
Definition: filter.cpp:28
Botan::OCTET_STRING
Definition: asn1_int.h:31
Botan::Pipe::end_msg
void end_msg()
Definition: pipe.cpp:166
Botan::Global_State_Management::global_state
Library_State & global_state()
Definition: global_state.cpp:32
Botan::PBE_PKCS5v20::~PBE_PKCS5v20
~PBE_PKCS5v20()
Definition: pbes2.cpp:235
Botan::OIDS::lookup
std::string lookup(const OID &oid)
Definition: oids.cpp:31
Botan::PBE_PKCS5v20::end_msg
void end_msg()
Definition: pbes2.cpp:55
Botan::SEQUENCE
Definition: asn1_int.h:35
Botan
Definition: algo_base.h:14
Botan::Algorithm::name
virtual std::string name() const =0
Botan::Pipe::message_count
message_id message_count() const
Definition: pipe.cpp:282
Botan::HashFunction
Definition: hash.h:20
Botan::MemoryRegion::size
size_t size() const
Definition: secmem.h:29
Botan::PEM_Code::encode
std::string encode(const byte der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:19
Botan::PBE_PKCS5v20::known_cipher
static bool known_cipher(const std::string &cipher)
Definition: pbes2.cpp:193
Botan::PKCS7_Padding
Definition: mode_pad.h:72
Botan::SecureVector< byte >
Botan::Pipe::set_default_msg
void set_default_msg(message_id msg)
Definition: pipe.cpp:106
Botan::PBE_PKCS5v20::PBE_PKCS5v20
PBE_PKCS5v20(DataSource &input)
Definition: pbes2.cpp:228
Botan::BlockCipher::block_size
virtual size_t block_size() const =0
Botan::PBE_PKCS5v20::write
void write(const byte[], size_t)
Definition: pbes2.cpp:27
Botan::BlockCipher
Definition: block_cipher.h:18