Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
CC32xxAes.hxx
1
36#ifndef _CC32xxAESCCM_HXX_
37#define _CC32xxAESCCM_HXX_
38
39#include <stdint.h>
40
41#include "inc/hw_types.h"
42#include "inc/hw_memmap.h"
43#include "inc/hw_aes.h"
44#include "inc/hw_dthe.h"
45#include "driverlib/prcm.h"
46#include "driverlib/rom.h"
47#include "driverlib/rom_map.h"
48#include "driverlib/aes.h"
49
50#include "utils/SyncStream.hxx"
51
55{
56public:
70 static void decrypt(const std::string &aes_key, const std::string &nonce,
71 const std::string &auth_data, const std::string &cipher,
72 std::string *plain, std::string *tag)
73 {
74 CCMHelper h;
75 h.decrypt_init(aes_key, nonce, auth_data, cipher.size(), tag->size());
76 unsigned ofs = cipher.size() / 3;
77 h.data_process(cipher.substr(0, ofs), plain);
78 std::string part;
79 h.data_process(cipher.substr(ofs), &part);
80 *plain += part;
81 h.data_finalize(&part, tag);
82 *plain += part;
83 }
84
100 static void encrypt(const std::string &aes_key, const std::string &nonce,
101 const std::string &auth_data, const std::string &plain,
102 unsigned tag_len, std::string *cipher, std::string *tag)
103 {
104 static_encrypt_init(aes_key, nonce, auth_data, plain.size(), tag_len);
105 cipher->resize(plain.size() + 15);
106 int len = plain.size();
107 unsigned ofs = 0;
108 while (len >= 16)
109 {
111 (const uint8_t *)&plain[ofs], (uint8_t *)&(*cipher)[ofs]);
112 ofs += 16;
113 len -= 16;
114 }
115 if (len > 0)
116 {
117 uint8_t buf[16];
118 memset(buf, 0, sizeof(buf));
119 memcpy(buf, &plain[ofs], len);
120 process_block(buf, (uint8_t *)&(*cipher)[ofs]);
121 }
122 cipher->resize(plain.size());
123 tag->resize(tag_len);
124 read_tag(tag);
125 }
126
141 void decrypt_init(const std::string &aes_key, const std::string &nonce,
142 const std::string &auth_data, unsigned data_len, uint8_t tag_len)
143 {
144 // will set the strings on each write.
145 outputStream_ = new StringAppendStream(nullptr);
146 decryptorStream_.reset(create_decryptor_stream(aes_key, nonce, auth_data, data_len, tag_len, outputStream_, &tagOut_, nullptr));
147 }
148
149 static void static_decrypt_init(const std::string &aes_key,
150 const std::string &nonce, const std::string &auth_data,
151 unsigned data_len, uint8_t tag_len)
152 {
153 reset();
154 // Sets configuration
155 unsigned mode = AES_CFG_DIR_DECRYPT | AES_CFG_MODE_CCM |
156 AES_CFG_CTR_WIDTH_32 |
157 get_mode(aes_key.size(), nonce.size(), tag_len);
158 MAP_AESConfigSet(AES_BASE, mode);
159
160 // Computes the initialization vector form the nonce.
161 string real_iv;
162 real_iv.push_back(nonce_length_to_l(nonce.size()) - 1);
163 real_iv += nonce;
164 while (real_iv.size() < 16)
165 {
166 real_iv.push_back(0);
167 }
168 MAP_AESIVSet(AES_BASE, (uint8_t *)real_iv.data());
169
170 // Sets key and length variables needed before starting the decryption.
171 MAP_AESKey1Set(AES_BASE, (uint8_t *)aes_key.data(),
172 interpret_key_size(aes_key.size()));
173 MAP_AESDataLengthSet(AES_BASE, data_len);
174 MAP_AESAuthDataLengthSet(AES_BASE, auth_data.size());
175
176 // Writes the pre-authenticated data.
177 for (unsigned ofs = 0; ofs < auth_data.size(); ofs += 16)
178 {
179 MAP_AESDataWrite(AES_BASE, (uint8_t *)&auth_data[ofs],
180 std::min(16u, auth_data.size() - ofs));
181 }
182 }
183
184 static void static_encrypt_init(const std::string &aes_key,
185 const std::string &nonce, const std::string &auth_data,
186 unsigned data_len, uint8_t tag_len)
187 {
188 reset();
189 // Sets configuration
190 unsigned mode = AES_CFG_DIR_ENCRYPT | AES_CFG_MODE_CCM |
191 AES_CFG_CTR_WIDTH_32 |
192 get_mode(aes_key.size(), nonce.size(), tag_len);
193 MAP_AESConfigSet(AES_BASE, mode);
194
195 // Computes the initialization vector form the nonce.
196 string real_iv;
197 real_iv.push_back(nonce_length_to_l(nonce.size()) - 1);
198 real_iv += nonce;
199 while (real_iv.size() < 16)
200 {
201 real_iv.push_back(0);
202 }
203 MAP_AESIVSet(AES_BASE, (uint8_t *)real_iv.data());
204
205 // Sets key and length variables needed before starting the decryption.
206 MAP_AESKey1Set(AES_BASE, (uint8_t *)aes_key.data(),
207 interpret_key_size(aes_key.size()));
208 MAP_AESDataLengthSet(AES_BASE, data_len);
209 MAP_AESAuthDataLengthSet(AES_BASE, auth_data.size());
210
211 // Writes the pre-authenticated data.
212 for (unsigned ofs = 0; ofs < auth_data.size(); ofs += 16)
213 {
214 MAP_AESDataWrite(AES_BASE, (uint8_t *)&auth_data[ofs],
215 std::min(16u, auth_data.size() - ofs));
216 }
217 }
218
224 void data_process(const std::string &payload, std::string *payload_out)
225 {
226 payload_out->clear();
227 payload_out->reserve(payload.size() + 16);
228 outputStream_->set_output(payload_out);
229 auto ret = decryptorStream_->write_all(payload.data(), payload.size());
230 HASSERT(ret == (ssize_t)payload.size());
231 }
232
237 void data_finalize(std::string *payload_out, std::string *tag_out)
238 {
239 payload_out->clear();
240 outputStream_->set_output(payload_out);
241 auto ret = decryptorStream_->finalize(0);
242 HASSERT(ret == 0);
243 tag_out->swap(tagOut_);
244 }
245
267 static SyncStream *create_decryptor_stream(const std::string &aes_key,
268 const std::string &nonce, const std::string &auth_data,
269 unsigned data_len, uint8_t tag_len, SyncStream *consumer,
270 std::string *tag_out, const std::string* expected_tag)
271 {
272 static_decrypt_init(aes_key, nonce, auth_data, data_len, tag_len);
273 tag_out->resize(tag_len);
274 return new MinWriteStream(
275 16, new DecryptorStream(
276 tag_out, expected_tag, new MaxLengthStream(data_len, consumer)));
277 }
278
280 {
281 public:
282 DecryptorStream(std::string *tag_out, const std::string *expected_tag,
283 SyncStream *consumer)
284 : WrappedStream(consumer)
285 , tagOut_(tag_out)
286 , expectedTag_(expected_tag)
287 {
288 }
289
290 ssize_t write(const void *data, size_t len) override
291 {
292 if (len < 16)
293 return -1;
294 unsigned ll = 0;
295 auto rp = (const uint8_t *)(data);
296 auto wp = (uint8_t *)(data);
297 while (len >= 16)
298 {
299 process_block(rp, wp);
300 rp += 16;
301 wp += 16;
302 ll += 16;
303 len -= 16;
304 }
305 delegate_->write_all(data, ll);
306 return ll;
307 }
308
309 int finalize(int status) override
310 {
311 read_tag(tagOut_);
312 if (expectedTag_ && (*expectedTag_ != *tagOut_)) {
313 status = -2;
314 }
315 return WrappedStream::finalize(status);
316 }
317
318 private:
319 std::string *tagOut_;
320 const std::string *expectedTag_;
321 };
322
323private:
325 static void reset()
326 {
327 MAP_PRCMPeripheralClkDisable(PRCM_DTHE, PRCM_RUN_MODE_CLK);
328 usleep(10);
329 MAP_PRCMPeripheralClkEnable(PRCM_DTHE, PRCM_RUN_MODE_CLK);
330 usleep(10);
331 while (!MAP_PRCMPeripheralStatusGet(PRCM_DTHE))
332 ;
333 }
334
339 static uint32_t interpret_key_size(unsigned key_len)
340 {
341 switch (key_len)
342 {
343 case 16:
344 return AES_CFG_KEY_SIZE_128BIT;
345 case 24:
346 return AES_CFG_KEY_SIZE_192BIT;
347 case 32:
348 return AES_CFG_KEY_SIZE_256BIT;
349 default:
350 DIE("Unknown key length");
351 }
352 return 0;
353 }
354
358 static int nonce_length_to_l(unsigned nonce_len)
359 {
360 switch (nonce_len)
361 {
362 case 15 - 2:
363 return 2;
364 case 15 - 4:
365 return 4;
366 case 15 - 8:
367 return 8;
368 }
369 return -1;
370 }
371
376 static unsigned get_mode(
377 unsigned key_len, unsigned nonce_len, unsigned tag_len)
378 {
379 unsigned ret = interpret_key_size(key_len);
380
381 switch (nonce_len)
382 {
383 case 15 - 2:
384 ret |= AES_CFG_CCM_L_2;
385 break;
386 case 15 - 4:
387 ret |= AES_CFG_CCM_L_4;
388 break;
389 case 15 - 8:
390 ret |= AES_CFG_CCM_L_8;
391 break;
392 default:
393 DIE("unsupported nonce length");
394 }
395
396 switch (tag_len)
397 {
398 case 4:
399 ret |= AES_CFG_CCM_M_4;
400 break;
401 case 6:
402 ret |= AES_CFG_CCM_M_6;
403 break;
404 case 8:
405 ret |= AES_CFG_CCM_M_8;
406 break;
407 case 10:
408 ret |= AES_CFG_CCM_M_10;
409 break;
410 case 12:
411 ret |= AES_CFG_CCM_M_12;
412 break;
413 case 14:
414 ret |= AES_CFG_CCM_M_14;
415 break;
416 case 16:
417 ret |= AES_CFG_CCM_M_16;
418 break;
419 default:
420 DIE("Unsupported tag length");
421 }
422 return ret;
423 }
424
429 static void process_block(const uint8_t *din, uint8_t *dout)
430 {
431 MAP_AESDataWrite(AES_BASE, (uint8_t *)din, 16);
432 MAP_AESDataRead(AES_BASE, dout, 16);
433 }
434
438 static void read_tag(std::string* tag_out) {
439 uint8_t tag[16];
440 //
441 // Wait for the context data registers to be ready.
442 //
443 while ((AES_CTRL_SVCTXTRDY & (HWREG(AES_BASE + AES_O_CTRL))) == 0)
444 {
445 }
446
447 MAP_AESTagRead(AES_BASE, tag);
448 tag_out->assign((const char*)tag, tag_out->size());
449 }
450
452 std::unique_ptr<SyncStream> decryptorStream_;
457 std::string tagOut_;
458};
459
460#endif // _CC32xxAESCCM_HXX_
int finalize(int status) override
Called once after all data has been written to close the stream and release resources.
ssize_t write(const void *data, size_t len) override
Main entry point to the data consumption.
Helper class for doing CCM encryption-with-authentication using the CC32xx's hardware AES engine.
Definition CC32xxAes.hxx:55
void data_finalize(std::string *payload_out, std::string *tag_out)
Completes the streaming operation.
std::unique_ptr< SyncStream > decryptorStream_
Implementation object.
static unsigned get_mode(unsigned key_len, unsigned nonce_len, unsigned tag_len)
Computes mode bits for the AES engine.
static void reset()
Resets / turns on the AES engine.
static void decrypt(const std::string &aes_key, const std::string &nonce, const std::string &auth_data, const std::string &cipher, std::string *plain, std::string *tag)
Performs authenticated decryption using CCM in one call.
Definition CC32xxAes.hxx:70
void data_process(const std::string &payload, std::string *payload_out)
Process streaming encryption data.
static SyncStream * create_decryptor_stream(const std::string &aes_key, const std::string &nonce, const std::string &auth_data, unsigned data_len, uint8_t tag_len, SyncStream *consumer, std::string *tag_out, const std::string *expected_tag)
Creates a stream for on-the-fly receiving encrypted data and passing on decrypted data to a consumer ...
static void process_block(const uint8_t *din, uint8_t *dout)
Performs encryption (or decryption) on a single block of data.
void decrypt_init(const std::string &aes_key, const std::string &nonce, const std::string &auth_data, unsigned data_len, uint8_t tag_len)
Initializes streaming decryption.
StringAppendStream * outputStream_
Stream that catches the decrypted output in the user-provided strings.
std::string tagOut_
Variable that will receive the output tag.
static uint32_t interpret_key_size(unsigned key_len)
Computes the internal constant used for the configuration of the key size.
static void encrypt(const std::string &aes_key, const std::string &nonce, const std::string &auth_data, const std::string &plain, unsigned tag_len, std::string *cipher, std::string *tag)
Performs authenticated encryption using CCM in one call.
static void read_tag(std::string *tag_out)
Finalizes encyrption/decryption and reads out the checksum tag.
static int nonce_length_to_l(unsigned nonce_len)
Compute the size of the L parameter in bytes from the nonce length.
Stream wrapper that limits the number of bytes sent to the child stream, and reports EOF after the gi...
Stream wrapper that contains a small internal buffer to ensure that all writes are at least a certain...
Simple stream implementation that appends all data to a given std::string.
Helper class for defining streams that forward data to another stream internally.
int finalize(int status) override
Called once after all data has been written to close the stream and release resources.
std::unique_ptr< SyncStream > delegate_
Where to write the data to.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143