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

randombit / botan / 4876456163

03 May 2023 09:27PM UTC coverage: 91.724% (-0.002%) from 91.726%
4876456163

push

github

77612 of 84615 relevant lines covered (91.72%)

11907228.65 hits per line

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

93.33
/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/mac.h>
12
#include <botan/rng.h>
13
#include <botan/pwdhash.h>
14
#include <botan/data_src.h>
15
#include <botan/pem.h>
16
#include <botan/internal/loadstor.h>
17
#include <botan/mem_ops.h>
18

19
namespace Botan::CryptoBox {
20

21
namespace {
22

23
/*
24
First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits
25
for later use as flags, etc if needed
26
*/
27
const uint32_t CRYPTOBOX_VERSION_CODE = 0xEFC22400;
28

29
const size_t VERSION_CODE_LEN = 4;
30
const size_t CIPHER_KEY_LEN = 32;
31
const size_t CIPHER_IV_LEN = 16;
32
const size_t MAC_KEY_LEN = 32;
33
const size_t MAC_OUTPUT_LEN = 20;
34
const size_t PBKDF_SALT_LEN = 10;
35
const size_t PBKDF_ITERATIONS = 8 * 1024;
36

37
const size_t CRYPTOBOX_HEADER_LEN = VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN;
38

39
}
40

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

59
   // Generate the keys and IV
60

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

64
   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);
18✔
65

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

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

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

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

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

92
   return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE");
18✔
93
   }
126✔
94

95
secure_vector<uint8_t>
96
decrypt_bin(const uint8_t input[], size_t input_len,
36✔
97
            std::string_view passphrase)
98
   {
99
   DataSource_Memory input_src(input, input_len);
36✔
100
   secure_vector<uint8_t> ciphertext =
36✔
101
      PEM_Code::decode_check_label(input_src,
102
                                   "BOTAN CRYPTOBOX MESSAGE");
54✔
103

104
   if(ciphertext.size() < CRYPTOBOX_HEADER_LEN)
36✔
105
      throw Decoding_Error("Invalid CryptoBox input");
×
106

107
   for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
180✔
108
      {
109
      uint32_t version = load_be<uint32_t>(ciphertext.data(), 0);
144✔
110
      if(version != CRYPTOBOX_VERSION_CODE)
144✔
111
         throw Decoding_Error("Bad CryptoBox version");
×
112
      }
113

114
   const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN];
36✔
115
   const uint8_t* box_mac = &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN];
36✔
116

117
   auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
54✔
118
   auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);
36✔
119

120
   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);
54✔
121

122
   pbkdf->derive_key(
36✔
123
      master_key.data(), master_key.size(),
124
      passphrase.data(), passphrase.size(),
125
      pbkdf_salt, PBKDF_SALT_LEN);
126

127
   const uint8_t* mk = master_key.data();
36✔
128
   const uint8_t* cipher_key = mk;
36✔
129
   const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
36✔
130
   const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;
36✔
131

132
   // Now authenticate and decrypt
133
   std::unique_ptr<MessageAuthenticationCode> hmac =
36✔
134
      MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
54✔
135
   hmac->set_key(mac_key, MAC_KEY_LEN);
36✔
136

137
   if(ciphertext.size() > CRYPTOBOX_HEADER_LEN)
36✔
138
      {
139
      hmac->update(&ciphertext[CRYPTOBOX_HEADER_LEN],
34✔
140
                   ciphertext.size() - CRYPTOBOX_HEADER_LEN);
34✔
141
      }
142
   secure_vector<uint8_t> computed_mac = hmac->final();
36✔
143

144
   if(!constant_time_compare(computed_mac.data(), box_mac, MAC_OUTPUT_LEN))
36✔
145
      throw Decoding_Error("CryptoBox integrity failure");
18✔
146

147
   auto ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", Cipher_Dir::Decryption);
36✔
148
   ctr->set_key(cipher_key, CIPHER_KEY_LEN);
18✔
149
   ctr->start(iv, CIPHER_IV_LEN);
18✔
150
   ctr->finish(ciphertext, CRYPTOBOX_HEADER_LEN);
18✔
151

152
   ciphertext.erase(ciphertext.begin(), ciphertext.begin() + CRYPTOBOX_HEADER_LEN);
18✔
153
   return ciphertext;
18✔
154
   }
234✔
155

156
BOTAN_DIAGNOSTIC_PUSH
157
BOTAN_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
158

159
secure_vector<uint8_t> decrypt_bin(std::string_view input,
18✔
160
                                   std::string_view passphrase)
161
   {
162
   return decrypt_bin(cast_char_ptr_to_uint8(input.data()),
18✔
163
                      input.size(),
164
                      passphrase);
18✔
165
   }
166

167
std::string decrypt(const uint8_t input[], size_t input_len,
18✔
168
                    std::string_view passphrase)
169
   {
170
   const secure_vector<uint8_t> bin = decrypt_bin(input, input_len, passphrase);
18✔
171

172
   return std::string(cast_uint8_ptr_to_char(&bin[0]),
×
173
                      bin.size());
×
174
   }
×
175

176
std::string decrypt(std::string_view input,
18✔
177
                    std::string_view passphrase)
178
   {
179
   return decrypt(cast_char_ptr_to_uint8(input.data()),
18✔
180
                  input.size(), passphrase);
18✔
181
   }
182
BOTAN_DIAGNOSTIC_POP
183

184
}
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

© 2025 Coveralls, Inc