Skip to content

Commit 12bb471

Browse files
committed
AES encrypt function
1 parent bf7690e commit 12bb471

File tree

3 files changed

+276
-11
lines changed

3 files changed

+276
-11
lines changed

examples/ECCX08AES/ECCX08AES.ino

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
This sketch uses the ECC608 to compute
55
the AES_128_GCM encryption for some data
66
7+
This sketch assumes TempKey has been set
8+
(ECDH sketch will do this)
9+
710
*/
811

912
#include <ArduinoECCX08.h>
@@ -30,14 +33,28 @@ void setup() {
3033
printHex(devicePubKey, 64);
3134
}
3235

36+
byte ad[20] = {0x14};
37+
uint64_t adLength = (sizeof(ad));
38+
Serial.print("AD: ");
39+
printHex(ad, adLength);
40+
byte pt[40] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};
41+
uint64_t ptLength = (sizeof(pt));
42+
Serial.print("PT: ");
43+
printHex(pt, ptLength);
44+
3345
byte IV[12];
34-
if (!ECCX08.AESGenIV(IV)){
35-
Serial.println("Failed to initialize IV.");
46+
byte ct[40];
47+
byte tag[16];
48+
if (!ECCX08.AESEncrypt(IV, ad, pt, ct, tag, adLength, ptLength)){
49+
Serial.println("Failed to encrypt.");
3650
} else {
37-
Serial.print("IV: ");
51+
Serial.print("IV: ");
3852
printHex(IV, 12);
53+
Serial.print("CT: ");
54+
printHex(ct, ptLength);
55+
Serial.print("tag: ");
56+
printHex(tag, 16);
3957
}
40-
4158
}
4259

