new AES library

The code is written for 8-bit microcontrollers as the comments mention.

You'll have to look for 8-bit and 16-bit assumptions if you want to port it
to a 32 bit machine.

MarkT:
The code is written for 8-bit microcontrollers as the comments mention.

You'll have to look for 8-bit and 16-bit assumptions if you want to port it
to a 32 bit machine.

Thanks for the reply!

I've found some pseudo code for AES ( http://www.cs.utsa.edu/~wagner/laws/AESintro.html ) that has helped me understand this some more -- but I'm still struggling to find where the '8 bit assumptions' are precisely.

It seems from what I can find one difference between the 8 and 32 bit micros with Arduino is the size of int variables (16 and 32 bit, respectively). Are variables such as the two below therefore the ones causing me problems in this library?

int n_block
int keylen

For instance the line:
byte next = keylen ;

byte is 8 bits regardless, but the size of keylen is different between the 8 and 32 bit systems. Is this my problem?

Any additional pointers would be greatly appreciated as I try to work through this.

Hi could you help me making this library able for the Arduino Zero

Thank you!!!

This library is intended for 8 bit CPU's. You'll probably have better performance finding a 32-bit version.

However you should be able to go through and change the data types (int) to their AVR sized fixed width equivalents (int becomes int16_t and such).

Hi MarkT,

sorry but your lib don't work correct.
I've do decode AES128 CBC, encoded from another device. Only the first block is correct, all others wrong.
Please check against

Here you find usefull info and test-vectors:

Greetings,
gprand

Hello gpra,

it would be nice from you if you could provide the proof of what you're saying, for example some code that shows incorrect blocks compared to test vectors :slight_smile:

Was this the exact same CBC mode and with the precise IV in the right endianess to match
my code? All these details matter, you have to check. Perhaps you could provide a specific
example case referenced to the documentation?

Have you run the example that runs the test vectors? Does it work for you? Seen my #2 post?

Hi,

yes, I'll evaluate an example in the next days. Test program "aes.pde" did run correct. But it does encrypt and then decrypt, this seems to compensate the difference.

Greetings,

gpra

In the "aes" example, line:

succ = aes.decrypt (cipher, plain) ;

should read:

succ = aes.decrypt (cipher, check) ;

With original aes example code, when running:

void prekey_test ()
{
  prekey (128, 4) ;
  prekey (192, 3) ;
  prekey (256, 2) ;
  prekey (128, 1) ;
  prekey (192, 1) ;
  prekey (256, 1) ;
}

check variable is untouched after prekey(256,2), that is why if you comment statements before prekey(128, 1), right decryption won't be shown. In order to see it, you also should change plain to something like:

byte plain[] =
{
  0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} ;

Is it possible that variable names are inverted in decrypt function in AES.cpp? Line:

byte AES::decrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) 
{ 
... 
}

should read:

byte AES::decrypt (byte cipher [N_BLOCK], byte plain [N_BLOCK])
{
...
}

I too am very new to AES. I've learned enough to know basically how it works, but do not quite understand the methods in the arduino library. I'd like to ask for a simple example of encrypting/decrypting a 16 character string.

Could someone respond with some syntax using this AES library to do just that? Sorry but even looking at the library files themselves I am still somewhat lost.

I'm unsure how to set the 'password' and for my purposes I would ALWAYS be encrpyting 16 characters @ 128 bit. If I had an example using the libraries keywords/methods it would really help me to understand the rest of it.

A good example would be 128 bit encrypt/decryption of the string "abcdefghijklmnop" with a password of "panthers".

Any example or help would be greatly appreciated and would help me to understand the library better.

Excellent, library very quick and efficient however, there is an issue with the CBC decrypt, below is my code running on arduino

#include <Base64.h>
#include <AES.h>

AES aes ;

byte key[] = 
{
  12,13,14,15,15,16,17,18,19,10,11,12,13,14,15,16
 ,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
} ;

byte my_iv[] = 
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
} ;

//byte cipher [4*N_BLOCK] ;
byte check [4*N_BLOCK] ;

void loop () 
{}


void setup ()
{
  Serial.begin (57600) ;

  delay(30000);
  
  Serial.println("testing mode") ;

  byte succ = aes.set_key (key, 256) ;

  byte iv [N_BLOCK] ;
  for (byte i = 0 ; i < 16 ; i++)
      iv[i] = my_iv[i] ;

  int decodedLen = 32;
  byte decoded[] = {70,33,158,65,106,36,73,238,61,225,69,115,121,47,148,114,238,92,183,97,37,152,168,11,248,112,41,187,179,2,119,250};

  succ = aes.cbc_decrypt (decoded, check, (decodedLen/N_BLOCK), iv) ;

  aes.clean();

  for(int i=0; i<decodedLen;i++)
  {
    Serial.print((char)check[i]);
  }
  Serial.println("");
}

