0

I am trying to encrypt data from ESP32 to an Internet webpage. The plain text is 31 characters long and will need 3 blocks of 16 characters. The 2 first blocks encrypts fine, but the last one fails. The last block is terminated by a 0 in spec for C/C++ string standard.

Please have a look at my code for ref:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "mbedtls/aes.h"

#include "esp_log.h"
#include "aes/esp_aes.h"
#include "mbedtls/base64.h"

#define ESP_AES_ENCRYPT 1

esp_aes_context aes;

unsigned char key[33] = {'d', 'v', 'i', 'z', 'd', 'u', 'm', 'c', 's', 'm', 'v', 'l', 'v', 'f', 'd', 'v', 'b', 'j', 's', 'v', 'd', 'u', 'i', 'a', 's', 'r', 'u', 'i', 'a', 'e', 'u', 'y', '\0'};
unsigned char encrypted[255] = {0};

void crypto_aes_ecb(char *input){
    static const char *TAG = "CryptTest";
    bool doEncrypt = true;
    uint16_t blockIndex = 0;
    uint16_t inputIndex = 0;
    uint16_t outputIndex = 0;
//    unsigned char input[64] = {'T', 'e', 's', 't', 'i', 'n', 'g', ' ', 'e', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', '.', '.', '.', ' ', 'T', 'e', 's', 't', 'i', 'n', 'g', ' ', 'e', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', '.', '.', '.', '\0'};
    unsigned char inputBlock[16] = {0};
    unsigned char output[17] = {0};
    esp_aes_init(&aes);
    esp_aes_setkey(&aes, (const unsigned char*) key, 256);
    inputIndex = 0;
    while(doEncrypt){
        for (blockIndex = 0; blockIndex < 16; blockIndex++){
            inputBlock[blockIndex] = input[blockIndex + (inputIndex * 16)];
            if(input[blockIndex + (inputIndex * 16)] == '\0'){
                for (; blockIndex < 16; blockIndex++){inputBlock[blockIndex] = 0;}
                doEncrypt = false;
                break;
            }
        }
        inputIndex++;
        inputBlock[16] = '\0';
        ESP_LOGI(TAG, "inputBlock = '%s'", inputBlock);
        esp_aes_crypt_ecb(&aes, ESP_AES_ENCRYPT, (const unsigned char *)inputBlock, output);
        for (blockIndex = 0; blockIndex < 16; blockIndex++){
            encrypted[blockIndex + (outputIndex * 16)] = output[blockIndex];
        }
        outputIndex++;
    }
    ESP_LOGW(TAG, "-----------------------------------------------------------------------------------");
    ESP_LOGW(TAG, "Key     : '%s'", key);
    ESP_LOGW(TAG, "Input   : '%s'", input);
//    ESP_LOGW(TAG, "Output  : '%s'", encrypted);
    ESP_LOG_BUFFER_HEXDUMP(TAG, encrypted, 128, ESP_LOG_WARN);
    esp_aes_free(&aes);
}

void app_main(){
    crypto_aes_ecb("Testing encryption... Testing encryption...");
}

Testing the HexDump with an online encrypt / decrypt tester, it reports "Given final block not properly padded. Such issues can arise if a bad key is used during decryption." Testing the plain text, I can see that the last block is different than my ESP32. Any idea how to solve this?

Test web site : https://www.devglan.com/online-tools/aes-encryption-decryption

Dump from ESP32 : 
ea 99 ca 39 2b 62 58 ce 71 5a 75 62 fe ac b7 f0 29 16 0c 1e 20 f5 ba 6f b0 7e c7 ee 0b eb 3a e3 89 51 f4 84 97 61 4b e8 66 22 78 72 60 0f 3e 2d
Result from web page : 
EA 99 CA 39 2B 62 58 CE 71 5A 75 62 FE AC B7 F0 29 16 0C 1E 20 F5 BA 6F B0 7E C7 EE 0B EB 3A E3 3F 3E 65 3F 78 BA AD 13 AE 74 3E 99 44 1F E1 E5

