9#include <botan/internal/ccm.h>
11#include <botan/exceptn.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/fmt.h>
15#include <botan/internal/int_utils.h>
16#include <botan/internal/loadstor.h>
21static const size_t CCM_BS = 16;
28 if(m_cipher->block_size() != CCM_BS) {
29 throw Invalid_Argument(m_cipher->name() +
" cannot be used with CCM mode");
33 throw Invalid_Argument(fmt(
"Invalid CCM L value {}", L));
37 throw Invalid_Argument(fmt(
"Invalid CCM tag length {}", tag_size));
53 return fmt(
"{}/CCM({},{})", m_cipher->name(),
tag_size(),
L());
57 return (length == (15 -
L()));
70 return m_cipher->parallel_bytes();
78 return m_cipher->key_spec();
82 return m_cipher->has_keying_material();
85void CCM_Mode::key_schedule(std::span<const uint8_t> key) {
86 m_cipher->set_key(key);
93 BOTAN_ARG_CHECK(idx == 0,
"CCM: cannot handle non-zero index in set_associated_data_n");
100 BOTAN_ARG_CHECK(ad.size() < (0xFFFF - 0xFF),
"Supported CCM AD length");
102 m_ad_buf.push_back(
get_byte<0>(
static_cast<uint16_t
>(ad.size())));
103 m_ad_buf.push_back(
get_byte<1>(
static_cast<uint16_t
>(ad.size())));
104 m_ad_buf.insert(m_ad_buf.end(), ad.begin(), ad.end());
105 while(m_ad_buf.size() % CCM_BS != 0) {
106 m_ad_buf.push_back(0);
111void CCM_Mode::start_msg(
const uint8_t nonce[],
size_t nonce_len) {
118 m_nonce.assign(nonce, nonce + nonce_len);
122size_t CCM_Mode::process_msg(uint8_t buf[],
size_t sz) {
124 m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
128 const uint64_t max_msg_len = (
static_cast<uint64_t
>(1) << (8 *
L())) - 1;
129 if(m_msg_buf.size() > max_msg_len) {
130 throw Invalid_State(
"CCM message length exceeds the limit for L");
138 const size_t len_bytes =
L();
142 for(
size_t i = 0; i != len_bytes; ++i) {
143 out[len_bytes - 1 - i] =
get_byte_var(
sizeof(uint64_t) - 1 - i, len);
146 if(len_bytes < 8 && (len >> (len_bytes * 8)) > 0) {
147 throw Encoding_Error(
"CCM message length too long to encode in L field");
152 for(
size_t i = 0; i != C.size(); ++i) {
153 uint8_t& b = C[C.size() - i - 1];
162 if(m_nonce.size() != 15 -
L()) {
167 const uint8_t b_flags =
168 static_cast<uint8_t
>((!m_ad_buf.empty() ? 64 : 0) + (((
tag_size() / 2) - 1) << 3) + (
L() - 1));
171 copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
178 if(m_nonce.size() != 15 -
L()) {
183 const uint8_t a_flags =
static_cast<uint8_t
>(
L() - 1);
186 copy_mem(&C[1], m_nonce.data(), m_nonce.size());
198 buffer.insert(buffer.begin() + offset,
msg_buf().begin(),
msg_buf().end());
200 const size_t sz = buffer.size() - offset;
201 uint8_t* buf = buffer.data() + offset;
211 for(
size_t i = 0; i != ad.size(); i += CCM_BS) {
212 xor_buf(T.data(), &ad[i], CCM_BS);
223 const uint8_t* buf_end = &buf[sz];
225 while(buf != buf_end) {
226 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
228 xor_buf(T.data(), buf, to_proc);
232 xor_buf(buf, X.data(), to_proc);
240 buffer += std::make_pair(T.data(),
tag_size());
253 buffer.insert(buffer.begin() + offset,
msg_buf().begin(),
msg_buf().end());
255 const size_t sz = buffer.size() - offset;
256 uint8_t* buf = buffer.data() + offset;
268 for(
size_t i = 0; i != ad.size(); i += CCM_BS) {
269 xor_buf(T.data(), &ad[i], CCM_BS);
281 const uint8_t* buf_end = &buf[sz -
tag_size()];
283 while(buf != buf_end) {
284 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
287 xor_buf(buf, X.data(), to_proc);
290 xor_buf(T.data(), buf, to_proc);
303 throw Invalid_Authentication_Tag(
"CCM tag check failed");
306 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 output_length(size_t input_length) const override
size_t output_length(size_t input_length) const override
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 T add_or_throw(T a, T b, std::string_view msg)
constexpr uint8_t get_byte(T input)
std::string fmt(std::string_view format, const T &... args)
constexpr void copy_mem(T *out, const T *in, size_t n)
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)
constexpr void clear_mem(T *ptr, size_t n)