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