Coverage Report

Created: 2023-12-08 07:00

/src/botan/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp
Line
Count
Source (jump to first uncovered line)
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/internal/ct_utils.h>
12
#include <botan/internal/loadstor.h>
13
14
namespace Botan {
15
16
ChaCha20Poly1305_Mode::ChaCha20Poly1305_Mode() :
17
0
      m_chacha(StreamCipher::create("ChaCha")), m_poly1305(MessageAuthenticationCode::create("Poly1305")) {
18
0
   if(!m_chacha || !m_poly1305) {
19
0
      throw Algorithm_Not_Found("ChaCha20Poly1305");
20
0
   }
21
0
}
22
23
0
bool ChaCha20Poly1305_Mode::valid_nonce_length(size_t n) const {
24
0
   return (n == 8 || n == 12 || n == 24);
25
0
}
26
27
0
size_t ChaCha20Poly1305_Mode::update_granularity() const {
28
0
   return 1;
29
0
}
30
31
0
size_t ChaCha20Poly1305_Mode::ideal_granularity() const {
32
0
   return 128;
33
0
}
34
35
0
void ChaCha20Poly1305_Mode::clear() {
36
0
   m_chacha->clear();
37
0
   m_poly1305->clear();
38
0
   reset();
39
0
}
40
41
0
void ChaCha20Poly1305_Mode::reset() {
42
0
   m_ad.clear();
43
0
   m_ctext_len = 0;
44
0
   m_nonce_len = 0;
45
0
}
46
47
0
bool ChaCha20Poly1305_Mode::has_keying_material() const {
48
0
   return m_chacha->has_keying_material();
49
0
}
50
51
0
void ChaCha20Poly1305_Mode::key_schedule(std::span<const uint8_t> key) {
52
0
   m_chacha->set_key(key);
53
0
}
54
55
0
void ChaCha20Poly1305_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
56
0
   BOTAN_ARG_CHECK(idx == 0, "ChaCha20Poly1305: cannot handle non-zero index in set_associated_data_n");
57
0
   if(m_ctext_len > 0 || m_nonce_len > 0) {
58
0
      throw Invalid_State("Cannot set AD for ChaCha20Poly1305 while processing a message");
59
0
   }
60
0
   m_ad.assign(ad.begin(), ad.end());
61
0
}
62
63
0
void ChaCha20Poly1305_Mode::update_len(size_t len) {
64
0
   uint8_t len8[8] = {0};
65
0
   store_le(static_cast<uint64_t>(len), len8);
66
0
   m_poly1305->update(len8, 8);
67
0
}
68
69
0
void ChaCha20Poly1305_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
70
0
   if(!valid_nonce_length(nonce_len)) {
71
0
      throw Invalid_IV_Length(name(), nonce_len);
72
0
   }
73
74
0
   m_ctext_len = 0;
75
0
   m_nonce_len = nonce_len;
76
77
0
   m_chacha->set_iv(nonce, nonce_len);
78
79
0
   uint8_t first_block[64];
80
0
   m_chacha->write_keystream(first_block, sizeof(first_block));
81
82
0
   m_poly1305->set_key(first_block, 32);
83
   // Remainder of first block is discarded
84
0
   secure_scrub_memory(first_block, sizeof(first_block));
85
86
0
   m_poly1305->update(m_ad);
87
88
0
   if(cfrg_version()) {
89
0
      if(m_ad.size() % 16) {
90
0
         const uint8_t zeros[16] = {0};
91
0
         m_poly1305->update(zeros, 16 - m_ad.size() % 16);
92
0
      }
93
0
   } else {
94
0
      update_len(m_ad.size());
95
0
   }
96
0
}
97
98
0
size_t ChaCha20Poly1305_Encryption::process_msg(uint8_t buf[], size_t sz) {
99
0
   m_chacha->cipher1(buf, sz);
100
0
   m_poly1305->update(buf, sz);  // poly1305 of ciphertext
101
0
   m_ctext_len += sz;
102
0
   return sz;
103
0
}
104
105
0
void ChaCha20Poly1305_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
106
0
   update(buffer, offset);
107
0
   if(cfrg_version()) {
108
0
      if(m_ctext_len % 16) {
109
0
         const uint8_t zeros[16] = {0};
110
0
         m_poly1305->update(zeros, 16 - m_ctext_len % 16);
111
0
      }
112
0
      update_len(m_ad.size());
113
0
   }
114
0
   update_len(m_ctext_len);
115
116
0
   buffer.resize(buffer.size() + tag_size());
117
0
   m_poly1305->final(&buffer[buffer.size() - tag_size()]);
118
0
   m_ctext_len = 0;
119
0
   m_nonce_len = 0;
120
0
}
121
122
0
size_t ChaCha20Poly1305_Decryption::process_msg(uint8_t buf[], size_t sz) {
123
0
   m_poly1305->update(buf, sz);  // poly1305 of ciphertext
124
0
   m_chacha->cipher1(buf, sz);
125
0
   m_ctext_len += sz;
126
0
   return sz;
127
0
}
128
129
0
void ChaCha20Poly1305_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
130
0
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
131
0
   const size_t sz = buffer.size() - offset;
132
0
   uint8_t* buf = buffer.data() + offset;
133
134
0
   BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
135
136
0
   const size_t remaining = sz - tag_size();
137
138
0
   if(remaining) {
139
0
      m_poly1305->update(buf, remaining);  // poly1305 of ciphertext
140
0
      m_chacha->cipher1(buf, remaining);
141
0
      m_ctext_len += remaining;
142
0
   }
143
144
0
   if(cfrg_version()) {
145
0
      if(m_ctext_len % 16) {
146
0
         const uint8_t zeros[16] = {0};
147
0
         m_poly1305->update(zeros, 16 - m_ctext_len % 16);
148
0
      }
149
0
      update_len(m_ad.size());
150
0
   }
151
152
0
   update_len(m_ctext_len);
153
154
0
   uint8_t mac[16];
155
0
   m_poly1305->final(mac);
156
157
0
   const uint8_t* included_tag = &buf[remaining];
158
159
0
   m_ctext_len = 0;
160
0
   m_nonce_len = 0;
161
162
0
   if(!CT::is_equal(mac, included_tag, tag_size()).as_bool()) {
163
0
      throw Invalid_Authentication_Tag("ChaCha20Poly1305 tag check failed");
164
0
   }
165
0
   buffer.resize(offset + remaining);
166
0
}
167
168
}  // namespace Botan