Coverage Report

Created: 2022-09-23 06:05

/src/botan/src/lib/modes/aead/gcm/gcm.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* GCM Mode Encryption
3
* (C) 2013,2015 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/gcm.h>
10
#include <botan/internal/ghash.h>
11
#include <botan/block_cipher.h>
12
#include <botan/internal/ctr.h>
13
14
namespace Botan {
15
16
/*
17
* GCM_Mode Constructor
18
*/
19
GCM_Mode::GCM_Mode(std::unique_ptr<BlockCipher> cipher, size_t tag_size) :
20
   m_tag_size(tag_size),
21
   m_cipher_name(cipher->name())
22
397
   {
23
397
   if(cipher->block_size() != GCM_BS)
24
0
      throw Invalid_Argument("Invalid block cipher for GCM");
25
26
397
   m_ctr = std::make_unique<CTR_BE>(std::move(cipher), 4);
27
397
   m_ghash = std::make_unique<GHASH>();
28
29
   /* We allow any of the values 128, 120, 112, 104, or 96 bits as a tag size */
30
   /* 64 bit tag is still supported but deprecated and will be removed in the future */
31
397
   if(m_tag_size != 8 && (m_tag_size < 12 || m_tag_size > 16))
32
0
      throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size));
33
397
   }
34
35
397
GCM_Mode::~GCM_Mode() { /* for unique_ptr */ }
36
37
void GCM_Mode::clear()
38
0
   {
39
0
   m_ctr->clear();
40
0
   m_ghash->clear();
41
0
   reset();
42
0
   }
43
44
void GCM_Mode::reset()
45
0
   {
46
0
   m_ghash->reset();
47
0
   }
48
49
std::string GCM_Mode::name() const
50
0
   {
51
0
   return (m_cipher_name + "/GCM(" + std::to_string(tag_size()) + ")");
52
0
   }
53
54
std::string GCM_Mode::provider() const
55
0
   {
56
0
   return m_ghash->provider();
57
0
   }
58
59
size_t GCM_Mode::update_granularity() const
60
0
   {
61
0
   return GCM_BS * std::max<size_t>(2, BOTAN_BLOCK_CIPHER_PAR_MULT);
62
0
   }
63
64
bool GCM_Mode::valid_nonce_length(size_t len) const
65
628
   {
66
   // GCM does not support empty nonces
67
628
   return (len > 0);
68
628
   }
69
70
Key_Length_Specification GCM_Mode::key_spec() const
71
397
   {
72
397
   return m_ctr->key_spec();
73
397
   }
74
75
void GCM_Mode::key_schedule(const uint8_t key[], size_t keylen)
76
397
   {
77
397
   m_ctr->set_key(key, keylen);
78
79
397
   const std::vector<uint8_t> zeros(GCM_BS);
80
397
   m_ctr->set_iv(zeros.data(), zeros.size());
81
82
397
   secure_vector<uint8_t> H(GCM_BS);
83
397
   m_ctr->encipher(H);
84
397
   m_ghash->set_key(H);
85
397
   }
86
87
void GCM_Mode::set_associated_data(const uint8_t ad[], size_t ad_len)
88
413
   {
89
413
   m_ghash->set_associated_data(ad, ad_len);
90
413
   }
91
92
void GCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
93
413
   {
94
413
   if(!valid_nonce_length(nonce_len))
95
0
      throw Invalid_IV_Length(name(), nonce_len);
96
97
413
   if(m_y0.size() != GCM_BS)
98
366
      m_y0.resize(GCM_BS);
99
100
413
   clear_mem(m_y0.data(), m_y0.size());
101
102
413
   if(nonce_len == 12)
103
413
      {
104
413
      copy_mem(m_y0.data(), nonce, nonce_len);
105
413
      m_y0[15] = 1;
106
413
      }
107
0
   else
108
0
      {
109
0
      m_ghash->nonce_hash(m_y0, nonce, nonce_len);
110
0
      }
111
112
413
   m_ctr->set_iv(m_y0.data(), m_y0.size());
113
114
413
   clear_mem(m_y0.data(), m_y0.size());
115
413
   m_ctr->encipher(m_y0);
116
117
413
   m_ghash->start(m_y0.data(), m_y0.size());
118
413
   clear_mem(m_y0.data(), m_y0.size());
119
413
   }
120
121
size_t GCM_Encryption::process(uint8_t buf[], size_t sz)
122
0
   {
123
0
   BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size");
124
0
   m_ctr->cipher(buf, buf, sz);
125
0
   m_ghash->update(buf, sz);
126
0
   return sz;
127
0
   }
128
129
void GCM_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
130
327
   {
131
327
   BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
132
327
   const size_t sz = buffer.size() - offset;
133
327
   uint8_t* buf = buffer.data() + offset;
134
135
327
   m_ctr->cipher(buf, buf, sz);
136
327
   m_ghash->update(buf, sz);
137
138
327
   uint8_t mac[16] = { 0 };
139
327
   m_ghash->final(mac, tag_size());
140
327
   buffer += std::make_pair(mac, tag_size());
141
327
   }
142
143
size_t GCM_Decryption::process(uint8_t buf[], size_t sz)
144
0
   {
145
0
   BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size");
146
0
   m_ghash->update(buf, sz);
147
0
   m_ctr->cipher(buf, buf, sz);
148
0
   return sz;
149
0
   }
150
151
void GCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
152
86
   {
153
86
   BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
154
86
   const size_t sz = buffer.size() - offset;
155
86
   uint8_t* buf = buffer.data() + offset;
156
157
86
   if(sz < tag_size())
158
0
      throw Decoding_Error("Insufficient input for GCM decryption, tag missing");
159
160
86
   const size_t remaining = sz - tag_size();
161
162
   // handle any final input before the tag
163
86
   if(remaining)
164
85
      {
165
85
      m_ghash->update(buf, remaining);
166
85
      m_ctr->cipher(buf, buf, remaining);
167
85
      }
168
169
86
   uint8_t mac[16] = { 0 };
170
86
   m_ghash->final(mac, tag_size());
171
172
86
   const uint8_t* included_tag = &buffer[remaining+offset];
173
174
86
   if(!constant_time_compare(mac, included_tag, tag_size()))
175
86
      throw Invalid_Authentication_Tag("GCM tag check failed");
176
177
0
   buffer.resize(offset + remaining);
178
0
   }
179
180
}