Coverage Report

Created: 2020-11-21 08:34

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