Botan 3.13.0
Crypto and TLS for C&
ascon_aead128.cpp
Go to the documentation of this file.
1/*
2* Ascon-AEAD128 AEAD
3* (C) 2025 Jack Lloyd
4* 2025 René Meusel
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/ascon_aead128.h>
10
11#include <botan/exceptn.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/concat_util.h>
14#include <botan/internal/int_utils.h>
15#include <botan/internal/loadstor.h>
16
17namespace Botan {
18
19namespace {
20
21constexpr void xor2x64(std::span<uint64_t, 2> lhs, std::span<const uint64_t, 2> rhs) {
22 lhs[0] ^= rhs[0];
23 lhs[1] ^= rhs[1];
24}
25
26template <size_t N>
27constexpr auto as_array_of_uint64(std::span<const uint8_t> in) {
28 BOTAN_DEBUG_ASSERT(in.size() == N * sizeof(uint64_t));
29 return load_le<std::array<uint64_t, N>>(in.first<N * 8>());
30}
31
32// NIST SP.800-232 Appendix B (Table 13)
33constexpr Ascon_p initial_state_of_ascon_aead_permutation({
34 .init_and_final_rounds = 12,
35 .processing_rounds = 8,
36 .bit_rate = 128,
37 .initial_state = {},
38});
39
40// NIST SP.800-232 Section 5.1
41constexpr uint64_t ascon_aead_128_iv = 0x00001000808c0001;
42
43// NIST SP.800-232 Appendix A.2
44constexpr uint64_t ascon_aead_128_domain_sep = 0x8000000000000000;
45
46} // namespace
47
48Ascon_AEAD128_Mode::Ascon_AEAD128_Mode() : m_ascon_p(initial_state_of_ascon_aead_permutation) {}
49
55
57 if(m_key.has_value()) {
59 }
60 m_key.reset();
61 m_ad.clear();
62 reset();
63}
64
66 m_ascon_p = initial_state_of_ascon_aead_permutation;
67 m_started = false;
68 m_has_nonce = false;
69}
70
71void Ascon_AEAD128_Mode::key_schedule(std::span<const uint8_t> key) {
72 reset();
73 m_key = as_array_of_uint64<2>(key);
74}
75
76void Ascon_AEAD128_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
77 BOTAN_ARG_CHECK(idx == 0, "Ascon-AEAD128: cannot handle non-zero index in set_associated_data_n");
79 m_ad.assign(ad.begin(), ad.end());
80}
81
82void Ascon_AEAD128_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
83 BOTAN_ARG_CHECK(valid_nonce_length(nonce_len), "Invalid nonce length in Ascon-AEAD128");
84
87
88 m_ascon_p.state() = concat(std::array{ascon_aead_128_iv}, *m_key, as_array_of_uint64<2>({nonce, nonce_len}));
89 m_ascon_p.initial_permute();
90 xor2x64(m_ascon_p.range_of_state<3, 2>(), *m_key);
91
92 m_has_nonce = true;
93}
94
98
99 if(!m_started) {
100 if(!m_ad.empty()) {
101 m_ascon_p.absorb(m_ad);
102 m_ascon_p.intermediate_finish();
103 }
104 m_ascon_p.state()[4] ^= ascon_aead_128_domain_sep;
105
106 m_started = true;
107 }
108}
109
111 BOTAN_DEBUG_ASSERT(m_started);
112
113 xor2x64(m_ascon_p.range_of_state<2, 2>(), *m_key);
114 m_ascon_p.finish();
115 xor2x64(m_ascon_p.range_of_state<3, 2>(), *m_key);
116
117 auto tag = store_le(m_ascon_p.range_of_state<3, 2>());
118
119 reset();
120 return tag;
121}
122
123size_t Ascon_AEAD128_Encryption::output_length(size_t input_length) const {
124 return add_or_throw(input_length, tag_size(), "Ascon-AEAD128 input too large");
125}
126
127size_t Ascon_AEAD128_Encryption::process_msg(uint8_t buf[], size_t size) {
130
132 m_ascon_p.percolate_in({buf, size});
133 return size;
134}
135
136void Ascon_AEAD128_Encryption::finish_msg(secure_vector<uint8_t>& final_block, size_t offset) {
138 BOTAN_ARG_CHECK(final_block.size() >= offset, "Offset is out of range");
139
140 const auto final_block_at_offset = std::span{final_block}.subspan(offset);
141 process_msg(final_block_at_offset.data(), final_block_at_offset.size());
142 const auto tag = calculate_tag_and_finish();
143 final_block.insert(final_block.end(), tag.begin(), tag.end());
144}
145
146size_t Ascon_AEAD128_Decryption::output_length(size_t input_length) const {
147 BOTAN_ARG_CHECK(input_length >= tag_size(), "Message too short to be valid");
148 return input_length - tag_size();
149}
150
151size_t Ascon_AEAD128_Decryption::process_msg(uint8_t buf[], size_t size) {
154
156 m_ascon_p.percolate_out({buf, size});
157 return size;
158}
159
160void Ascon_AEAD128_Decryption::finish_msg(secure_vector<uint8_t>& final_block, size_t offset) {
162 BOTAN_ARG_CHECK(final_block.size() >= offset, "Offset is out of range");
163
164 const auto final_block_at_offset = std::span{final_block}.subspan(offset);
165 BOTAN_ARG_CHECK(final_block_at_offset.size() >= tag_size(), "input did not include the tag");
166 const auto final_ciphertext_block = final_block_at_offset.first(final_block_at_offset.size() - tag_size());
167 const auto expected_tag = final_block_at_offset.last(tag_size());
168
169 process_msg(final_ciphertext_block.data(), final_ciphertext_block.size());
170 if(!constant_time_compare(calculate_tag_and_finish(), expected_tag)) {
171 clear_mem(std::span{final_block}.subspan(offset, final_ciphertext_block.size()));
172 throw Invalid_Authentication_Tag("Ascon-AEAD128 tag check failed");
173 }
174
175 final_block.resize(offset + final_ciphertext_block.size());
176}
177
178} // namespace Botan
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
size_t output_length(size_t input_length) const override
size_t output_length(size_t input_length) const override
bool has_keying_material() const final
void key_schedule(std::span< const uint8_t > key) final
std::optional< std::array< uint64_t, 2 > > m_key
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) final
size_t tag_size() const final
bool valid_nonce_length(size_t n) const final
std::array< uint8_t, 16 > calculate_tag_and_finish()
void start_msg(const uint8_t nonce[], size_t nonce_len) final
void percolate_in(std::span< uint8_t > data)
void percolate_out(std::span< uint8_t > data)
constexpr T add_or_throw(T a, T b, std::string_view msg)
Definition int_utils.h:66
void secure_scrub_memory(void *ptr, size_t n)
Definition mem_utils.cpp:25
constexpr auto store_le(ParamTs &&... params)
Definition loadstor.h:736
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
bool constant_time_compare(std::span< const uint8_t > x, std::span< const uint8_t > y)
Definition mem_ops.cpp:17
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118