4360
void loop() {

src/ECCX08.cpp

Lines changed: 246 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,243 @@ int ECCX08Class::ecdh(int slot, byte mode, const byte pubKeyXandY[], byte output
354354
return 1;
355355
}
356356

357-
int ECCX08Class::AESEncrypt(byte IV[], byte ad[], byte pt[], byte ct[], byte tag[])
357+
int ECCX08Class::AESEncrypt(byte IV[], byte ad[], byte pt[], byte ct[], byte tag[], const uint64_t adLength, const uint64_t ptLength)
358358
{
359-
return 0;
359+
byte H[16] = {0x00};
360+
if (!AESBlockEncrypt(H)){
361+
Serial.println("AESEncrypt: failed to compute H.");
362+
return 0;
363+
}
364+
365+
byte J0[16] = {0x00};
366+
if (!AESGenIV(IV)){
367+
Serial.println("AESEncrypt: failed to generate IV.");
368+
return 0;
369+
}
370+
memcpy(J0, IV, 12);
371+
J0[15] = 0x01;
372+
373+
byte counterBlock[16];
374+
memcpy(counterBlock, J0, 16);
375+
if (!AESIncrementBlock(counterBlock)){
376+
Serial.println("AESEncrypt: failed to increment counter block.");
377+
return 0;
378+
}
379+
380+
if (!AESGCTR(counterBlock, pt, ct, ptLength)){
381+
Serial.println("AESEncrypt: failed to encrypt.");
382+
return 0;
383+
}
384+
385+
int adPad = (-adLength) % 16;
386+
int ctPad = (-ptLength) % 16;
387+
388+
byte S[16];
389+
uint64_t inputLength = adLength+adPad+ptLength+ctPad+16;
390+
byte input[inputLength];
391+
memcpy(input, ad, adLength);
392+
memset(input+adLength, 0, adPad);
393+
memcpy(input+adLength+adPad, ct, ptLength);
394+
memset(input+adLength+adPad+ptLength, 0, ctPad);
395+
// Device is little endian
396+
// GCM specification requires big endian length representation
397+
// Hence we reverse the byte order of adLength and ptLength
398+
for (int i=0; i<8; i++){
399+
input[adLength+adPad+ptLength+ctPad+i] = (adLength >> (56-8*i)) & 0xFF;
400+
input[adLength+adPad+ptLength+ctPad+8+i] = (ptLength >> (56-8*i)) & 0xFF;
401+
}
402+
403+
if (!AESGHASH(H, input, S, inputLength)){
404+
Serial.println("AESEncrypt: failed to compute GHASH.");
405+
return 0;
406+
}
407+
408+
if (!AESGCTR(J0, S, tag, 16)){
409+
Serial.println("AESEncrypt: failed to compute tag.");
410+
return 0;
411+
}
412+
413+
return 1;
414+
}
415+
416+
417+
/** \brief GCTR function, see
418+
* NIST Special Publication 800-38D
419+
* 6.5
420+
*
421+
* \param[in,out] counterBlock The initial counter block
422+
* (16 bytes).
423+
* \param[in] input The input bit string
424+
* \param[out] output The output bit string
425+
* \param[in] inputLength The length of the input
426+
*
427+
* \return 1 on success, otherwise 0.
428+
*/
429+
int ECCX08Class::AESGCTR(byte counterBlock[], byte input[], byte output[], const uint64_t inputLength)
430+
{
431+
if(inputLength == 0){
432+
return 1;
433+
}
434+
int remainder = inputLength % 16;
435+
int n = inputLength / 16 + (remainder != 0);
436+
437+
int i;
438+
for (i=0; i<n-1; i++){
439+
byte temp[16];
440+
memcpy(temp, counterBlock, 16);
441+
442+
if (!AESBlockEncrypt(temp)){
443+
Serial.println("AESGCTR: failed to encrypt counter block.");
444+
return 0;
445+
}
446+
447+
for (int j=0; j<16; j++){
448+
output[16*i+j] = input[16*i+j]^temp[j];
449+
}
450+
451+
if (!AESIncrementBlock(counterBlock)){
452+
Serial.println("AESGCTR: failed to increment counter block.");
453+
return 0;
454+
}
455+
}
456+
byte temp[16];
457+
memcpy(temp, counterBlock, 16);
458+
459+
if (!AESBlockEncrypt(temp)){
460+
Serial.println("AESGCTR: failed to encrypt counter block.");
461+
return 0;
462+
}
463+
464+
remainder = (remainder == 0) ? 16 : remainder;
465+
for (int j=0; j<remainder; j++){
466+
output[16*i+j] = input[16*i+j]^temp[j];
467+
}
468+
469+
return 1;
470+
}
471+
472+
/** \brief GHASH function, see
473+
* NIST Special Publication 800-38D
474+
* 6.4
475+
*
476+
* \param[in] H The hash subkey H
477+
* (16 bytes).
478+
* \param[in] input The input bit string
479+
* \param[out] output The output block
480+
* (16 bytes)
481+
* \param[in] inputLength The length of the input
482+
*
483+
* \return 1 on success, otherwise 0.
484+
*/
485+
int ECCX08Class::AESGHASH(byte H[], byte input[], byte output[], const uint64_t inputLength)
486+
{
487+
if (inputLength % 16 != 0){
488+
Serial.println("GHASH is only defined for multiples of 16 bytes.");
489+
return 0;
490+
}
491+
492+
memset(output, 0, 16);
493+
for (int i=0; i< inputLength/16; i++){
494+
for (int j=0; j<16; j++){
495+
output[j] ^= input[16*i+j];
496+
}
497+
if (!AESBlockMultiplication(H, output)){
498+
return 0;
499+
}
500+
}
501+
return 1;
502+
}
503+
504+
/** \brief Increments the right-most 32 bits of the block
505+
* regarded as an integer mod 2^32
506+
*
507+
* \param[in,out] counterBlock The block to be incremented
508+
* (16 bytes). See
509+
* NIST Special Publication 800-38D
510+
* 6.2
511+
*
512+
* \return 1 on success, otherwise 0.
513+
*/
514+
int ECCX08Class::AESIncrementBlock(byte counterBlock[])
515+
{
516+
// Increment the big-endian counter value
517+
int i;
518+
for (i = 0; i < 4; i++) {
519+
if (++(counterBlock[15 - i]) != 0) {
520+
break;
521+
}
522+
}
523+
if (i >= 4) {
524+
Serial.println("AESIncrementBlock: counter overflowed.");
525+
return 0;
526+
}
527+
return 1;
528+
}
529+
530+
/** \brief AES encrypts a block using TempKey
531+
*
532+
* \param[in,out] block The block to be encrypted
533+
* (16 bytes).
534+
*
535+
* \return 1 on success, otherwise 0.
536+
*/
537+
int ECCX08Class::AESBlockEncrypt(byte block[])
538+
{
539+
if (!wakeup()) {
540+
return 0;
541+
}
542+
if (!sendCommand(0x51, 0x00, 0xFFFF, block, 16)) {
543+
return 0;
544+
}
545+
546+
delay(51);
547+
548+
if (!receiveResponse(block, 16)) {
549+
return 0;
550+
}
551+
552+
delay(1);
553+
idle();
554+
555+
return 1;
556+
}
557+
558+
/** \brief AES block multiplication with hash key H
559+
*
560+
* \param[in] H The hash subkey
561+
* (16 bytes)
562+
* \param[in,out] block The block to be multiplied
563+
* (16 bytes).
564+
*
565+
* \return 1 on success, otherwise 0.
566+
*/
567+
int ECCX08Class::AESBlockMultiplication(byte H[], byte block[])
568+
{
569+
if (!wakeup()) {
570+
return 0;
571+
}
572+
byte data[32];
573+
memcpy(data, H, 16);
574+
memcpy(data+16, block, 16);
575+
if (!sendCommand(0x51, 0x03, 0xFFFF, block, 16)) {
576+
return 0;
577+
}
578+
579+
delay(51);
580+
581+
if (!receiveResponse(block, 16)) {
582+
return 0;
583+
}
584+
585+
delay(1);
586+
idle();
587+
588+
return 1;
360589
}
361590

362591
/** \brief Generates AES GCM initialization vector.
363592
*
364-
* \param[in,out] IV Initialization vector to be generated
593+
* \param[out] IV Initialization vector to be generated
365594
* (12 bytes). See
366595
* NIST Special Publication 800-38D
367596
* 8.2.1 Deterministic Construction
@@ -409,6 +638,13 @@ int ECCX08Class::AESGenIV(byte IV[])
409638
return 1;
410639
}
411640

641+
/** \brief Reads the counter on the device.
642+
*
643+
* \param[in] slot counter slot to read from
644+
* \param[out] counter counter value (4 bytes)
645+
*
646+
* \return 1 on success, otherwise 0.
647+
*/
412648
int ECCX08Class::readCounter(int slot, byte counter[])
413649
{
414650
if (!wakeup()) {
@@ -430,6 +666,13 @@ int ECCX08Class::readCounter(int slot, byte counter[])
430666
return 1;
431667
}
432668

669+
/** \brief Increments the counter on the device.
670+
*
671+
* \param[in] slot counter slot to increment
672+
* \param[out] counter counter value (4 bytes)
673+
*
674+
* \return 1 on success, otherwise 0.
675+
*/
433676
int ECCX08Class::incrementCounter(int slot, byte counter[])
434677
{
435678
if (!wakeup()) {

src/ECCX08.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,17 @@ class ECCX08Class
5454
#define ECDH_MODE_TEMPKEY ((uint8_t)0x08) //!< ECDH mode: write to TempKey
5555
#define ECDH_MODE_OUTPUT ((uint8_t)0x0c) //!< ECDH mode: write to buffer
5656

57-
int AESEncrypt(byte IV[], byte ad[], byte pt[], byte ct[], byte tag[]);
57+
int AESEncrypt(byte IV[], byte ad[], byte pt[], byte ct[], byte tag[], const uint64_t adLength, const uint64_t ptLength);
5858
int AESDecrypt(byte IV[], byte ad[], byte pt[], byte ct[], byte tag[]);
59-
#define AES_MODE_ENCRYPT ((uint8_t)0x00) //!< AES mode: encrypt
60-
#define AES_MODE_GFM ((uint8_t)0x03) //!< AES mode: Galois Field Multiply
61-
int AESGenIV(byte IV[]);
6259

60+
int AESGCTR(byte counterBlock[], byte input[], byte output[], const uint64_t inputLength);
61+
int AESGHASH(byte counterBlock[], byte input[], byte output[], const uint64_t inputLength);
62+
63+
int AESIncrementBlock(byte counterBlock[]);
64+
int AESBlockEncrypt(byte block[]);
65+
int AESBlockMultiplication(byte H[], byte block[]);
66+
67+
int AESGenIV(byte IV[]);
6368
int incrementCounter(int slot, byte counter[]);
6469
int readCounter(int slot, byte counter[]);
6570

0 commit comments

Comments
 (0)