9#include <botan/internal/ccm.h>
11#include <botan/exceptn.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/loadstor.h>
19static const size_t CCM_BS = 16;
26 if(m_cipher->block_size() != CCM_BS) {
27 throw Invalid_Argument(m_cipher->name() +
" cannot be used with CCM mode");
31 throw Invalid_Argument(fmt(
"Invalid CCM L value {}", L));
35 throw Invalid_Argument(fmt(
"Invalid CCM tag length {}", tag_size));
51 return fmt(
"{}/CCM({},{})", m_cipher->name(),
tag_size(),
L());
55 return (length == (15 -
L()));
68 return m_cipher->parallel_bytes();
76 return m_cipher->key_spec();
80 return m_cipher->has_keying_material();
83void CCM_Mode::key_schedule(std::span<const uint8_t> key) {
84 m_cipher->set_key(key);
88 BOTAN_ARG_CHECK(idx == 0,
"CCM: cannot handle non-zero index in set_associated_data_n");
94 BOTAN_ARG_CHECK(ad.size() < (0xFFFF - 0xFF),
"Supported CCM AD length");
96 m_ad_buf.push_back(
get_byte<0>(
static_cast<uint16_t
>(ad.size())));
97 m_ad_buf.push_back(
get_byte<1>(
static_cast<uint16_t
>(ad.size())));
98 m_ad_buf.insert(m_ad_buf.end(), ad.begin(), ad.end());
99 while(m_ad_buf.size() % CCM_BS != 0) {
100 m_ad_buf.push_back(0);
105void CCM_Mode::start_msg(
const uint8_t nonce[],
size_t nonce_len) {
110 m_nonce.assign(nonce, nonce + nonce_len);
114size_t CCM_Mode::process_msg(uint8_t buf[],
size_t sz) {
116 m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
121 const size_t len_bytes =
L();
125 for(
size_t i = 0; i != len_bytes; ++i) {
126 out[len_bytes - 1 - i] =
get_byte_var(
sizeof(uint64_t) - 1 - i, len);
129 if(len_bytes < 8 && (len >> (len_bytes * 8)) > 0) {
130 throw Encoding_Error(
"CCM message length too long to encode in L field");
135 for(
size_t i = 0; i != C.size(); ++i) {
136 uint8_t& b = C[C.size() - i - 1];
145 if(m_nonce.size() != 15 -
L()) {
150 const uint8_t b_flags =
151 static_cast<uint8_t
>((!m_ad_buf.empty() ? 64 : 0) + (((
tag_size() / 2) - 1) << 3) + (
L() - 1));
154 copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
161 if(m_nonce.size() != 15 -
L()) {
166 const uint8_t a_flags =
static_cast<uint8_t
>(
L() - 1);
169 copy_mem(&C[1], m_nonce.data(), m_nonce.size());
177 buffer.insert(buffer.begin() + offset,
msg_buf().begin(),
msg_buf().end());
179 const size_t sz = buffer.size() - offset;
180 uint8_t* buf = buffer.data() + offset;
190 for(
size_t i = 0; i != ad.size(); i += CCM_BS) {
191 xor_buf(T.data(), &ad[i], CCM_BS);
202 const uint8_t* buf_end = &buf[sz];
204 while(buf != buf_end) {
205 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
207 xor_buf(T.data(), buf, to_proc);
211 xor_buf(buf, X.data(), to_proc);
219 buffer += std::make_pair(T.data(),
tag_size());
227 buffer.insert(buffer.begin() + offset,
msg_buf().begin(),
msg_buf().end());
229 const size_t sz = buffer.size() - offset;
230 uint8_t* buf = buffer.data() + offset;
237 const BlockCipher& E =
cipher();
242 for(
size_t i = 0; i != ad.size(); i += CCM_BS) {
243 xor_buf(T.data(), &ad[i], CCM_BS);
255 const uint8_t* buf_end = &buf[sz -
tag_size()];
257 while(buf != buf_end) {
258 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
261 xor_buf(buf, X.data(), to_proc);
264 xor_buf(T.data(), buf, to_proc);
273 throw Invalid_Authentication_Tag(
"CCM tag check failed");
276 buffer.resize(buffer.size() -
tag_size());
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
void encrypt(const uint8_t in[], uint8_t out[]) const
size_t ideal_granularity() const final
bool requires_entire_message() const final
static void inc(secure_vector< uint8_t > &C)
size_t update_granularity() const final
secure_vector< uint8_t > & msg_buf()
const BlockCipher & cipher() const
void encode_length(uint64_t len, uint8_t out[])
size_t tag_size() const final
Key_Length_Specification key_spec() const final
bool valid_nonce_length(size_t length) const final
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) final
secure_vector< uint8_t > format_c0()
bool has_keying_material() const final
std::string name() const final
const secure_vector< uint8_t > & ad_buf() const
CCM_Mode(std::unique_ptr< BlockCipher > cipher, size_t tag_size, size_t L)
secure_vector< uint8_t > format_b0(size_t msg_size)
size_t default_nonce_length() const final
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
constexpr uint8_t get_byte(T input)
constexpr void copy_mem(T *out, const T *in, size_t n)
std::string fmt(std::string_view format, const T &... args)
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
std::vector< T, secure_allocator< T > > secure_vector
constexpr uint8_t get_byte_var(size_t byte_num, T input)