• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 16788529396

06 Aug 2025 09:04PM UTC coverage: 90.677%. Remained the same
16788529396

Pull #4255

github

web-flow
Merge 09544fbc3 into 1f9987555
Pull Request #4255: Add support for building with clang-cl

99983 of 110263 relevant lines covered (90.68%)

24310874.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.57
/src/lib/misc/cryptobox/cryptobox.cpp
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/mac.h>
13
#include <botan/pem.h>
14
#include <botan/pwdhash.h>
15
#include <botan/rng.h>
16
#include <botan/internal/ct_utils.h>
17
#include <botan/internal/loadstor.h>
18
#include <botan/internal/mem_utils.h>
19

20
namespace Botan::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 CRYPTOBOX_HEADER_LEN = VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN;
39

40
}  // namespace
41

42
std::string encrypt(const uint8_t input[], size_t input_len, std::string_view passphrase, RandomNumberGenerator& rng) {
36✔
43
   /*
44
   Output format is:
45
      version # (4 bytes)
46
      salt (10 bytes)
47
      mac (20 bytes)
48
      ciphertext
49
   */
50
   secure_vector<uint8_t> out_buf(CRYPTOBOX_HEADER_LEN + input_len);
36✔
51
   store_be(CRYPTOBOX_VERSION_CODE, out_buf.data());
36✔
52
   rng.randomize(&out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN);
36✔
53
   // space left for MAC here
54
   if(input_len > 0) {
36✔
55
      copy_mem(&out_buf[CRYPTOBOX_HEADER_LEN], input, input_len);
34✔
56
   }
57

58
   // Generate the keys and IV
59

60
   auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
36✔
61
   auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);
36✔
62

63
   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);
36✔
64

65
   pbkdf->derive_key(master_key.data(),
36✔
66
                     master_key.size(),
67
                     passphrase.data(),
68
                     passphrase.size(),
69
                     &out_buf[VERSION_CODE_LEN],
36✔
70
                     PBKDF_SALT_LEN);
71

72
   const uint8_t* mk = master_key.data();
36✔
73
   const uint8_t* cipher_key = mk;
36✔
74
   const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
36✔
75
   const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;
36✔
76

77
   // Now encrypt and authenticate
78
   auto ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", Cipher_Dir::Encryption);
36✔
79
   ctr->set_key(cipher_key, CIPHER_KEY_LEN);
36✔
80
   ctr->start(iv, CIPHER_IV_LEN);
36✔
81
   ctr->finish(out_buf, CRYPTOBOX_HEADER_LEN);
36✔
82

83
   std::unique_ptr<MessageAuthenticationCode> hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
36✔
84
   hmac->set_key(mac_key, MAC_KEY_LEN);
36✔
85
   if(input_len > 0) {
36✔
86
      hmac->update(&out_buf[CRYPTOBOX_HEADER_LEN], input_len);
34✔
87
   }
88

89
   // Can't write directly because of MAC truncation
90
   secure_vector<uint8_t> mac = hmac->final();
36✔
91
   copy_mem(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], mac.data(), MAC_OUTPUT_LEN);
36✔
92

93
   return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE");
36✔
94
}
252✔
95

96
secure_vector<uint8_t> decrypt_bin(const uint8_t input[], size_t input_len, std::string_view passphrase) {
72✔
97
   DataSource_Memory input_src(input, input_len);
72✔
98
   secure_vector<uint8_t> ciphertext = PEM_Code::decode_check_label(input_src, "BOTAN CRYPTOBOX MESSAGE");
108✔
99

100
   if(ciphertext.size() < CRYPTOBOX_HEADER_LEN) {
72✔
101
      throw Decoding_Error("Invalid CryptoBox input");
×
102
   }
103

104
   for(size_t i = 0; i != VERSION_CODE_LEN; ++i) {
356✔
105
      uint32_t version = load_be<uint32_t>(ciphertext.data(), 0);
285✔
106
      if(version != CRYPTOBOX_VERSION_CODE) {
285✔
107
         throw Decoding_Error("Bad CryptoBox version");
1✔
108
      }
109
   }
110

111
   const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN];
71✔
112
   const uint8_t* box_mac = &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN];
71✔
113

114
   auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
107✔
115
   auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);
71✔
116

117
   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);
106✔
118

119
   pbkdf->derive_key(
71✔
120
      master_key.data(), master_key.size(), passphrase.data(), passphrase.size(), pbkdf_salt, PBKDF_SALT_LEN);
121

122
   const uint8_t* mk = master_key.data();
71✔
123
   const uint8_t* cipher_key = mk;
71✔
124
   const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
71✔
125
   const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;
71✔
126

127
   // Now authenticate and decrypt
128
   std::unique_ptr<MessageAuthenticationCode> hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
106✔
129
   hmac->set_key(mac_key, MAC_KEY_LEN);
71✔
130

131
   if(ciphertext.size() > CRYPTOBOX_HEADER_LEN) {
71✔
132
      hmac->update(&ciphertext[CRYPTOBOX_HEADER_LEN], ciphertext.size() - CRYPTOBOX_HEADER_LEN);
68✔
133
   }
134
   secure_vector<uint8_t> computed_mac = hmac->final();
71✔
135

136
   if(!CT::is_equal(computed_mac.data(), box_mac, MAC_OUTPUT_LEN).as_bool()) {
142✔
137
      throw Decoding_Error("CryptoBox integrity failure");
35✔
138
   }
139

140
   auto ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", Cipher_Dir::Decryption);
107✔
141
   ctr->set_key(cipher_key, CIPHER_KEY_LEN);
36✔
142
   ctr->start(iv, CIPHER_IV_LEN);
36✔
143
   ctr->finish(ciphertext, CRYPTOBOX_HEADER_LEN);
36✔
144

145
   ciphertext.erase(ciphertext.begin(), ciphertext.begin() + CRYPTOBOX_HEADER_LEN);
36✔
146
   return ciphertext;
36✔
147
}
463✔
148

149
BOTAN_DIAGNOSTIC_PUSH
150
BOTAN_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
151

152
namespace {
153

154
secure_vector<uint8_t> decrypt_bin(std::span<const uint8_t> input, std::string_view passphrase) {
36✔
155
   return CryptoBox::decrypt_bin(input.data(), input.size(), passphrase);
36✔
156
}
157

158
std::string decrypt(std::span<const uint8_t> input, std::string_view passphrase) {
36✔
159
   return CryptoBox::decrypt(input.data(), input.size(), passphrase);
36✔
160
}
161

162
}  // namespace
163

164
secure_vector<uint8_t> decrypt_bin(std::string_view input, std::string_view passphrase) {
36✔
165
   return decrypt_bin(as_span_of_bytes(input), passphrase);
36✔
166
}
167

168
std::string decrypt(const uint8_t input[], size_t input_len, std::string_view passphrase) {
36✔
169
   return bytes_to_string(decrypt_bin(input, input_len, passphrase));
36✔
170
}
171

172
std::string decrypt(std::string_view input, std::string_view passphrase) {
36✔
173
   return decrypt(as_span_of_bytes(input), passphrase);
36✔
174
}
175

176
BOTAN_DIAGNOSTIC_POP
177

178
}  // namespace Botan::CryptoBox
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc