Coverage Report

Created: 2022-01-14 08:07

/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
368
   {
23
368
   if(cipher->block_size() != GCM_BS)
24
0
      throw Invalid_Argument("Invalid block cipher for GCM");
25
26
368
   m_ctr = std::make_unique<CTR_BE>(std::move(cipher), 4);
27
368
   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
368
   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
368
   }
34
35
368
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
604
   {
66
   // GCM does not support empty nonces
67
604
   return (len > 0);
68
604
   }
69
70
Key_Length_Specification GCM_Mode::key_spec() const
71
368
   {
72
368
   return m_ctr->key_spec();
73
368
   }
74
75
void GCM_Mode::key_schedule(const uint8_t key[], size_t keylen)
76
368
   {
77
368
   m_ctr->set_key(key, keylen);
78
79
368
   const std::vector<uint8_t> zeros(GCM_BS);
80
368
   m_ctr->set_iv(zeros.data(), zeros.size());
81
82
368
   secure_vector<uint8_t> H(GCM_BS);
83
368
   m_ctr->encipher(H);
84
368
   m_ghash->set_key(H);
85
368
   }
86
87
void GCM_Mode::set_associated_data(const uint8_t ad[], size_t ad_len)
88
377
   {
89
377
   m_ghash->set_associated_data(ad, ad_len);
90
377
   }
91
92
void GCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
93
377
   {
94
377
   if(!valid_nonce_length(nonce_len))
95
0
      throw Invalid_IV_Length(name(), nonce_len);
96
97
377
   if(m_y0.size() != GCM_BS)
98
345
      m_y0.resize(GCM_BS);
99
100
377
   clear_mem(m_y0.data(), m_y0.size());
101
102
377
   if(nonce_len == 12)
103
377
      {
104
377
      copy_mem(m_y0.data(), nonce, nonce_len);
105
377
      m_y0[15] = 1;
106
377
      }
107
0
   else
108
0
      {
109
0
      m_ghash->nonce_hash(m_y0, nonce, nonce_len);
110
0
      }
111
112
377
   m_ctr->set_iv(m_y0.data(), m_y0.size());
113
114
377
   clear_mem(m_y0.data(), m_y0.size());
115
377
   m_ctr->encipher(m_y0);
116
117
377
   m_ghash->start(m_y0.data(), m_y0.size());
118
377
   clear_mem(m_y0.data(), m_y0.size());
119
377
   }
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
300
   {
131
300
   BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
132
300
   const size_t sz = buffer.size() - offset;
133
300
   uint8_t* buf = buffer.data() + offset;
134
135
300
   m_ctr->cipher(buf, buf, sz);
136
300
   m_ghash->update(buf, sz);
137
138
300
   uint8_t mac[16] = { 0 };
139
300
   m_ghash->final(mac, tag_size());
140
300
   buffer += std::make_pair(mac, tag_size());
141
300
   }
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
77
   {
153
77
   BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
154
77
   const size_t sz = buffer.size() - offset;
155
77
   uint8_t* buf = buffer.data() + offset;
156
157
77
   if(sz < tag_size())
158
0
      throw Decoding_Error("Insufficient input for GCM decryption, tag missing");
159
160
77
   const size_t remaining = sz - tag_size();
161
162
   // handle any final input before the tag
163
77
   if(remaining)
164
76
      {
165
76
      m_ghash->update(buf, remaining);
166
76
      m_ctr->cipher(buf, buf, remaining);
167
76
      }
168
169
77
   uint8_t mac[16] = { 0 };
170
77
   m_ghash->final(mac, tag_size());
171
172
77
   const uint8_t* included_tag = &buffer[remaining+offset];
173
174
77
   if(!constant_time_compare(mac, included_tag, tag_size()))
175
77
      throw Invalid_Authentication_Tag("GCM tag check failed");
176
177
0
   buffer.resize(offset + remaining);
178
0
   }
179
180
}