Coverage Report

Created: 2021-02-21 07:20

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