@@ -354,14 +354,243 @@ int ECCX08Class::ecdh(int slot, byte mode, const byte pubKeyXandY[], byte output
354
354
return 1 ;
355
355
}
356
356
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 )
358
358
{
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 ;
360
589
}
361
590
362
591
/* * \brief Generates AES GCM initialization vector.
363
592
*
364
- * \param[in, out] IV Initialization vector to be generated
593
+ * \param[out] IV Initialization vector to be generated
365
594
* (12 bytes). See
366
595
* NIST Special Publication 800-38D
367
596
* 8.2.1 Deterministic Construction
@@ -409,6 +638,13 @@ int ECCX08Class::AESGenIV(byte IV[])
409
638
return 1 ;
410
639
}
411
640
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
+ */
412
648
int ECCX08Class::readCounter (int slot, byte counter[])
413
649
{
414
650
if (!wakeup ()) {
@@ -430,6 +666,13 @@ int ECCX08Class::readCounter(int slot, byte counter[])
430
666
return 1 ;
431
667
}
432
668
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
+ */
433
676
int ECCX08Class::incrementCounter (int slot, byte counter[])
434
677
{
435
678
if (!wakeup ()) {
0 commit comments