monotone

monotone Mtn Source Tree

Root/botan/pbes2.cpp

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

Archive Download this file

Branches

Tags

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