new AES library

I've written an AES (Advanced Encryption Standard) library for Arduino. It supports 128, 192 and 256 bit key sizes. Code space overhead is about 4KB I think, each instance requires 240 bytes RAM for subkeys. Fairly tightly coded and checked against official test vectors for ECB mode. Also CBC mode supported.

Its derived from Brian Gladman's implementation for byte-oriented processors but signficantly modified. See the README and examples.

Functions:

  byte set_key (byte key[], int keylen) ;
  void clean () ;  // delete key schedule after use
  void copy_n_bytes (byte * dest, byte * src, byte n) ;

  byte encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) ;
  byte cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) ;

  byte decrypt (byte cipher [N_BLOCK], byte plain [N_BLOCK]) ;
  byte cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) ;

Lives here: http://utter.chaos.org.uk:/~markt/AES-library.zip

Feedback welcome.

Nice work, not tested it (if i only had time ...),

have you tried it in communication (serial/ethernet/SD/...) yet? especially with other device PC/Mac/pinguin

Its tested against many of the test-vectors (key varying, plaintext varying, Monte Carlo), which is the only contract it needs to fulfil... I've some speed/timing information now:

128 bit, key setup 0.37ms
128 bit, ECB, encryption 0.58ms / block (27.5kB/s)
128 bit, ECB, decryption 0.77ms / block (20.5kB/s)

192 bit, key setup 0.41ms
192 bit, ECB, encryption 0.71ms / block (22.5kB/s)
192 bit, ECB, decryption 0.92ms / block (17.5kB/s)

256 bit, key setup 0.52ms
256 bit, ECB, encryption 0.82ms / block (19.5kB/s)
256 bit, ECB, decryption 1.09ms / block (14.5kB/s)

(CBC modes are a little slower than ECB)

(All ATmega328p, 16MHz)

good speed, given that the Arduino/Mega only have a few KB of RAM, it can encode total RAM within a second.

Arduino can make approx 9000 (18KB) of analogRead samples per second [ @100% ] so I think it can keep up with 3-4000 samples/second.

Glad you like it. Next project is elliptic curve public key cryptography! (Only half joking)

Thank you so much for this extremely useful library. I'm not too "up" on C. Would you have any examples on encrypting a string that is longer than the N_BLOCK?

I have hit a stumbling block (no pun intended), and am trying multi-dimentional arrays to create blocks for encrypting/decrypting - I haven't gotten it working so am not even sure if plain and cipher will always be the same length.