I have tried Googling the encryption method, but no success. Most examples results in compile error. I have tried ChatGPT. Also results in compile errors. They warn me of "unsafe" encryption using ECB. The warning does not apply to me. My ESP32 will only send 10-15 blocks before the Secret Key is updated.

Geir
  • 3
  • 2
  • The difference is in the padding, the website uses PKCS#7 padding, in your code zero padding is applied: https://gchq.github.io/CyberChef/#recipe=AES_Decrypt(%7B'option':'UTF8','string':'dvizdumcsmvlvfdvbjsvduiasruiaeuy'%7D,%7B'option':'Hex','string':''%7D,'ECB/NoPadding','Hex','Raw',%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D)&input=ZWE5OWNhMzkyYjYyNThjZTcxNWE3NTYyZmVhY2I3ZjAyOTE2MGMxZTIwZjViYTZmYjA3ZWM3ZWUwYmViM2FlMzg5NTFmNDg0OTc2MTRiZTg2NjIyNzg3MjYwMGYzZTJk – Topaco Jul 31 '23 at 17:52
  • No padding would work fine for me. However, I'm unable to decrypt the data on the PHP server. --------- ( same cryptokey and encrypted text) $bindata = hex2bin($encrypted); echo "'" . openssl_decrypt($bindata, "AES-256-ECB", $cryptoKey, OPENSSL_ZERO_PADDING) . "'\n"; echo "'" . openssl_decrypt($bindata, "AES-256-ECB", $cryptoKey, OPENSSL_DONT_ZERO_PAD_KEY) . "'\n"; echo "'" . openssl_decrypt($bindata, 'AES-128-ECB', $cryptoKey, OPENSSL_ZERO_PADDING) . "'\n"; --------- All 3 alternatives returns nothing. Is there a way to have PHP accept my encrypted data? – Geir Aug 01 '23 at 10:16
  • This is actually a new question and should be posted as such in a new question. Anyway, the first code works if you also set the `OPENSSL_RAW_DATA` flag. Also, `$test` is not defined, which may just be a copy/paste issue: https://paiza.io/projects/bZmQHNNslE3kz9UQWjZBDA. Note that `OPENSSL_ZERO_PADDING` does not apply zero padding, but only disables padding (the name is poorly chosen), i.e. the decrypted data still contains the 0x00 padding bytes at the end. The 2nd and 3rd codes do not work (`OPENSSL_DONT_ZERO_PAD_KEY` is used in the context of Blowfish and AES-128 is simply wrong). – Topaco Aug 01 '23 at 10:46
  • I stand corrected. "OPENSSL_ZERO_PADDING" works fine. It wants to have the enctrypted data formatted as Base64. ----------- $test = hex2bin($encrypted); $base64 = base64_encode($test); $intRes = openssl_decrypt($base64, 'AES-256-ECB', $cryptoKey, OPENSSL_ZERO_PADDING); ----------- This returns the decrypted data :-) – Geir Aug 01 '23 at 10:55

1 Answers1

0

So - my solution, if anyone wants a working example:

--- ESP32 side ---

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "mbedtls/aes.h"

#include "esp_log.h"
#include "aes/esp_aes.h"
#include "mbedtls/base64.h"

#define ESP_AES_ENCRYPT 1

esp_aes_context aes;

unsigned char key[33] = {'d', 'v', 'i', 'z', 'd', 'u', 'm', 'c', 's', 'm', 'v', 'l', 'v', 'f', 'd', 'v', 'b', 'j', 's', 'v', 'd', 'u', 'i', 'a', 's', 'r', 'u', 'i', 'a', 'e', 'u', 'y', '\0'};
unsigned char encoded[1024] = {0};