This is decrypted but not correctly, the second block, first byte us incorrect, decrypted the string should read Decoded hello world encrypted!!! but this library decodes as Decoded hello wnrld encrypted!!!

The encrypted text is from a C# console app

using System;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sandbox
{
    class Program
    {
        static void Main(string[] args)
        {
            var isLE = BitConverter.IsLittleEndian;


            byte[] encrypData = System.Text.Encoding.UTF8.GetBytes("Decoded hello world encrypted!!!");

            using (AesManaged crypto = new AesManaged())
            {
                crypto.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                crypto.Key = new byte[] {12,13,14,15,15,16,17,18,19,10,11,12,13,14,15,16
                                        ,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32};
                crypto.Mode = CipherMode.CBC;

                using (var encryptor = crypto.CreateEncryptor())
                {
                    var outBuffer = new byte[32];

                    encryptor.TransformBlock(encrypData, 0, 32, outBuffer, 0);

                }
            }
        }
    }
}

Any ideas what could be causing the issue? I have checked from previous threads about endian and I can confirm both are little.

After my previous post I noticed an issue with my_iv, had a 01 as last byte and should have been 00, corrected and can confirm the library works 100%, nice work MARKT

Hi
I have quastion about library "AES.h " .

I am use arduino DUE
how I can do this with your library ?
enter voice by microphone in (A0)
the voice out encryption by " AES" from (DAC0)
the encryption voice enter to (A1)
then the voice out decryption from ( DAC1)

Hi at all, I'm trying to use this aes lib on my arduino uno to encrypt and decrypt a string, how can I do? thank you

Hi Mark,

I might came across a minor bug (with a workaround) in your library.
how to reproduce
if you run your example code with the following calls

void prekey_test ()
{
//prekey (128, 2) ;
//prekey (192, 3) ;
//prekey (256, 2) ;
//prekey (128, 1) ;
//prekey (192, 1) ;
//prekey (256, 1) ;
prekey (256, 1) ;
}

you get

testng modeset_key 256 ->0 took 748us
encrypt 0 took 716us
decrypt 0 took 968us
F3 44 81 EC 3C C6 27 BA CD 5D C3 FB 08 F2 73 E6
63 60 DD 58 F0 F1 A4 93 8B 40 6A 8E AA 7E 0A 14
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

so the decrypt for block==1 fails
however if you run the following calls

void prekey_test ()
{
//prekey (128, 2) ;
//prekey (192, 3) ;
prekey (256, 2) ;
//prekey (128, 1) ;
//prekey (192, 1) ;
//prekey (256, 1) ;
prekey (256, 1) ;
}

then the both work fine

testng modeset_key 256 ->0 took 748us
encrypt 0 took 1492us
decrypt 0 took 2044us
F3 44 81 EC 3C C6 27 BA CD 5D C3 FB 08 F2 73 E6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6A BB C9 E8 A0 FD 6D E7 FB 8A A5 D8 A6 CF 4C 7D D3 2B 9D 08 7B AA 9D 43 09 56 B0 D9 21 0B 62 C8
F3 44 81 EC 3C C6 27 BA CD 5D C3 FB 08 F2 73 E6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
D3 2B 9D 08 7B AA 9D 43 09 56 B0 D9 21 0B 62 C8
set_key 256 ->0 took 752us
encrypt 0 took 708us
decrypt 0 took 972us
F3 44 81 EC 3C C6 27 BA CD 5D C3 FB 08 F2 73 E6
63 60 DD 58 F0 F1 A4 93 8B 40 6A 8E AA 7E 0A 14
F3 44 81 EC 3C C6 27 BA CD 5D C3 FB 08 F2 73 E6

not a big deal - but it might worth a look.
Thanks for the great work!

Best Regards,
Aurelian

Does this library exists on github that may have all this issues fixed?

Hello,

I have a program where I have several strings. To avoid the use of RAM, I'm using the PROGMEM to have array of strings, and also the F() to store strings on the flash (PGM).

I'm using a arduino mega2560, and I see if changes some strings to the flash, with F(), I start having problems with the encoding and decondig.

I have arrived to the point where I have a program with 83346 bytes (32% of program space). And all is working.

If I change the line:

_lcd->print("1) ");

to

_lcd->print(F("1) "));

The program size jumps to 83598 bytes, and the encode and decode doesn't work correctly.
I have made several changes on the code, but always I get a program above the 83346 I get problems on the AES library. All the rest is working.

I see that the library also uses PGM to store values.

My question, is there the possibility that the use of several strings stored on the PGM, could cause problem on the library?

I'm using AES CBC 128bits.

Thanks for any idea that can be shared.

Thanks for any idea that can be shared.

It is probably a near vs. far address problem. Most pointers, like "const char *" or "const __FlashStringHelper *", are 16-bit addresses (i.e., "near" in the first 64K).

For function calls to "far" destinations, the linker is "supposed" to use a "trampoline" to get there, jumping to a "near" address first. I get the impression that far calls are usually handled correctly.

