monotone

monotone Mtn Source Tree

Root/botan/pbes2.cpp

1/*************************************************
2* PKCS #5 PBES2 Source File *
3* (C) 1999-2006 The Botan Project *
4*************************************************/
5
6#include <botan/pbe_pkcs.h>
7#include <botan/der_enc.h>
8#include <botan/ber_dec.h>
9#include <botan/parsing.h>
10#include <botan/lookup.h>
11#include <botan/rng.h>
12#include <botan/asn1_obj.h>
13#include <botan/oids.h>
14#include <algorithm>
15#include <memory>
16
17namespace Botan {
18
19/*************************************************
20* Encrypt some bytes using PBES2 *
21*************************************************/
22void PBE_PKCS5v20::write(const byte input[], u32bit length)
23 {
24 while(length)
25 {
26 u32bit put = std::min(DEFAULT_BUFFERSIZE, length);
27 pipe.write(input, length);
28 flush_pipe(true);
29 length -= put;
30 }
31 }
32
33/*************************************************
34* Start encrypting with PBES2 *
35*************************************************/
36void PBE_PKCS5v20::start_msg()
37 {
38 pipe.append(get_cipher(cipher, key, iv, direction));
39 pipe.start_msg();
40 if(pipe.message_count() > 1)
41 pipe.set_default_msg(pipe.default_msg() + 1);
42 }
43
44/*************************************************
45* Finish encrypting with PBES2 *
46*************************************************/
47void PBE_PKCS5v20::end_msg()
48 {
49 pipe.end_msg();
50 flush_pipe(false);
51 pipe.reset();
52 }
53
54/*************************************************
55* Flush the pipe *
56*************************************************/
57void PBE_PKCS5v20::flush_pipe(bool safe_to_skip)
58 {
59 if(safe_to_skip && pipe.remaining() < 64)
60 return;
61
62 SecureVector<byte> buffer(DEFAULT_BUFFERSIZE);
63 while(pipe.remaining())
64 {
65 u32bit got = pipe.read(buffer, buffer.size());
66 send(buffer, got);
67 }
68 }
69
70/*************************************************
71* Set the passphrase to use *
72*************************************************/
73void PBE_PKCS5v20::set_key(const std::string& passphrase)
74 {
75 std::auto_ptr<S2K> pbkdf(get_s2k("PBKDF2(" + digest + ")"));
76 pbkdf->set_iterations(iterations);
77 pbkdf->change_salt(salt, salt.size());
78 key = pbkdf->derive_key(key_length, passphrase).bits_of();
79 }
80
81/*************************************************
82* Create a new set of PBES2 parameters *
83*************************************************/
84void PBE_PKCS5v20::new_params()
85 {
86 iterations = 2048;
87 key_length = max_keylength_of(cipher_algo);
88 salt.create(8);
89 iv.create(block_size_of(cipher_algo));
90 Global_RNG::randomize(salt, salt.size());
91 Global_RNG::randomize(iv, iv.size());
92 }
93
94/*************************************************
95* Encode PKCS#5 PBES2 parameters *
96*************************************************/
97MemoryVector<byte> PBE_PKCS5v20::encode_params() const
98 {
99 return DER_Encoder()
100 .start_cons(SEQUENCE)
101 .encode(
102 AlgorithmIdentifier("PKCS5.PBKDF2",
103 DER_Encoder()
104 .start_cons(SEQUENCE)
105 .encode(salt, OCTET_STRING)
106 .encode(iterations)
107 .encode(key_length)
108 .end_cons()
109 .get_contents()
110 )
111 )
112 .encode(
113 AlgorithmIdentifier(cipher,
114 DER_Encoder()
115 .encode(iv, OCTET_STRING)
116 .get_contents()
117 )
118 )
119 .end_cons()
120 .get_contents();
121 }
122
123/*************************************************
124* Decode PKCS#5 PBES2 parameters *
125*************************************************/
126void PBE_PKCS5v20::decode_params(DataSource& source)
127 {
128 AlgorithmIdentifier kdf_algo, enc_algo;
129
130 BER_Decoder(source)
131 .start_cons(SEQUENCE)
132 .decode(kdf_algo)
133 .decode(enc_algo)
134 .verify_end()
135 .end_cons();
136
137 if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2"))
138 {
139 digest = "SHA-160";
140
141 BER_Decoder(kdf_algo.parameters)
142 .start_cons(SEQUENCE)
143 .decode(salt, OCTET_STRING)
144 .decode(iterations)
145 .decode_optional(key_length, INTEGER, UNIVERSAL)
146 .verify_end()
147 .end_cons();
148 }
149 else
150 throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
151 kdf_algo.oid.as_string());
152
153 cipher = OIDS::lookup(enc_algo.oid);
154 std::vector<std::string> cipher_spec = split_on(cipher, '/');
155 if(cipher_spec.size() != 2)
156 throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
157 cipher_algo = deref_alias(cipher_spec[0]);
158
159 if(!known_cipher(cipher_algo) || cipher_spec[1] != "CBC")
160 throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " +
161 cipher);
162
163 BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end();
164
165 if(key_length == 0)
166 key_length = max_keylength_of(cipher_algo);
167
168 if(salt.size() < 8)
169 throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
170 }
171
172/*************************************************
173* Return an OID for PBES2 *
174*************************************************/
175OID PBE_PKCS5v20::get_oid() const
176 {
177 return OIDS::lookup("PBE-PKCS5v20");
178 }
179
180/*************************************************
181* Check if this is a known PBES2 cipher *
182*************************************************/
183bool PBE_PKCS5v20::known_cipher(const std::string& algo) const
184 {
185 if(algo == "AES-128" || algo == "AES-192" || algo == "AES-256")
186 return true;
187 if(algo == "DES" || algo == "TripleDES")
188 return true;
189 return false;
190 }
191
192/*************************************************
193* PKCS#5 v2.0 PBE Constructor *
194*************************************************/
195PBE_PKCS5v20::PBE_PKCS5v20(const std::string& d_algo,
196 const std::string& c_algo) :
197 direction(ENCRYPTION), digest(deref_alias(d_algo)), cipher(c_algo)
198 {
199 std::vector<std::string> cipher_spec = split_on(cipher, '/');
200 if(cipher_spec.size() != 2)
201 throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
202 cipher_algo = deref_alias(cipher_spec[0]);
203 const std::string cipher_mode = cipher_spec[1];
204
205 if(!have_block_cipher(cipher_algo))
206 throw Algorithm_Not_Found(cipher_algo);
207 if(!have_hash(digest))
208 throw Algorithm_Not_Found(digest);
209
210 if(!known_cipher(cipher_algo))
211 throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher);
212 if(cipher_mode != "CBC")
213 throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid cipher " + cipher);
214 if(digest != "SHA-160")
215 throw Invalid_Argument("PBE-PKCS5 v2.0: Invalid digest " + digest);
216 }
217
218/*************************************************
219* PKCS#5 v2.0 PBE Constructor *
220*************************************************/
221PBE_PKCS5v20::PBE_PKCS5v20(DataSource& params) : direction(DECRYPTION)
222 {
223 decode_params(params);
224 }
225
226}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status