void crypto_aes_ecb(char *input){
    static const char *TAG = "CryptTest";
    bool doEncrypt = true;
    uint16_t blockIndex = 0;
    uint16_t inputIndex = 0;
    uint16_t outputIndex = 0;
    uint16_t encryptedLength = 0;
    size_t encodedLength = 0;
    unsigned char inputBlock[16] = {0};
    unsigned char outputBlock[17] = {0};
    unsigned char encrypted_raw[1024] = {0};
    esp_aes_init(&aes);
    esp_aes_setkey(&aes, (const unsigned char*) key, 256);
    inputIndex = 0;
    while(doEncrypt){
        for (blockIndex = 0; blockIndex < 16; blockIndex++){
            inputBlock[blockIndex] = input[blockIndex + (inputIndex * 16)];
            if(input[blockIndex + (inputIndex * 16)] == '\0'){
                for (; blockIndex < 16; blockIndex++){inputBlock[blockIndex] = '\0';}
                doEncrypt = false;
                break;
            }
        }
        if(input[blockIndex + (inputIndex * 16)] == '\0'){doEncrypt = false;}
        inputBlock[16] = '\0';
        ESP_LOGI(TAG, "inputBlock = '%s'", inputBlock);
        esp_aes_crypt_ecb(&aes, ESP_AES_ENCRYPT, (const unsigned char *)inputBlock, outputBlock);
        for (blockIndex = 0; blockIndex < 16; blockIndex++){
            encrypted_raw[blockIndex + (outputIndex * 16)] = outputBlock[blockIndex];
        }
        encryptedLength = blockIndex + (outputIndex * 16);
        inputIndex++;
        outputIndex++;
    }
//    encodedLength = mbedtls_base64_encode(encrypted_raw, encryptedLength, encoded, sizeof(encoded));
    mbedtls_base64_encode((unsigned char*)encoded, sizeof(encoded), &encodedLength, encrypted_raw, encryptedLength);
    encoded[encodedLength] = '\0';
    ESP_LOGW(TAG, "-----------------------------------------------------------------------------------");
    ESP_LOGI(TAG, "Key     : '%s'", key);
    ESP_LOGI(TAG, "Input   : '%s'", input);
    ESP_LOGI(TAG, "Output  : '%s'", encoded);
    esp_aes_free(&aes);
}

void app_main(){
    crypto_aes_ecb("Testing encryption... Testing encryption...");
}

--- Result ---

I (325) CryptTest: -----------------------------------------------------------------------------------
I (335) CryptTest: Key     : 'dvizdumcsmvlvfdvbjsvduiasruiaeuy'
I (335) CryptTest: Input   : 'Testing encryption... Testing encryption...'
I (345) CryptTest: Output  : '6pnKOStiWM5xWnVi/qy38CkWDB4g9bpvsH7H7gvrOuOJUfSEl2FL6GYieHJgDz4t'

--- PHP side ---

<?php
    $cryptoKey = "dvizdumcsmvlvfdvbjsvduiasruiaeuy";
    $base64 = "6pnKOStiWM5xWnVi/qy38CkWDB4g9bpvsH7H7gvrOuOJUfSEl2FL6GYieHJgDz4t";
    $intRes = openssl_decrypt($base64, 'AES-256-ECB', $cryptoKey,  OPENSSL_ZERO_PADDING);
    $decrypted = rtrim($intRes, "\0");
    echo "<html>\n<body>\n";
    echo "Key       : '" . $cryptoKey . "'<br />\n";
    echo "Input     : '" . $base64 . "'<br />\n";
    echo "Decrypted : '" . $decrypted . "'<br />\n";
    echo "</body>\n</html>\n";
?>

--- Result ---

Key : 'dvizdumcsmvlvfdvbjsvduiasruiaeuy'
Input : '6pnKOStiWM5xWnVi/qy38CkWDB4g9bpvsH7H7gvrOuOJUfSEl2FL6GYieHJgDz4t'
Decrypted : 'Testing encryption... Testing encryption...'
Geir
  • 3
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 06 '23 at 23:58