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