Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

cryptobox.cpp
Go to the documentation of this file.
1 /*
2 * Cryptobox Message Routines
3 * (C) 2009 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7
8 #include <botan/cryptobox.h>
9 #include <botan/filters.h>
10 #include <botan/pipe.h>
11 #include <botan/sha2_64.h>
12 #include <botan/hmac.h>
13 #include <botan/pbkdf2.h>
14 #include <botan/pem.h>
15 #include <botan/loadstor.h>
16 #include <botan/mem_ops.h>
17
18 namespace Botan {
19
20 namespace CryptoBox {
21
22 namespace {
23
24 /*
25 First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits
26 for later use as flags, etc if needed
27 */
28 const uint32_t CRYPTOBOX_VERSION_CODE = 0xEFC22400;
29
30 const size_t VERSION_CODE_LEN = 4;
31 const size_t CIPHER_KEY_LEN = 32;
32 const size_t CIPHER_IV_LEN = 16;
33 const size_t MAC_KEY_LEN = 32;
34 const size_t MAC_OUTPUT_LEN = 20;
35 const size_t PBKDF_SALT_LEN = 10;
36 const size_t PBKDF_ITERATIONS = 8 * 1024;
37
38 const size_t PBKDF_OUTPUT_LEN = CIPHER_KEY_LEN + CIPHER_IV_LEN + MAC_KEY_LEN;
39
40 }
41
42 std::string encrypt(const uint8_t input[], size_t input_len,
43 const std::string& passphrase,
44 RandomNumberGenerator& rng)
45 {
46 secure_vector<uint8_t> pbkdf_salt(PBKDF_SALT_LEN);
47 rng.randomize(pbkdf_salt.data(), pbkdf_salt.size());
48
49 PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512));
50
51 OctetString master_key = pbkdf.derive_key(
52 PBKDF_OUTPUT_LEN,
53 passphrase,
54 pbkdf_salt.data(),
55 pbkdf_salt.size(),
56 PBKDF_ITERATIONS);
57
58 const uint8_t* mk = master_key.begin();
59
60 SymmetricKey cipher_key(mk, CIPHER_KEY_LEN);
61 SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN);
62 InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN);
63
64 Pipe pipe(get_cipher("Serpent/CTR-BE", cipher_key, iv, ENCRYPTION),
65 new Fork(
66 nullptr,
67 new MAC_Filter(new HMAC(new SHA_512),
68 mac_key, MAC_OUTPUT_LEN)));
69
70 pipe.process_msg(input, input_len);
71
72 /*
73 Output format is:
74 version # (4 bytes)
75 salt (10 bytes)
76 mac (20 bytes)
77 ciphertext
78 */
79 const size_t ciphertext_len = pipe.remaining(0);
80
81 std::vector<uint8_t> out_buf(VERSION_CODE_LEN +
82 PBKDF_SALT_LEN +
83 MAC_OUTPUT_LEN +
84 ciphertext_len);
85
86 for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
87 out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE);
88
89 copy_mem(&out_buf[VERSION_CODE_LEN], pbkdf_salt.data(), PBKDF_SALT_LEN);
90
91 BOTAN_ASSERT_EQUAL(
92 pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], MAC_OUTPUT_LEN, 1),
93 MAC_OUTPUT_LEN, "MAC output");
94 BOTAN_ASSERT_EQUAL(
95 pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN],
96 ciphertext_len, 0),
97 ciphertext_len, "Ciphertext size");
98
99 return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE");
100 }
101
102 std::string decrypt(const uint8_t input[], size_t input_len,
103 const std::string& passphrase)
104 {
105 DataSource_Memory input_src(input, input_len);
106 secure_vector<uint8_t> ciphertext =
107 PEM_Code::decode_check_label(input_src,
108 "BOTAN CRYPTOBOX MESSAGE");
109
110 if(ciphertext.size() < (VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN))
111 throw Decoding_Error("Invalid CryptoBox input");
112
113 for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
114 if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE))
115 throw Decoding_Error("Bad CryptoBox version");
116
117 const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN];
118
119 PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512));
120
121 OctetString master_key = pbkdf.derive_key(
122 PBKDF_OUTPUT_LEN,
123 passphrase,
124 pbkdf_salt,
125 PBKDF_SALT_LEN,
126 PBKDF_ITERATIONS);
127
128 const uint8_t* mk = master_key.begin();
129
130 SymmetricKey cipher_key(mk, CIPHER_KEY_LEN);
131 SymmetricKey mac_key(&mk[CIPHER_KEY_LEN], MAC_KEY_LEN);
132 InitializationVector iv(&mk[CIPHER_KEY_LEN + MAC_KEY_LEN], CIPHER_IV_LEN);
133
134 Pipe pipe(new Fork(
135 get_cipher("Serpent/CTR-BE", cipher_key, iv, DECRYPTION),
136 new MAC_Filter(new HMAC(new SHA_512),
137 mac_key, MAC_OUTPUT_LEN)));
138
139 const size_t ciphertext_offset =
140 VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN;
141
142 pipe.process_msg(&ciphertext[ciphertext_offset],
143 ciphertext.size() - ciphertext_offset);
144
145 uint8_t computed_mac[MAC_OUTPUT_LEN];
146 BOTAN_ASSERT_EQUAL(MAC_OUTPUT_LEN, pipe.read(computed_mac, MAC_OUTPUT_LEN, 1), "MAC size");
147
148 if(!same_mem(computed_mac,
149 &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN],
150 MAC_OUTPUT_LEN))
151 throw Decoding_Error("CryptoBox integrity failure");
152
153 return pipe.read_all_as_string(0);
154 }
155
156 std::string decrypt(const std::string& input,
157 const std::string& passphrase)
158 {
159 return decrypt(reinterpret_cast<const uint8_t*>(input.data()),
160 input.size(),
161 passphrase);
162 }
163
164 }
165
166 }
Botan::OctetString
Definition: symkey.h:19
Botan::same_mem
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
Botan::PKCS5_PBKDF2
Definition: pbkdf2.h:28
Botan::RandomNumberGenerator
Definition: rng.h:25
Botan::RandomNumberGenerator::randomize
virtual void randomize(uint8_t output[], size_t length)=0
Botan::ENCRYPTION
Definition: cipher_mode.h:212
Botan::Pipe::remaining
size_t remaining(message_id msg=DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT
Definition: pipe_rw.cpp:130
Botan::PEM_Code::encode
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
Botan::PBKDF::derive_key
OctetString derive_key(size_t out_len, const std::string &passphrase, const uint8_t salt[], size_t salt_len, size_t iterations) const
Definition: pbkdf.h:149
Botan::Pipe::read
size_t read(uint8_t output[], size_t length) override BOTAN_WARN_UNUSED_RESULT
Definition: pipe_rw.cpp:81
Botan::DECRYPTION
Definition: cipher_mode.h:212
Botan::CryptoBox::encrypt
std::string encrypt(const uint8_t input[], size_t input_len, const std::string &passphrase, RandomNumberGenerator &rng)
Definition: cryptobox.cpp:42
Botan::secure_vector
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
BOTAN_ASSERT_EQUAL
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition: assert.h:53
Botan::Pipe::read_all_as_string
std::string read_all_as_string(message_id=DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT
Definition: pipe_rw.cpp:109
Botan::Decoding_Error
Definition: exceptn.h:189
Botan::CryptoBox::decrypt
std::string decrypt(const uint8_t input[], size_t input_len, const std::string &passphrase)
Definition: cryptobox.cpp:102
Botan::Pipe::process_msg
void process_msg(const uint8_t in[], size_t length)
Definition: pipe.cpp:117
Botan::copy_mem
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:68
Botan
Definition: alg_id.cpp:13
Botan::MAC_Filter
Definition: filters.h:134
Botan::PEM_Code::decode_check_label
secure_vector< uint8_t > decode_check_label(DataSource &source, const std::string &label_want)
Definition: pem.cpp:54
Botan::DataSource_Memory
Definition: data_src.h:98
Botan::Fork
Definition: basefilt.h:63
Botan::get_byte
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:47
Botan::HMAC
Definition: hmac.h:19
Botan::Pipe
Definition: pipe.h:27
Botan::OctetString::begin
const uint8_t * begin() const
Definition: symkey.h:36
Botan::get_cipher
Keyed_Filter * get_cipher(const std::string &algo_spec, Cipher_Dir direction)
Definition: key_filt.cpp:12
Botan::SHA_512
Definition: sha2_64.h:39