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