Botan 3.0.0
Crypto and TLS for C&
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/cipher_mode.h>
10#include <botan/mac.h>
11#include <botan/rng.h>
12#include <botan/pwdhash.h>
13#include <botan/data_src.h>
14#include <botan/pem.h>
15#include <botan/internal/loadstor.h>
16#include <botan/mem_ops.h>
17
19
20namespace {
21
22/*
23First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits
24for later use as flags, etc if needed
25*/
26const uint32_t CRYPTOBOX_VERSION_CODE = 0xEFC22400;
27
28const size_t VERSION_CODE_LEN = 4;
29const size_t CIPHER_KEY_LEN = 32;
30const size_t CIPHER_IV_LEN = 16;
31const size_t MAC_KEY_LEN = 32;
32const size_t MAC_OUTPUT_LEN = 20;
33const size_t PBKDF_SALT_LEN = 10;
34const size_t PBKDF_ITERATIONS = 8 * 1024;
35
36const size_t CRYPTOBOX_HEADER_LEN = VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN;
37
38}
39
40std::string encrypt(const uint8_t input[], size_t input_len,
41 std::string_view passphrase,
43 {
44 /*
45 Output format is:
46 version # (4 bytes)
47 salt (10 bytes)
48 mac (20 bytes)
49 ciphertext
50 */
51 secure_vector<uint8_t> out_buf(CRYPTOBOX_HEADER_LEN + input_len);
52 store_be(CRYPTOBOX_VERSION_CODE, out_buf.data());
53 rng.randomize(&out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN);
54 // space left for MAC here
55 if(input_len > 0)
56 copy_mem(&out_buf[CRYPTOBOX_HEADER_LEN], input, input_len);
57
58 // Generate the keys and IV
59
60 auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
61 auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);
62
63 secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);
64
65 pbkdf->derive_key(
66 master_key.data(), master_key.size(),
67 passphrase.data(), passphrase.size(),
68 &out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN);
69
70 const uint8_t* mk = master_key.data();
71 const uint8_t* cipher_key = mk;
72 const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
73 const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;
74
75 // Now encrypt and authenticate
76 auto ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", Cipher_Dir::Encryption);
77 ctr->set_key(cipher_key, CIPHER_KEY_LEN);
78 ctr->start(iv, CIPHER_IV_LEN);
79 ctr->finish(out_buf, CRYPTOBOX_HEADER_LEN);
80
81 std::unique_ptr<MessageAuthenticationCode> hmac =
83 hmac->set_key(mac_key, MAC_KEY_LEN);
84 if(input_len > 0)
85 hmac->update(&out_buf[CRYPTOBOX_HEADER_LEN], input_len);
86
87 // Can't write directly because of MAC truncation
88 secure_vector<uint8_t> mac = hmac->final();
89 copy_mem(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], mac.data(), MAC_OUTPUT_LEN);
90
91 return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE");
92 }
93
95decrypt_bin(const uint8_t input[], size_t input_len,
96 std::string_view passphrase)
97 {
98 DataSource_Memory input_src(input, input_len);
99 secure_vector<uint8_t> ciphertext =
101 "BOTAN CRYPTOBOX MESSAGE");
102
103 if(ciphertext.size() < CRYPTOBOX_HEADER_LEN)
104 throw Decoding_Error("Invalid CryptoBox input");
105
106 for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
107 {
108 uint32_t version = load_be<uint32_t>(ciphertext.data(), 0);
109 if(version != CRYPTOBOX_VERSION_CODE)
110 throw Decoding_Error("Bad CryptoBox version");
111 }
112
113 const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN];
114 const uint8_t* box_mac = &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN];
115
116 auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
117 auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);
118
119 secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);
120
121 pbkdf->derive_key(
122 master_key.data(), master_key.size(),
123 passphrase.data(), passphrase.size(),
124 pbkdf_salt, PBKDF_SALT_LEN);
125
126 const uint8_t* mk = master_key.data();
127 const uint8_t* cipher_key = mk;
128 const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
129 const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;
130
131 // Now authenticate and decrypt
132 std::unique_ptr<MessageAuthenticationCode> hmac =
134 hmac->set_key(mac_key, MAC_KEY_LEN);
135
136 if(ciphertext.size() > CRYPTOBOX_HEADER_LEN)
137 {
138 hmac->update(&ciphertext[CRYPTOBOX_HEADER_LEN],
139 ciphertext.size() - CRYPTOBOX_HEADER_LEN);
140 }
141 secure_vector<uint8_t> computed_mac = hmac->final();
142
143 if(!constant_time_compare(computed_mac.data(), box_mac, MAC_OUTPUT_LEN))
144 throw Decoding_Error("CryptoBox integrity failure");
145
146 auto ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", Cipher_Dir::Decryption);
147 ctr->set_key(cipher_key, CIPHER_KEY_LEN);
148 ctr->start(iv, CIPHER_IV_LEN);
149 ctr->finish(ciphertext, CRYPTOBOX_HEADER_LEN);
150
151 ciphertext.erase(ciphertext.begin(), ciphertext.begin() + CRYPTOBOX_HEADER_LEN);
152 return ciphertext;
153 }
154
157
158secure_vector<uint8_t> decrypt_bin(std::string_view input,
159 std::string_view passphrase)
160 {
161 return decrypt_bin(cast_char_ptr_to_uint8(input.data()),
162 input.size(),
163 passphrase);
164 }
165
166std::string decrypt(const uint8_t input[], size_t input_len,
167 std::string_view passphrase)
168 {
169 const secure_vector<uint8_t> bin = decrypt_bin(input, input_len, passphrase);
170
171 return std::string(cast_uint8_ptr_to_char(&bin[0]),
172 bin.size());
173 }
174
175std::string decrypt(std::string_view input,
176 std::string_view passphrase)
177 {
178 return decrypt(cast_char_ptr_to_uint8(input.data()),
179 input.size(), passphrase);
180 }
182
183}
static std::unique_ptr< Cipher_Mode > create_or_throw(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition: cipher_mode.cpp:40
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition: mac.cpp:134
static std::unique_ptr< PasswordHashFamily > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition: pwdhash.cpp:118
void randomize(std::span< uint8_t > output)
Definition: rng.h:53
#define BOTAN_DIAGNOSTIC_POP
Definition: compiler.h:204
#define BOTAN_DIAGNOSTIC_PUSH
Definition: compiler.h:201
#define BOTAN_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
Definition: compiler.h:202
secure_vector< uint8_t > decrypt_bin(const uint8_t input[], size_t input_len, std::string_view passphrase)
Definition: cryptobox.cpp:95
std::string encrypt(const uint8_t input[], size_t input_len, std::string_view passphrase, RandomNumberGenerator &rng)
Definition: cryptobox.cpp:40
std::string decrypt(const uint8_t input[], size_t input_len, std::string_view passphrase)
Definition: cryptobox.cpp:166
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
Definition: pem.cpp:42
secure_vector< uint8_t > decode_check_label(DataSource &source, std::string_view label_want)
Definition: pem.cpp:53
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:126
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
constexpr uint32_t load_be< uint32_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:190
constexpr void store_be(uint16_t in, uint8_t out[2])
Definition: loadstor.h:449
const char * cast_uint8_ptr_to_char(const uint8_t *b)
Definition: mem_ops.h:188
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:64
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:183