I am quite new to idea of encryption and am trying to use aes-256-ecb encryption.
I am using library called "Arduino cryptography". Unfortunately I could not find any tutorial that would explain how to encrypt a json string (and other things latter) using a key.
I have a function that generates same key on both sides of Arduino and php script on a server side, but I could not find a working tutorial (except the case of obsolete buggy library with instruction like : "copy this text" and even that doesn't work.
Unfortunately libraries examples do not bother to show how to retrieve encrypted string or explain what is what and instead just focus on checking how long encryption takes.
Does any of you know of some tutorial or an example from which I could engineer a solution?
library link:The library
in buioltin example there is a code of:
cipher->decryptBlock(buffer, test->ciphertext);
But I do not understand where is the output and where the input here
Second question would be if I can use other modes like the mentioned GCM simply by changing the value in
static TestVector const testVectorAES256 = {
.name = "AES-256-ECB",
.key = {0x00, 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},
.plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
.ciphertext = {0x8E, 0xA2, 0xB7, 0xCA, 0x51, 0x67, 0x45, 0xBF,
0xEA, 0xFC, 0x49, 0x90, 0x4B, 0x49, 0x60, 0x89}
};
or how?
After bits and strougles I have managed to get this working, but next step is how to make it take a string:
/*Skúška kódovania GCM-AES256#*/
#include <Crypto.h>
#include <AES.h>
#include <GCM.h>
//#include <pgmspace.h>
struct TestVector
{
const char *name;
uint8_t key[32];
uint8_t plaintext[60];
uint8_t ciphertext[60];
uint8_t authdata[20];
uint8_t iv[12];
uint8_t tag[16];
size_t authsize;
size_t datasize;
size_t tagsize;
size_t ivsize;
};
static TestVector const testVectorGCM PROGMEM = {
.name = "AES-256 GCM",
.key = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08},
.plaintext = {0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
0xba, 0x63, 0x7b, 0x39},
.ciphertext = {0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
0xbc, 0xc9, 0xf6, 0x62},
.authdata = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
0xab, 0xad, 0xda, 0xd2},
.iv = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
0xde, 0xca, 0xf8, 0x88},
.tag = {0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b},
.authsize = 20,
.datasize = 60,
.tagsize = 16,
.ivsize = 12
};
TestVector testVector;
byte buffer[128];
bool testCipher_N(AuthenticatedCipher *cipher, const struct TestVector *test, size_t inc)
{
size_t posn, len;
uint8_t tag[16];
crypto_feed_watchdog();
cipher->clear();
if (!cipher->setKey(test->key, cipher->keySize())) {
Serial.print("setKey ");
return false;
}
if (!cipher->setIV(test->iv, test->ivsize)) {
Serial.print("setIV ");
return false;
}
memset(buffer, 0xBA, sizeof(buffer));
for (posn = 0; posn < test->authsize; posn += inc) {
len = test->authsize - posn;
if (len > inc)
len = inc;
cipher->addAuthData(test->authdata + posn, len);
}
for (posn = 0; posn < test->datasize; posn += inc) {
len = test->datasize - posn;
if (len > inc)
len = inc;
cipher->encrypt(buffer + posn, test->plaintext + posn, len);
}
Serial.println("Vystup:\n");
for(uint8_t i=0; i<sizeof(buffer); i++) printf("0x%X,",buffer[i]);
return true;
}
void testCipher(AuthenticatedCipher *cipher, const struct TestVector *test)
{
bool ok;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" ... ");
ok = testCipher_N(cipher, test, test->datasize);
/*ok &= testCipher_N(cipher, test, 1);
ok &= testCipher_N(cipher, test, 2);
ok &= testCipher_N(cipher, test, 5);
ok &= testCipher_N(cipher, test, 8);
ok &= testCipher_N(cipher, test, 13);
ok &= testCipher_N(cipher, test, 16);*/
if (ok)
Serial.println("Passed");
else
Serial.println("Failed");
}
void perfCipherSetKey(AuthenticatedCipher *cipher, const struct TestVector *test, const char *name)
{
unsigned long start;
unsigned long elapsed;
int count;
crypto_feed_watchdog();
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(name);
Serial.print(" SetKey ... ");
start = micros();
for (count = 0; count < 1000; ++count) {
cipher->setKey(test->key, cipher->keySize());
cipher->setIV(test->iv, test->ivsize);
}
elapsed = micros() - start;
Serial.print(elapsed / 1000.0);
Serial.print("us per operation, ");
Serial.print((1000.0 * 1000000.0) / elapsed);
Serial.println(" per second");
}
void perfCipherEncrypt(AuthenticatedCipher *cipher, const struct TestVector *test, const char *name)
{
unsigned long start;
unsigned long elapsed;
int count;
crypto_feed_watchdog();
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(name);
Serial.print(" Encrypt ... ");
cipher->setKey(test->key, cipher->keySize());
cipher->setIV(test->iv, test->ivsize);
start = micros();
for (count = 0; count < 500; ++count) {
cipher->encrypt(buffer, buffer, 128);
}
elapsed = micros() - start;
Serial.print(elapsed / (128.0 * 500.0));
Serial.print("us per byte, ");
Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void setup(){
Serial.begin(115200);
Serial.println("Začínam\n");
GCM <AES256> *gcm=0;
gcm= new GCM<AES256>();
gcm->setKey(testVectorGCM.key, 32);
gcm->setIV(testVectorGCM.iv,testVectorGCM.ivsize);
crypto_feed_watchdog();
//gcm->encrypt(buffer,testVectorGCM.plaintext,60);
testCipher(gcm,&testVectorGCM);
delete gcm;
//gcm.encrypt(&vstupny,&vystup,49);
crypto_feed_watchdog();
Serial.println("Vystup: \n");
for(uint8_t i=0; i<50;i++) Serial.print(buffer[i]);
}
void loop(){
delay(1000);
Serial.print(".");
}
I need to be able to get the text on PHP side
1 Answer 1
Kind of an answer. After the advise from @Kwasmich I have converted to aes-256-gcm.
Upgraded to UTF-8 thanks to Edgar Bonet
Based mostly on GCMTest example comming with Arduino Cryptograhy libraries:
-----------------------------------------------
Shared between Encryption and decrition
First need to define parts which will not change:
#include <Crypto.h>
#include <AES.h>
#include <GCM.h>
struct TestVector
{
const char *name;
uint8_t key[32];
uint8_t authdata[20];
uint8_t iv[12];
uint8_t tag[16];
size_t authsize;
size_t tagsize;
size_t ivsize;
};
static TestVector const testVectorGCM PROGMEM = { //Dont forget to change the Values here
.name = "AES-256 GCM",
.key = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08},
.authdata = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
0xab, 0xad, 0xda, 0xd2},
.iv = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
0xde, 0xca, 0xf8, 0x88},
.tag = {0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b},
.authsize = 20,
.tagsize = 16,
.ivsize = 12
};
Now create a global buffer (easier to understand then pointers)
TestVector testVector;
byte buffer[128];
Encrytpion
{
memcpy_P(&testVector, test, sizeof(TestVector)); //Load into memory
test = &testVector;
size_t posn, len;
uint8_t tag[16];
crypto_feed_watchdog(); //To protect from Watchdog reseting this function
It is important to clear memory of any ciphering before doing one:
cipher->clear();
cipher->setKey(test->key, cipher->keySize()); //Setting key
cipher->setIV(test->iv, test->ivsize); //vector
for (posn = 0; posn < test->authsize; posn += datasize) {
len = test->authsize - posn;
if (len > datasize)
len = datasize;
cipher->addAuthData(test->authdata + posn, len); //To make hack even more confusing
}
Serial.print("input numbers ");
for(uint8_t i=0; i<60; i++) Serial.printf("%X",buffer[i]);
Serial.println();
for (posn = 0; posn < datasize; posn += datasize) {
len = datasize - posn;
if (len > datasize) len = datasize;
crypto_feed_watchdog();
cipher->encrypt((uint8_t*)buffer + posn, buffer + posn, len); //This is why we are here
crypto_feed_watchdog();
}
Serial.println("Vystup:\n");
for(uint8_t i=0; i<sizeof(buffer); i++) printf("0x%X,",buffer[i]);
}
Decryption
void decrypt(AuthenticatedCipher *cipher, const struct TestVector *test, size_t datasize){
bool ok;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
size_t posn, len;
uint8_t tag[16];
crypto_feed_watchdog();
cipher->clear();
cipher->setKey(test->key, cipher->keySize());
cipher->setIV(test->iv, test->ivsize);
for (posn = 0; posn < test->authsize; posn += datasize) {
len = test->authsize - posn;
if (len > datasize)
len = datasize;
cipher->addAuthData(test->authdata + posn, len);
}
for (posn = 0; posn < datasize; posn += datasize) {
len = datasize - posn;
if (len > datasize)
len = datasize;
cipher->decrypt((uint8_t*)buffer + posn, buffer + posn, len);
}
Serial.print("\nVystup: ");
for(uint8_t i=0; i<60;i++) Serial.printf("%c",(char)buffer[i]);
Serial.println();
}
-----------------------------------------------
full example:
/*Skúška kódovania GCM-AES256#*/
#include <Crypto.h>
#include <AES.h>
#include <GCM.h>
struct TestVector
{
const char *name;
uint8_t key[32];
uint8_t authdata[20];
uint8_t iv[12];
uint8_t tag[16];
size_t authsize;
size_t tagsize;
size_t ivsize;
};
static TestVector const testVectorGCM PROGMEM = {
.name = "AES-256 GCM",
.key = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08},
.authdata = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
0xab, 0xad, 0xda, 0xd2},
.iv = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
0xde, 0xca, 0xf8, 0x88},
.tag = {0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b},
.authsize = 20,
.tagsize = 16,
.ivsize = 12
};
TestVector testVector;
byte buffer[128];
void encrypt(AuthenticatedCipher *cipher, const struct TestVector *test, size_t datasize)
{
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
size_t posn, len;
uint8_t tag[16];
crypto_feed_watchdog();
cipher->clear();
cipher->setKey(test->key, cipher->keySize());
cipher->setIV(test->iv, test->ivsize);
for (posn = 0; posn < test->authsize; posn += datasize) {
len = test->authsize - posn;
if (len > datasize)
len = datasize;
cipher->addAuthData(test->authdata + posn, len);
}
Serial.print("Cisla: ");
for(uint8_t i=0; i<60; i++) Serial.printf("%X",buffer[i]);
Serial.println();
for (posn = 0; posn < datasize; posn += datasize) {
len = datasize - posn;
if (len > datasize) len = datasize;
crypto_feed_watchdog();
cipher->encrypt((uint8_t*)buffer + posn, buffer + posn, len);
crypto_feed_watchdog();
}
Serial.println("Vystup:\n");
// Decrypt
for(uint8_t i=0; i<sizeof(buffer); i++) printf("0x%X,",buffer[i]);
}
void decrypt(AuthenticatedCipher *cipher, const struct TestVector *test, size_t datasize){
bool ok;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
size_t posn, len;
uint8_t tag[16];
crypto_feed_watchdog();
cipher->clear();
cipher->setKey(test->key, cipher->keySize());
cipher->setIV(test->iv, test->ivsize);
for (posn = 0; posn < test->authsize; posn += datasize) {
len = test->authsize - posn;
if (len > datasize)
len = datasize;
cipher->addAuthData(test->authdata + posn, len);
}
for (posn = 0; posn < datasize; posn += datasize) {
len = datasize - posn;
if (len > datasize)
len = datasize;
cipher->decrypt((uint8_t*)buffer + posn, buffer + posn, len);
}
Serial.print("\nVystup: ");
for(uint8_t i=0; i<60;i++) Serial.printf("%c",(char)buffer[i]);
Serial.println();
}
void setup(){
Serial.begin(115200);
Serial.println("Začínam\n");
GCM <AES256> *gcm=0;
gcm= new GCM<AES256>();
gcm->setKey(testVectorGCM.key, 32);
gcm->setIV(testVectorGCM.iv,testVectorGCM.ivsize);
crypto_feed_watchdog();
memset(buffer, (int)'0円', sizeof(buffer));
char vstup[30]="Tak to netuším"; //String containing Non-Asci characters
for(uint8_t i=0; i<30; i++) buffer[i]=vstup[i];
encrypt(gcm,&testVectorGCM,30);
decrypt(gcm,&testVectorGCM,30);
delete gcm;
}
void loop(){
delay(1000);
Serial.print(".");
}
simple key generator in PHP:
<?php
for($i=0;$i<31;$i++) printf("0x%X,",random_int(0,0xFF));
printf("0x%X\n",random_int(0,0xFF));
?>
-
1Re "I could not figure-out how to convert utf-8 into numbers": an UTF-8 text is a sequence of 8-bit numbers. There is nothing to convert.Edgar Bonet– Edgar Bonet2020年05月19日 19:43:31 +00:00Commented May 19, 2020 at 19:43
-
I understand that, but the problem is that when one (char)letter get translated to multiple numbers (uint8_t), then converting it back require more then one conversion per number: needs to know how many numbers apply now and as such I could not convert numbers back to char lettersTomas– Tomas2020年05月20日 01:25:45 +00:00Commented May 20, 2020 at 1:25
-
the important part is "and back" as while I could decrypt to the same int array I could not convert the int array into char array with utf-8 letters.Tomas– Tomas2020年05月20日 01:33:25 +00:00Commented May 20, 2020 at 1:33
-
1A
char
is not a letter (or a character): it's a byte. It synonym ofint8_t
and differs fromuint8_t
only by signedness. UTF-8 encodes each character as a sequence of 8-bit "code units", thus an UTF-8 encoded text is just a byte array. You don't care about having a variable-width encoding unless you are converting to/from some form of wide characters. You can encrypt and decrypt the text with the same ease as ASCII text. If it happens to be stored as an array ofchar
, you encrypt it withcipher->encrypt((uint8_t*)buffer...)
and recover it withcipher->decrypt((uint8_t*)buffer...)
.Edgar Bonet– Edgar Bonet2020年05月20日 08:02:54 +00:00Commented May 20, 2020 at 8:02 -
What are the
authdata
,iv
andtag
parameters for? And should I change them too?krystof18– krystof182021年11月11日 20:24:03 +00:00Commented Nov 11, 2021 at 20:24
library.json
file