you make a loop that takes n_BLOCK bytes per iteration of the character array until all chars are done. (you might need to pad the last block with zero's or so).

Note that AES is a block hash, not suitable for encrypting bulk data simply by dividing the data into blocks and encrypting each one with the same key. That would open up all sorts of flaws and vulnerabilities. typically you use something like "cipher block chaining" or "random ctr-mode" that generate separate xor keys for each block of data, BASED on your AES key. Essentially you need a library like openSSL on top of AES before you have something more than a mathematical curiosity.

"Cryptography is hard."

Not looking to encrypt bulk data, just more than 16 characters each time.

"bulk" means more than the native block size, in this case. For example, if you were to just run AES with your key on each block, an attacked could immediately tell whether both blocks were the same, which would be a terrible thing from a cryptographic point of view.
Random-ctr mode consists of picking a random number (N) the same size as a block, and then running THAT through AES with your key to give you something to xor with the first 16 bytes, and then AES(N+1, k) to get something to xor with the second 16 bytes, and so on. (then you transmit N at the start of your message.) Aside from it being a bit tricky to generate 128bit random numbers, it should be TOO hard.

Thanks to robtillaart for putting me on the right track. Fundamental mistake on my part. When transferring string value to char array, I needed to size array to str.length() + 1 and also null terminate the final element.

dauhee:
Thank you so much for this extremely useful library. I'm not too "up" on C. Would you have any examples on encrypting a string that is longer than the N_BLOCK?

I have hit a stumbling block (no pun intended), and am trying multi-dimentional arrays to create blocks for encrypting/decrypting - I haven't gotten it working so am not even sure if plain and cipher will always be the same length.

Assuming you have padded your plaintext up to a whole number of blocks "blockcount", and
assuming ciphertext is a byte array long enough for that amount of data, and that iv is a block's
worth of initialization vector, the encryption call is

  success_flag = aes.cbc_encrypt (plaintext, ciphertext, blockcount, iv);

Similarly for cbc_decrypt. If "iv" and "padding" don't mean anything to you you will need to read up about
block cipher encryption modes - all details matter.

These routines side-effect the iv argument to perform chaining (meaning they can be called repeatedly on groups of blocks
without having to pass around a chaning block explicitly).

I apologize for not noticing that the library already has a CBC-mode function. That's (one possibility) for what should be used to encrypt more than one block worth of data.

I am new to this encryption and decryption stuff, so i was playing with this library to get a idea on how it works.

My questions is why does the decryption function require the original unencrpyted plain message? Should it not be requesting the key and the cypher to decrypt it?

If I encrpted a message on one arduino and sent the cypher to another arduino with the keys hard coded into each seperate program how would i decrpyt the message on the second arduino? I wouldn't want to send the plain text in the message because then it defeats the purpose of encrypting in the first place.

toonamo:
I am new to this encryption and decryption stuff, so i was playing with this library to get a idea on how it works.

My questions is why does the decryption function require the original unencrpyted plain message? Should it not be requesting the key and the cypher to decrypt it?

If I encrpted a message on one arduino and sent the cypher to another arduino with the keys hard coded into each seperate program how would i decrpyt the message on the second arduino? I wouldn't want to send the plain text in the message because then it defeats the purpose of encrypting in the first place.

I'll try explain some symmetric encryption AES concepts a little (I found this while googling an arduino AES library - thanks to the O.P. for his/her hard work!)

The password is the actual 'secret' that must never be disclosed to the public. The sender and receiver must know the password to encrypt and decrypt correctly.

To keep things VERY simple, lets NOT break things up and pad strings - I'm simply explaining concepts.
We have our plaintext - "Hello World"
We have our password - "Hunter2"

The encryption will use the password to scramble "Hello World" into (example) "Um1nvnlmPP".
But what happens if you want to send the same encrypted message again? The ciphertext will look exactly the same! This means the bad guys can do "Pattern analysis", not exactly figuring out exactly what's in your message, but they know the same message was sent.

An excellent example is here on Wikipedia:

Block based encryption breaks a message up into little "blocks of data" to encrypt. In the above link, you can clearly see why ECB is a very very bad thing if Initialization Vectors (IV) aren't used for EACH block. What's an IV?

The IV is purely random data that is used WITH your password to encrypt the data. The IV does not need to be kept private, it is often sent with the encrypted message, eg:
Plaintext: "Hello World"
Password: "Hunter2"
IV: (randomly generated) "aabbaabbaa"
The complete message: "[aabbaabbaa][mnmnmnmnmn]"

So the encrypted message that anyone can see contains the IV in plain text. The IV does not need to be kept secret, only the password since it's not easy to crack the encryption without the password. The decrypter takes the IV, the user supplied password and attempts to decrypt the ciphertext

How does the IV help? Lets encrypt the same message again:
Plaintext: "Hello World"
Password: "Hunter2"
IV: (randomly generated) "ccddccddccdd"
Ciphertext: "[ccddccddccdd][opopopopopop]

See the ciphertext is always different, even if the same password is used because the IV is always different. This is only one step of preventing the bad guys identifying the contents of your message.

CBC is a little different. CBC uses a little bit of encrypted data from the previous block to encrypt the next block. The first block still needs the IV to be random. CBC has a smaller data size for a lot of blocks since a single IV can be used for a lot of blocks, while ECB can have only one IV for the lot, to prevent pattern matching as per the wikipedia article, better security would necessitate it should have a unique IV per block.

Great lib! Thanks MarkT!

Does it work for larger keys, like 1024 or 2048 ?

MarkT:
I've written an AES (Advanced Encryption Standard) library for Arduino. It supports 128, 192 and 256 bit key sizes. Code space overhead is about 4KB I think, each instance requires 240 bytes RAM for subkeys. Fairly tightly coded and checked against official test vectors for ECB mode. Also CBC mode supported.

Its derived from Brian Gladman's implementation for byte-oriented processors but signficantly modified. See the README and examples.

Functions:

  byte set_key (byte key[], int keylen) ;

void clean () ;  // delete key schedule after use
  void copy_n_bytes (byte * dest, byte * src, byte n) ;

byte encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) ;
  byte cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) ;

