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