Botan  2.1.0
Crypto and TLS for C++11
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,
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 
92  pipe.read(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], MAC_OUTPUT_LEN, 1),
93  MAC_OUTPUT_LEN, "MAC output");
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 =
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 }
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
virtual void randomize(uint8_t output[], size_t length)=0
size_t remaining(message_id msg=DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT
Definition: pipe_rw.cpp:130
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
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
size_t read(uint8_t output[], size_t length) override BOTAN_WARN_UNUSED_RESULT
Definition: pipe_rw.cpp:81
std::string encrypt(const uint8_t input[], size_t input_len, const std::string &passphrase, RandomNumberGenerator &rng)
Definition: cryptobox.cpp:42
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition: assert.h:53
std::string read_all_as_string(message_id=DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT
Definition: pipe_rw.cpp:109
std::string decrypt(const uint8_t input[], size_t input_len, const std::string &passphrase)
Definition: cryptobox.cpp:102
void process_msg(const uint8_t in[], size_t length)
Definition: pipe.cpp:117
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:68
Definition: alg_id.cpp:13
secure_vector< uint8_t > decode_check_label(DataSource &source, const std::string &label_want)
Definition: pem.cpp:54
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:47
const uint8_t * begin() const
Definition: symkey.h:36
Keyed_Filter * get_cipher(const std::string &algo_spec, Cipher_Dir direction)
Definition: key_filt.cpp:12