Coverage Report

Created: 2020-02-14 15:38

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