For "far" data, I can't find anything other than managing it yourself with explicit declarations like uint_farptr_t and xxxx_PF variants, like memcpy_PF.

I don't think FLASH data (e.g., declared via the F macro) is guaranteed to be anywhere in particular. The sketch code is preferentially loaded in the first 64K, but libraries may extend past that boundary. I wonder if the code size pushes FLASH data past the 64K address boundary. Then it is dereferenced incorrectly by code that expectes near pointers (e.g., Print methods).

To force the code to use far pointers for FLASH data, you have to do something like this:

const char someFlashData[] PROGMEM = "stringity string.";

void farPrint( const char *farFD )
{
  uint_farptr_t farAddr = pgm_get_far_address( farFD );
  
  do {
    char c = pgm_read_byte_far( farAddr++ );
    if (!c)
      break;
    Serial.write( c );
  }
}

void foo()
{
  farPrint( someFlashData );
}

Untested. Functions/macros documented here.

If the AES library is using FLASH data, it would have to be modified to always use far pointers. If it's just your sketch that is using FLASH data, you should be able to modify all the F macro uses to do something different. Initial values may also fall into that category: they are loaded from FLASH into the RAM variable being initialized.

That's about all I can suggest. Free advice is worth what you paid for it, my $0.02, YMMV, etc., etc.

You've been warned. :wink:

I am trying to use this library to encrypt some data I'm sending to a Raspberry Pi using a transceiver module. In order to make a small test prototype I've modified the example code provided with this library so that it performs 256 2 block CBC encryption and then prints the cipher to the Serial monitor.

#include <AES.h>

AES aes ;

byte key[] = 
{
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} ;

byte plain[] =
{
  // 0xf3, 0x44, 0x81, 0xec, 0x3c, 0xc6, 0x27, 0xba, 0xcd, 0x5d, 0xc3, 0xfb, 0x08, 0xf2, 0x73, 0xe6
  0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} ;

byte my_iv[] = 
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
} ;

byte cipher [4*N_BLOCK] ;
byte check [4*N_BLOCK] ;

void loop () 
{}


void setup ()
{
  Serial.begin (57600) ;
  Serial.print ("testng mode") ;

  prekey_test () ;
  
//  otfly_test () ;
//  otfly_test256 () ;
}

void prekey (int bits, int blocks)
{
  byte iv [N_BLOCK] ;
  
  long t0 = micros () ;
  byte succ = aes.set_key (key, bits) ;
  long t1 = micros()-t0 ;
  Serial.print ("set_key ") ; Serial.print (bits) ; Serial.print (" ->") ; Serial.print ((int) succ) ;
  Serial.print (" took ") ; Serial.print (t1) ; Serial.println ("us") ;
  t0 = micros () ;
  if (blocks == 1)
    succ = aes.encrypt (plain, cipher) ;
  else
  {
    for (byte i = 0 ; i < 16 ; i++)
      iv[i] = my_iv[i] ;
    succ = aes.cbc_encrypt (plain, cipher, blocks, iv) ;
  }
  t1 = micros () - t0 ;
  Serial.print ("encrypt ") ; Serial.print ((int) succ) ;
  Serial.print (" took ") ; Serial.print (t1) ; Serial.println ("us") ;
  Serial.println();
  Serial.println("-------------------");
  for(byte i = 0; i < sizeof(cipher); i++) {
    Serial.print(cipher[i], HEX);
  }
  Serial.println("");
  Serial.println("------------------------------");

}

void prekey_test ()
{
  prekey (256,2) ;

}

I am then taking the cipher text and copying it to Python on the Raspberry Pi to the decryption code which uses the pycryptodome library, which is where I don't understand what to do. I am unsure of the block length of this library (I've serially printed N_BLOCK and found it to be 16, but the cipher array is 64 bytes long...) and I continually get a padding error in Python. I realise this is more of a Python problem than anything else but I have tried everything I can think of.

from Crypto.Cipher import AES
from base64 import b64encode, b64decode
from Crypto.Util.Padding import pad, unpad

BLOCK_SIZE = 64 # is that right?

def encrypt(plaintext, key, IV):
    cipher = AES.new(key, AES.MODE_CBC, IV)
    cipher_bytes = cipher.encrypt(pad(plaintext, BLOCK_SIZE))
    return(cipher_bytes)

def decrypt(ct, passkey, IV):
    cipher = AES.new(passkey, AES.MODE_CBC, IV)
    decrypted = cipher.decrypt(ct)
    return((unpad(decrypted, BLOCK_SIZE)))

passkey = b'80000000000000000000000000000000' #have I converted the passkey from the example code correctly?
IV = b'0000000000000001' # have I converted the IV from the example code correctly?
ct = b"F7B337A3C81C50169E4851F823E8C8B78EB31B013171CA23641F0D385DB38B00000000000000000000000000000000"
print(decrypt(ct, passkey, IV))

"""
>> ValueError: Data must be padded to 16 byte boundary in CBC mode

"""