Botan 2.19.1
Crypto and TLS for C&
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
15namespace Botan {
16
17namespace {
18
19class 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
54CommonCrypto_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
64CommonCrypto_Cipher_Mode::~CommonCrypto_Cipher_Mode()
65 {
66 if(m_cipher)
67 {
68 CCCryptorRelease(m_cipher);
69 }
70 }
71
72void 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
89size_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
118void 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
149size_t CommonCrypto_Cipher_Mode::update_granularity() const
150 {
151 return m_opts.block_size * BOTAN_BLOCK_CIPHER_PAR_MULT;
152 }
153
154size_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
162size_t CommonCrypto_Cipher_Mode::default_nonce_length() const
163 {
164 return m_opts.block_size;
165 }
166
167bool 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
172size_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
180void 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
196void 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
212Key_Length_Specification CommonCrypto_Cipher_Mode::key_spec() const
213 {
214 return m_opts.key_spec;
215 }
216
217void 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
233Cipher_Mode*
234make_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}
#define BOTAN_STATE_CHECK(expr)
Definition: assert.h:49
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
bool m_key_set
CommonCryptor_Opts m_opts
std::string name
int(* final)(unsigned char *, CTX *)
Definition: alg_id.cpp:13
CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string &algo)
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
Cipher_Dir
Definition: cipher_mode.h:23
@ ENCRYPTION
Definition: cipher_mode.h:23
Cipher_Mode * make_commoncrypto_cipher_mode(const std::string &name, Cipher_Dir direction)
int32_t CCCryptorStatus
Definition: commoncrypto.h:23
size_t round_up(size_t n, size_t align_to)
Definition: rounding.h:21