Coverage Report

Created: 2023-02-22 06:14

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