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