byte decrypt (byte cipher [N_BLOCK], byte plain [N_BLOCK]) ;
  byte cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) ;




Lives here: http://utter.chaos.org.uk:/~markt/AES-library.zip

Feedback welcome.

Hi,

I am working on simple encryption on my Arduino to be able to talk back and forth with web service, and stumbled upon this useful library. However, I have few questions regarding the CRC_decrypt and encrypt.

I got this example from somewhere in the thread and modify in a little bit.

#include <AES.h>

#define KEYLENGTH 32  // this means 32 bit encryption only following values are allowed 16, 128, 24, 192, 32, 256
AES aes;
char PassString[] = "This is hard to believe but true however";// this must be at least KEYLENGTH characters long
byte my_iv[N_BLOCK] = 
{
  1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
} ;
byte key[KEYLENGTH];
void setup()
{
	Serial.begin(115200);

	Serial.println("Starting AES test");
	for (int i = 0; i < KEYLENGTH; i++)
	{
		key[i] = PassString[i];
	}

	if (aes.set_key(key, KEYLENGTH) != 0)
	{
		Serial.println(F("Failed to set key"));
	}

}

// The loop function is called in an endless loop
void loop()
{

	char Message[] = "A top secret message. 123456789012345678901234";
	byte plain[N_BLOCK];
	byte cipher[N_BLOCK];
	byte decrypted[N_BLOCK];

  byte iv [N_BLOCK] ;
  
	Serial.print(F("message : '"));
	Serial.print(Message);
	Serial.println(F("'"));
	Serial.print(F("plain binary: '"));
	for (int i = 0; i < N_BLOCK; i++)
	{
		plain[i] = Message[i];
		cipher[i] = 0;
		decrypted[i] = 0;
		Serial.print(plain[i]);
	}
	Serial.println(F("'"));

	Serial.print(F("plain char: '"));
	for (int i = 0; i < N_BLOCK; i++)
	{
		Serial.print(char(plain[i]));
	}
	Serial.println(F("'"));

for (byte i = 0 ; i < 16 ; i++)
      iv[i] = my_iv[i] ;
	if (aes.cbc_encrypt(plain, cipher,4,iv) == 0)
	{
		Serial.print(F("encrypted : '"));
		for (int i = 0; i < N_BLOCK; i++)
		{
			Serial.print(cipher[i]);
		}
		Serial.println(F("'"));
	} else
	{
		Serial.println(F("Failed to encrypt"));
	}

	if (aes.cbc_decrypt(cipher, decrypted,4,iv) == 0)
	{
		Serial.print(F("decrypted binary : '"));
		for (int i = 0; i < N_BLOCK; i++)
		{
			Serial.print(decrypted[i]);
		}
		Serial.println(F("'"));

		Serial.print(F("decrypted char : '"));
		for (int i = 0; i < N_BLOCK; i++)
		{
			Serial.print(char(decrypted[i]));
		}
		Serial.println(F("'"));
	} else
	{
		Serial.println(F("Failed to decrypt"));
	}

	delay(5000);
}

The result seemed to be stable, as in I get it decrypt and encrypt. How do I print those bytes in readable character? encrypted and decrypted plain text. if I cannot have this printed in ascii format, I cannot prove that I can decrypt the message in the web server.

Thanks.

As hexadecimal is conventional.

Mark,
Sorry, I'm afraid I don't understand what you mean. : :blush:

If you have binary data to display, it is conventional to display it in
hexadecimal.

What exactly are you wanting to achieve and do you understand about
cryptography?