ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
GCM.cpp
1 /*
2  * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "GCM.h"
24 #include "Crypto.h"
25 #include "utility/EndianUtil.h"
26 #include <string.h>
27 
45  : blockCipher(0)
46 {
47  state.authSize = 0;
48  state.dataSize = 0;
49  state.dataStarted = false;
50  state.posn = 16;
51 }
52 
57 {
58  clean(state);
59 }
60 
61 size_t GCMCommon::keySize() const
62 {
63  return blockCipher->keySize();
64 }
65 
66 size_t GCMCommon::ivSize() const
67 {
68  // The GCM specification recommends an IV size of 96 bits.
69  return 12;
70 }
71 
72 size_t GCMCommon::tagSize() const
73 {
74  return 16;
75 }
76 
77 bool GCMCommon::setKey(const uint8_t *key, size_t len)
78 {
79  // Set the encryption key for the block cipher.
80  if (!blockCipher->setKey(key, len))
81  return false;
82 
83  // Construct the hashing key by encrypting a zero block.
84  memset(state.nonce, 0, 16);
85  blockCipher->encryptBlock(state.nonce, state.nonce);
86  ghash.reset(state.nonce);
87  return true;
88 }
89 
90 bool GCMCommon::setIV(const uint8_t *iv, size_t len)
91 {
92  // Note: We assume that setKey() has already been called to
93  // set the hashing key in the "ghash" object and that the
94  // hashing key itself is still stored in "state.nonce".
95 
96  // Format the counter block from the IV.
97  if (len == 12) {
98  // IV's of exactly 96 bits are used directly as the counter block.
99  memcpy(state.counter, iv, 12);
100  state.counter[12] = 0;
101  state.counter[13] = 0;
102  state.counter[14] = 0;
103  state.counter[15] = 1;
104  } else {
105  // IV's of other sizes are hashed to produce the counter block.
106  ghash.update(iv, len);
107  ghash.pad();
108  uint64_t sizes[2] = {0, htobe64(((uint64_t)len) * 8)};
109  ghash.update(sizes, sizeof(sizes));
110  clean(sizes);
111  ghash.finalize(state.counter, 16);
112  ghash.reset(state.nonce);
113  }
114 
115  // Reset the GCM object ready to process auth or payload data.
116  state.authSize = 0;
117  state.dataSize = 0;
118  state.dataStarted = false;
119  state.posn = 16;
120 
121  // Replace the hash key in "nonce" with the encrypted counter.
122  // This value will be XOR'ed with the final authentication hash
123  // value in computeTag().
124  blockCipher->encryptBlock(state.nonce, state.counter);
125 }
126 
132 static inline void increment(uint8_t counter[16])
133 {
134  uint16_t carry = 1;
135  carry += counter[15];
136  counter[15] = (uint8_t)carry;
137  carry = (carry >> 8) + counter[14];
138  counter[14] = (uint8_t)carry;
139  carry = (carry >> 8) + counter[13];
140  counter[13] = (uint8_t)carry;
141  carry = (carry >> 8) + counter[12];
142  counter[12] = (uint8_t)carry;
143 }
144 
145 void GCMCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len)
146 {
147  // Finalize the authenticated data if necessary.
148  if (!state.dataStarted) {
149  ghash.pad();
150  state.dataStarted = true;
151  }
152 
153  // Encrypt the plaintext using the block cipher in counter mode.
154  uint8_t *out = output;
155  size_t size = len;
156  while (size > 0) {
157  // Create a new keystream block if necessary.
158  if (state.posn >= 16) {
159  increment(state.counter);
160  blockCipher->encryptBlock(state.stream, state.counter);
161  state.posn = 0;
162  }
163 
164  // Encrypt as many bytes as we can using the keystream block.
165  uint8_t temp = 16 - state.posn;
166  if (temp > size)
167  temp = size;
168  uint8_t *stream = state.stream + state.posn;
169  state.posn += temp;
170  size -= temp;
171  while (temp > 0) {
172  *out++ = *input++ ^ *stream++;
173  --temp;
174  }
175  }
176 
177  // Feed the ciphertext into the hash.
178  ghash.update(output, len);
179  state.dataSize += len;
180 }
181 
182 void GCMCommon::decrypt(uint8_t *output, const uint8_t *input, size_t len)
183 {
184  // Finalize the authenticated data if necessary.
185  if (!state.dataStarted) {
186  ghash.pad();
187  state.dataStarted = true;
188  }
189 
190  // Feed the ciphertext into the hash before we decrypt it.
191  ghash.update(input, len);
192  state.dataSize += len;
193 
194  // Decrypt the plaintext using the block cipher in counter mode.
195  while (len > 0) {
196  // Create a new keystream block if necessary.
197  if (state.posn >= 16) {
198  increment(state.counter);
199  blockCipher->encryptBlock(state.stream, state.counter);
200  state.posn = 0;
201  }
202 
203  // Decrypt as many bytes as we can using the keystream block.
204  uint8_t temp = 16 - state.posn;
205  if (temp > len)
206  temp = len;
207  uint8_t *stream = state.stream + state.posn;
208  state.posn += temp;
209  len -= temp;
210  while (temp > 0) {
211  *output++ = *input++ ^ *stream++;
212  --temp;
213  }
214  }
215 }
216 
217 void GCMCommon::addAuthData(const void *data, size_t len)
218 {
219  if (!state.dataStarted) {
220  ghash.update(data, len);
221  state.authSize += len;
222  }
223 }
224 
225 void GCMCommon::computeTag(void *tag, size_t len)
226 {
227  // Pad the hashed data and add the sizes.
228  ghash.pad();
229  uint64_t sizes[2] = {
230  htobe64(state.authSize * 8),
231  htobe64(state.dataSize * 8)
232  };
233  ghash.update(sizes, sizeof(sizes));
234  clean(sizes);
235 
236  // Get the finalized hash, encrypt it with the nonce, and return the tag.
237  ghash.finalize(state.stream, 16);
238  for (uint8_t posn = 0; posn < 16; ++posn)
239  state.stream[posn] ^= state.nonce[posn];
240  if (len > 16)
241  len = 16;
242  memcpy(tag, state.stream, len);
243 }
244 
245 bool GCMCommon::checkTag(const void *tag, size_t len)
246 {
247  // Can never match if the expected tag length is too long.
248  if (len > 16)
249  return false;
250 
251  // Compute the tag and check it.
252  computeTag(state.counter, 16);
253  return secure_compare(state.counter, tag, len);
254 }
255 
257 {
258  blockCipher->clear();
259  ghash.clear();
260  clean(state);
261  state.posn = 16;
262 }
263 
void computeTag(void *tag, size_t len)
Finalizes the encryption process and computes the authentication tag.
Definition: GCM.cpp:225
bool setKey(const uint8_t *key, size_t len)
Sets the key to use for future encryption and decryption operations.
Definition: GCM.cpp:77
size_t tagSize() const
Returns the size of the authentication tag.
Definition: GCM.cpp:72
void encrypt(uint8_t *output, const uint8_t *input, size_t len)
Encrypts an input buffer and writes the ciphertext to an output buffer.
Definition: GCM.cpp:145
void clear()
Clears all security-sensitive state from this cipher.
Definition: GCM.cpp:256
bool checkTag(const void *tag, size_t len)
Finalizes the decryption process and checks the authentication tag.
Definition: GCM.cpp:245
size_t ivSize() const
Size of the initialization vector for this cipher, in bytes.
Definition: GCM.cpp:66
void finalize(void *token, size_t len)
Finalizes the authentication process and returns the token.
Definition: GHASH.cpp:121
void addAuthData(const void *data, size_t len)
Adds extra data that will be authenticated but not encrypted.
Definition: GCM.cpp:217
void update(const void *data, size_t len)
Updates the message authenticator with more data.
Definition: GHASH.cpp:85
virtual void encryptBlock(uint8_t *output, const uint8_t *input)=0
Encrypts a single block using this cipher.
void decrypt(uint8_t *output, const uint8_t *input, size_t len)
Decrypts an input buffer and writes the plaintext to an output buffer.
Definition: GCM.cpp:182
virtual bool setKey(const uint8_t *key, size_t len)=0
Sets the key to use for future encryption and decryption operations.
GCMCommon()
Constructs a new cipher in GCM mode.
Definition: GCM.cpp:44
void pad()
Pads the input stream with zero bytes to a multiple of 16.
Definition: GHASH.cpp:137
virtual void clear()=0
Clears all security-sensitive state from this block cipher.
void clear()
Clears the authenticator's state, removing all sensitive data.
Definition: GHASH.cpp:150
virtual ~GCMCommon()
Destroys this cipher object after clearing sensitive information.
Definition: GCM.cpp:56
bool setIV(const uint8_t *iv, size_t len)
Sets the initialization vector to use for future encryption and decryption operations.
Definition: GCM.cpp:90
virtual size_t keySize() const =0
Default size of the key for this block cipher, in bytes.
size_t keySize() const
Default size of the key for this cipher, in bytes.
Definition: GCM.cpp:61
void reset(const void *key)
Resets the GHASH message authenticator for a new session.
Definition: GHASH.cpp:67