Botan 3.11.0
Crypto and TLS for C&
chacha20poly1305.cpp
Go to the documentation of this file.
1/*
2* ChaCha20Poly1305 AEAD
3* (C) 2014,2016,2018 Jack Lloyd
4* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/chacha20poly1305.h>
10
11#include <botan/exceptn.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/loadstor.h>
14
15namespace Botan {
16
23
25 return (n == 8 || n == 12 || n == 24);
26}
27
29 return 1;
30}
31
33 return 128;
34}
35
37 m_chacha->clear();
38 m_poly1305->clear();
39 reset();
40}
41
43 m_ad.clear();
44 m_ctext_len = 0;
45 m_nonce_len = 0;
46}
47
49 return m_chacha->has_keying_material();
50}
51
52void ChaCha20Poly1305_Mode::key_schedule(std::span<const uint8_t> key) {
53 m_chacha->set_key(key);
54}
55
56void ChaCha20Poly1305_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
57 BOTAN_ARG_CHECK(idx == 0, "ChaCha20Poly1305: cannot handle non-zero index in set_associated_data_n");
58 if(m_ctext_len > 0 || m_nonce_len > 0) {
59 throw Invalid_State("Cannot set AD for ChaCha20Poly1305 while processing a message");
60 }
61 m_ad.assign(ad.begin(), ad.end());
62}
63
65 uint8_t len8[8] = {0};
66 store_le(static_cast<uint64_t>(len), len8);
67 m_poly1305->update(len8, 8);
68}
69
70void ChaCha20Poly1305_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 m_ctext_len = 0;
76 m_nonce_len = nonce_len;
77
78 m_chacha->set_iv(nonce, nonce_len);
79
80 uint8_t first_block[64];
81 m_chacha->write_keystream(first_block, sizeof(first_block));
82
83 m_poly1305->set_key(first_block, 32);
84 // Remainder of first block is discarded
85 secure_scrub_memory(first_block, sizeof(first_block));
86
87 m_poly1305->update(m_ad);
88
89 if(cfrg_version()) {
90 if(m_ad.size() % 16 != 0) {
91 const uint8_t zeros[16] = {0};
92 m_poly1305->update(zeros, 16 - m_ad.size() % 16);
93 }
94 } else {
95 update_len(m_ad.size());
96 }
97}
98
99size_t ChaCha20Poly1305_Encryption::process_msg(uint8_t buf[], size_t sz) {
100 m_chacha->cipher1(buf, sz);
101 m_poly1305->update(buf, sz); // poly1305 of ciphertext
102 m_ctext_len += sz;
103 return sz;
104}
105
106void ChaCha20Poly1305_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
107 update(buffer, offset);
108 if(cfrg_version()) {
109 if(m_ctext_len % 16 != 0) {
110 const uint8_t zeros[16] = {0};
111 m_poly1305->update(zeros, 16 - m_ctext_len % 16);
112 }
113 update_len(m_ad.size());
114 }
116
117 buffer.resize(buffer.size() + tag_size());
118 m_poly1305->final(&buffer[buffer.size() - tag_size()]);
119 m_ctext_len = 0;
120 m_nonce_len = 0;
121}
122
123size_t ChaCha20Poly1305_Decryption::process_msg(uint8_t buf[], size_t sz) {
124 m_poly1305->update(buf, sz); // poly1305 of ciphertext
125 m_chacha->cipher1(buf, sz);
126 m_ctext_len += sz;
127 return sz;
128}
129
130void ChaCha20Poly1305_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
131 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
132 const size_t sz = buffer.size() - offset;
133 uint8_t* buf = buffer.data() + offset;
134
135 BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
136
137 const size_t remaining = sz - tag_size();
138
139 if(remaining > 0) {
140 m_poly1305->update(buf, remaining); // poly1305 of ciphertext
141 m_chacha->cipher1(buf, remaining);
142 m_ctext_len += remaining;
143 }
144
145 if(cfrg_version()) {
146 if(m_ctext_len % 16 != 0) {
147 const uint8_t zeros[16] = {0};
148 m_poly1305->update(zeros, 16 - m_ctext_len % 16);
149 }
150 update_len(m_ad.size());
151 }
152
154
155 uint8_t mac[16];
156 m_poly1305->final(mac);
157
158 const uint8_t* included_tag = &buf[remaining];
159
160 m_ctext_len = 0;
161 m_nonce_len = 0;
162
163 if(!CT::is_equal(mac, included_tag, tag_size()).as_bool()) {
164 throw Invalid_Authentication_Tag("ChaCha20Poly1305 tag check failed");
165 }
166 buffer.resize(offset + remaining);
167}
168
169} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
static std::unique_ptr< AEAD_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition aead.cpp:59
bool has_keying_material() const final
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) final
bool valid_nonce_length(size_t n) const override
secure_vector< uint8_t > m_ad
size_t ideal_granularity() const override
std::string name() const override
std::unique_ptr< StreamCipher > m_chacha
size_t update_granularity() const override
size_t tag_size() const override
std::unique_ptr< MessageAuthenticationCode > m_poly1305
void update(T &buffer, size_t offset=0)
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
void secure_scrub_memory(void *ptr, size_t n)
Definition mem_utils.cpp:25
constexpr auto store_le(ParamTs &&... params)
Definition loadstor.h:736
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68