Botan  2.11.0
Crypto and TLS for C++11
commoncrypto_mode.cpp
Go to the documentation of this file.
1 /*
2 * Cipher Modes via CommonCrypto
3 * (C) 2018 Jose Pereira
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/cipher_mode.h>
9 #include <botan/internal/rounding.h>
10 #include <botan/internal/commoncrypto.h>
11 
12 #include "commoncrypto_utils.h"
13 
14 #include <limits.h>
15 
16 namespace Botan {
17 
18 namespace {
19 
20 class CommonCrypto_Cipher_Mode final : public Cipher_Mode
21  {
22  public:
23  CommonCrypto_Cipher_Mode(const std::string& name,
24  Cipher_Dir direction,
25  const CommonCryptor_Opts& opts);
26 
27  ~CommonCrypto_Cipher_Mode();
28 
29  std::string provider() const override { return "commoncrypto"; }
30  std::string name() const override { return m_mode_name; }
31 
32  void start_msg(const uint8_t nonce[], size_t nonce_len) override;
33  size_t process(uint8_t msg[], size_t msg_len) override;
34  void finish(secure_vector<uint8_t>& final_block, size_t offset0) override;
35  size_t output_length(size_t input_length) const override;
36  size_t update_granularity() const override;
37  size_t minimum_final_size() const override;
38  size_t default_nonce_length() const override;
39  bool valid_nonce_length(size_t nonce_len) const override;
40  void clear() override;
41  void reset() override;
42  Key_Length_Specification key_spec() const override;
43 
44  private:
45  void key_schedule(const uint8_t key[], size_t length) override;
46 
47  const std::string m_mode_name;
48  Cipher_Dir m_direction;
49  CommonCryptor_Opts m_opts;
50  CCCryptorRef m_cipher = nullptr;
51  bool m_key_set;
52  bool m_nonce_set;
53  };
54 
55 CommonCrypto_Cipher_Mode::CommonCrypto_Cipher_Mode(const std::string& name,
56  Cipher_Dir direction, const CommonCryptor_Opts& opts) :
57  m_mode_name(name),
58  m_direction(direction),
59  m_opts(opts),
60  m_key_set(false),
61  m_nonce_set(false)
62  {
63  }
64 
65 CommonCrypto_Cipher_Mode::~CommonCrypto_Cipher_Mode()
66  {
67  if(m_cipher)
68  {
69  CCCryptorRelease(m_cipher);
70  }
71  }
72 
73 void CommonCrypto_Cipher_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
74  {
75  verify_key_set(m_key_set);
76 
77  if(!valid_nonce_length(nonce_len))
78  { throw Invalid_IV_Length(name(), nonce_len); }
79  if(nonce_len)
80  {
81  CCCryptorStatus status = CCCryptorReset(m_cipher, nonce);
82  if(status != kCCSuccess)
83  {
84  throw CommonCrypto_Error("CCCryptorReset on start_msg", status);
85  }
86  }
87  m_nonce_set = true;
88  }
89 
90 size_t CommonCrypto_Cipher_Mode::process(uint8_t msg[], size_t msg_len)
91  {
92  verify_key_set(m_key_set);
93  BOTAN_STATE_CHECK(m_nonce_set);
94 
95  if(msg_len == 0)
96  { return 0; }
97  if(msg_len > INT_MAX)
98  { throw Internal_Error("msg_len overflow"); }
99  size_t outl = CCCryptorGetOutputLength(m_cipher, msg_len, false);
100 
101  secure_vector<uint8_t> out(outl);
102 
103  if(m_opts.padding == ccNoPadding && msg_len % m_opts.block_size)
104  {
105  msg_len = outl;
106  }
107 
108  CCCryptorStatus status = CCCryptorUpdate(m_cipher, msg, msg_len,
109  out.data(), outl, &outl);
110  if(status != kCCSuccess)
111  {
112  throw CommonCrypto_Error("CCCryptorUpdate", status);
113  }
114  copy_mem(msg, out.data(), outl);
115 
116  return outl;
117  }
118 
119 void CommonCrypto_Cipher_Mode::finish(secure_vector<uint8_t>& buffer,
120  size_t offset)
121  {
122  verify_key_set(m_key_set);
123  BOTAN_STATE_CHECK(m_nonce_set);
124 
125  BOTAN_ASSERT(buffer.size() >= offset, "Offset ok");
126  uint8_t* buf = buffer.data() + offset;
127  const size_t buf_size = buffer.size() - offset;
128 
129  size_t written = process(buf, buf_size);
130 
131  size_t outl = CCCryptorGetOutputLength(m_cipher, buf_size - written, true);
132  secure_vector<uint8_t> out(outl);
133 
134  CCCryptorStatus status = CCCryptorFinal(
135  m_cipher, out.data(), outl, &outl);
136  if(status != kCCSuccess)
137  {
138  throw CommonCrypto_Error("CCCryptorFinal", status);
139  }
140 
141  size_t new_len = offset + written + outl;
142  if(m_opts.padding != ccNoPadding || buffer.size() < new_len)
143  {
144  buffer.resize(new_len);
145  }
146  copy_mem(buffer.data() - offset + written, out.data(), outl);
147  written += outl;
148  }
149 
150 size_t CommonCrypto_Cipher_Mode::update_granularity() const
151  {
152  return m_opts.block_size * BOTAN_BLOCK_CIPHER_PAR_MULT;
153  }
154 
155 size_t CommonCrypto_Cipher_Mode::minimum_final_size() const
156  {
157  if(m_direction == ENCRYPTION)
158  return 0;
159  else
160  return m_opts.block_size;
161  }
162 
163 size_t CommonCrypto_Cipher_Mode::default_nonce_length() const
164  {
165  return m_opts.block_size;
166  }
167 
168 bool CommonCrypto_Cipher_Mode::valid_nonce_length(size_t nonce_len) const
169  {
170  return (nonce_len == 0 || nonce_len == m_opts.block_size);
171  }
172 
173 size_t CommonCrypto_Cipher_Mode::output_length(size_t input_length) const
174  {
175  if(input_length == 0)
176  { return m_opts.block_size; }
177  else
178  { return round_up(input_length, m_opts.block_size); }
179  }
180 
181 void CommonCrypto_Cipher_Mode::clear()
182  {
183  m_key_set = false;
184 
185  if(m_cipher == nullptr)
186  {
187  return;
188  }
189 
190  if(m_cipher)
191  {
192  CCCryptorRelease(m_cipher);
193  m_cipher = nullptr;
194  }
195  }
196 
197 void CommonCrypto_Cipher_Mode::reset()
198  {
199  if(m_cipher == nullptr)
200  {
201  return;
202  }
203 
204  m_nonce_set = false;
205 
206  CCCryptorStatus status = CCCryptorReset(m_cipher, nullptr);
207  if(status != kCCSuccess)
208  {
209  throw CommonCrypto_Error("CCCryptorReset", status);
210  }
211  }
212 
213 Key_Length_Specification CommonCrypto_Cipher_Mode::key_spec() const
214  {
215  return m_opts.key_spec;
216  }
217 
218 void CommonCrypto_Cipher_Mode::key_schedule(const uint8_t key[], size_t length)
219  {
220  CCCryptorStatus status;
221  CCOperation op = m_direction == ENCRYPTION ? kCCEncrypt : kCCDecrypt;
222  status = CCCryptorCreateWithMode(op, m_opts.mode, m_opts.algo, m_opts.padding,
223  nullptr, key, length, nullptr, 0, 0, 0, &m_cipher);
224  if(status != kCCSuccess)
225  {
226  throw CommonCrypto_Error("CCCryptorCreate", status);
227  }
228 
229  m_key_set = true;
230  m_nonce_set = false;
231  }
232 }
233 
234 Cipher_Mode*
235 make_commoncrypto_cipher_mode(const std::string& name, Cipher_Dir direction)
236  {
237 
238  try
239  {
241  return new CommonCrypto_Cipher_Mode(name, direction, opts);
242  }
243  catch(CommonCrypto_Error& e)
244  {
245  return nullptr;
246  }
247  }
248 }
CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string &algo)
int(* final)(unsigned char *, CTX *)
CommonCryptor_Opts m_opts
#define BOTAN_STATE_CHECK(expr)
Definition: assert.h:49
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
std::string name
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:122
Definition: alg_id.cpp:13
bool m_key_set
Cipher_Dir
Definition: cipher_mode.h:23
size_t round_up(size_t n, size_t align_to)
Definition: rounding.h:21
Cipher_Mode * make_commoncrypto_cipher_mode(const std::string &name, Cipher_Dir direction)