1

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
    It is not recommended to use ECB mode. GCM is currently state of art. – Kwasmich May 15 '20 at 6:18
  • install the library using your Arduino IDE, then look at the examples ... some of them show encrypt and decrypt functions ..... or look at the examples online github.com/OperatorFoundation/Crypto .... that link is found in the library.json file – jsotola May 15 '20 at 16:43
  • your avatar is ironic, considering the textbook image used to show why ECB sucks. – dandavis May 15 '20 at 18:22
  • @Kwasmich and dandavis I take your Point – Tomas May 16 '20 at 1:07
  • @jsotola I have seen them, but I still do not understand them where the output comes and what is what – Tomas May 16 '20 at 1:07
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));
?>
  • Re “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 May 19 '20 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 letters – Tomas May 20 '20 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 May 20 '20 at 1:33
  • A char is not a letter (or a character): it's a byte. It synonym of int8_t and differs from uint8_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 of char, you encrypt it with cipher->encrypt((uint8_t*)buffer...) and recover it with cipher->decrypt((uint8_t*)buffer...). – Edgar Bonet May 20 '20 at 8:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.