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  return true;
126 }
127 
133 static inline void increment(uint8_t counter[16])
134 {
135  uint16_t carry = 1;
136  carry += counter[15];
137  counter[15] = (uint8_t)carry;
138  carry = (carry >> 8) + counter[14];
139  counter[14] = (uint8_t)carry;
140  carry = (carry >> 8) + counter[13];
141  counter[13] = (uint8_t)carry;
142  carry = (carry >> 8) + counter[12];
143  counter[12] = (uint8_t)carry;
144 }
145 
146 void GCMCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len)
147 {
148  // Finalize the authenticated data if necessary.
149  if (!state.dataStarted) {
150  ghash.pad();
151  state.dataStarted = true;
152  }
153 
154  // Encrypt the plaintext using the block cipher in counter mode.
155  uint8_t *out = output;
156  size_t size = len;
157  while (size > 0) {
158  // Create a new keystream block if necessary.
159  if (state.posn >= 16) {
160  increment(state.counter);
161  blockCipher->encryptBlock(state.stream, state.counter);
162  state.posn = 0;
163  }
164 
165  // Encrypt as many bytes as we can using the keystream block.
166  uint8_t temp = 16 - state.posn;
167  if (temp > size)
168  temp = size;
169  uint8_t *stream = state.stream + state.posn;
170  state.posn += temp;
171  size -= temp;
172  while (temp > 0) {
173  *out++ = *input++ ^ *stream++;
174  --temp;
175  }
176  }
177 
178  // Feed the ciphertext into the hash.
179  ghash.update(output, len);
180  state.dataSize += len;
181 }
182 
183 void GCMCommon::decrypt(uint8_t *output, const uint8_t *input, size_t len)
184 {
185  // Finalize the authenticated data if necessary.
186  if (!state.dataStarted) {
187  ghash.pad();
188  state.dataStarted = true;
189  }
190 
191  // Feed the ciphertext into the hash before we decrypt it.
192  ghash.update(input, len);
193  state.dataSize += len;
194 
195  // Decrypt the plaintext using the block cipher in counter mode.
196  while (len > 0) {
197  // Create a new keystream block if necessary.
198  if (state.posn >= 16) {
199  increment(state.counter);
200  blockCipher->encryptBlock(state.stream, state.counter);
201  state.posn = 0;
202  }
203 
204  // Decrypt as many bytes as we can using the keystream block.
205  uint8_t temp = 16 - state.posn;
206  if (temp > len)
207  temp = len;
208  uint8_t *stream = state.stream + state.posn;
209  state.posn += temp;
210  len -= temp;
211  while (temp > 0) {
212  *output++ = *input++ ^ *stream++;
213  --temp;
214  }
215  }
216 }
217 
218 void GCMCommon::addAuthData(const void *data, size_t len)
219 {
220  if (!state.dataStarted) {
221  ghash.update(data, len);
222  state.authSize += len;
223  }
224 }
225 
226 void GCMCommon::computeTag(void *tag, size_t len)
227 {
228  // Pad the hashed data and add the sizes.
229  ghash.pad();
230  uint64_t sizes[2] = {
231  htobe64(state.authSize * 8),
232  htobe64(state.dataSize * 8)
233  };
234  ghash.update(sizes, sizeof(sizes));
235  clean(sizes);
236 
237  // Get the finalized hash, encrypt it with the nonce, and return the tag.
238  ghash.finalize(state.stream, 16);
239  for (uint8_t posn = 0; posn < 16; ++posn)
240  state.stream[posn] ^= state.nonce[posn];
241  if (len > 16)
242  len = 16;
243  memcpy(tag, state.stream, len);
244 }
245 
246 bool GCMCommon::checkTag(const void *tag, size_t len)
247 {
248  // Can never match if the expected tag length is too long.
249  if (len > 16)
250  return false;
251 
252  // Compute the tag and check it.
253  computeTag(state.counter, 16);
254  return secure_compare(state.counter, tag, len);
255 }
256 
258 {
259  blockCipher->clear();
260  ghash.clear();
261  clean(state);
262  state.posn = 16;
263 }
264 
void computeTag(void *tag, size_t len)
Finalizes the encryption process and computes the authentication tag.
Definition: GCM.cpp:226
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:146
void clear()
Clears all security-sensitive state from this cipher.
Definition: GCM.cpp:257
bool checkTag(const void *tag, size_t len)
Finalizes the decryption process and checks the authentication tag.
Definition: GCM.cpp:246
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:218
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:183
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