Шифрование в PHP, дешифрование в Arduino на ESP32

llaabbss
Offline
Зарегистрирован: 28.12.2017

Здравствуйте,

Не могу разобраться, поэтому прощу помощи или подсказок у знающих людей.

На ESP32 я хочу дешифровать данные, зашифрованные на странице сервера при помощи openssl в PHP.

PHP

<?php
	// Используемый метод шифрования
	$cipher_method = 'AES-128-ECB';

	// Шифруемая строка
	$string_to_be_ciphered = 'My sensitive information I want to cipher';

	// Ключ 16 байт (128 бит)
	$key = 'My_cipher_key___';

	// Зашифрованная строка
	$ciphered_text = openssl_encrypt($string_to_be_ciphered, $cipher_method, $key);

	// Кодирование в base64
	$base64_text = base64_encode($ciphered_text);

	echo '<b>ciphered_text: </b><br>' . $ciphered_text . '<br><br>';
	echo '<b>base64_text: </b><br>' . $base64_text . '<br>';
?>

 

В результате получаю это:

ciphered_text: 
qg4dnkyIKEyj3AXut8OJVebK/gS1IyT+2BwCbZXjLSuOV7G8pEnozuJUfjS1YP39
 
base64_text: 
cWc0ZG5reUlLRXlqM0FYdXQ4T0pWZWJLL2dTMUl5VCsyQndDYlpYakxTdU9WN0c4cEVub3p1SlVmalMxWVAzOQ==
 

ARDUINO

#include "mbedtls/aes.h"

extern "C" {
    #include "crypto/base64.h"
}

char stringToBeCiphered[] = "My sensitive information I want to cipher";
char key[] = "My_cipher_key___"; 
char cipheredText[] = "qg4dnkyIKEyj3AXut8OJVebK/gS1IyT+2BwCbZXjLSuOV7G8pEnozuJUfjS1YP39";
char base64CipheredText[] = "cWc0ZG5reUlLRXlqM0FYdXQ4T0pWZWJLL2dTMUl5VCsyQndDYlpYakxTdU9WN0c4cEVub3p1SlVmalMxWVAzOQ==";

// Буферы для хранения данные достаточно большие, чтобы вместить все необходимое
unsigned char cipherTextOutput[100+1];
unsigned char decipheredTextOutput[100+1];

size_t outputLength;

#define BAUDS 115200


void encrypt(char * stringToBeCiphered, char * key, unsigned char * outputBuffer){
    
    // Создаю контекст алгоритма
    mbedtls_aes_context aes;
    
    // Инициализирую этот контекст
    mbedtls_aes_init(&aes);
    
    // Задаю ключ шифрования
    mbedtls_aes_setkey_enc(&aes, (const unsigned char*) key, strlen(key) * 8);
    
    // Применяю шифрование ECB
    mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, (const unsigned char*)stringToBeCiphered, outputBuffer);
    
    // Очищаю контекст для следующего использования
    mbedtls_aes_free(&aes);

}

void decrypt(unsigned char * chipherText, char * key, unsigned char * outputBuffer){
    
    // Создаю контекст алгоритма
    mbedtls_aes_context aes;
    
    // Инициализирую этот контекст
    mbedtls_aes_init(&aes);
    
    // Задаю ключ дешифрования
    mbedtls_aes_setkey_dec(&aes, (const unsigned char*) key, strlen(key) * 8);
    
    // Применяю дешифрование ECB
    mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_DECRYPT, (const unsigned char*)chipherText, outputBuffer);

    // Очищаю контекст для следующего использования
    mbedtls_aes_free(&aes);

}

void setup() {

    Serial.begin(BAUDS);
    
    // 1. Шифрую исходный текст
    encrypt(stringToBeCiphered, key, cipherTextOutput);
    Serial.println(F("\nOriginal text to be ciphered:"));
    Serial.println(stringToBeCiphered);
    Serial.println(F("\nCiphered text by mbedtls/aes in Arduino:"));
    for (byte i = 0; i < 16; i++) {
        char str[3];
        sprintf(str, "%02x", (int)cipherTextOutput[i]);
        Serial.print(str);
    }
    
    Serial.println("\n");
    
    // 2. Декодирую base64 (для визуального контроля)
    unsigned char * decoded = base64_decode((const unsigned char *)base64CipheredText, strlen(base64CipheredText), &outputLength);

    Serial.print("Length of decoded message: ");
    Serial.println(outputLength);

    Serial.print("Decoded base64: ");
    Serial.printf("%.*s", outputLength, decoded);
    free(decoded); // Освобождаю занятую память

    Serial.println("\n");
    
    
    // 3. Расшифровываю закодированный текст
    Serial.print(F("cipheredText (by openssl in PHP): ")); Serial.println(cipheredText);
    
    byte cipheredTextLength = strlen(cipheredText);

    Serial.print(F("cipheredTextLength: ")); Serial.println(cipheredTextLength);
    Serial.println();
    
    decrypt((unsigned char *)cipheredText, key, decipheredTextOutput);
    Serial.println(F("Deciphered text by mbedtls/aes in Arduino:"));
    for (byte j = 0; j < cipheredTextLength; j++) {
        Serial.print((char)decipheredTextOutput[j]);
    }

    Serial.println(F("\n--------------\n"));
    
}

void loop() {
  // put your main code here, to run repeatedly:

}

В результате получаю это:

Original text to be ciphered:
My sensitive information I want to cipher
 
Ciphered text by mbedtls/aes in Arduino:
aa0e1d9e4c88284ca3dc05eeb7c38955
 
Length of decoded message: 64
 
Decoded base64: qg4dnkyIKEyj3AXut8OJVebK/gS1IyT+2BwCbZXjLSuOV7G8pEnozuJUfjS1YP39
 
cipheredText (by openssl in PHP): qg4dnkyIKEyj3AXut8OJVebK/gS1IyT+2BwCbZXjLSuOV7G8pEnozuJUfjS1YP39
cipheredTextLength: 64
 
Deciphered text by mbedtls/aes in Arduino:
⸮@⸮c⸮d⸮⸮⸮l⸮⸮⸮`⸮
 
Чего я не понял в использовании AES в Arduino?
llaabbss
Offline
Зарегистрирован: 28.12.2017

Результат шифрования Arduino не совпадает с результатом шифрования openssl:
aa0e1d9e4c88284ca3dc05eeb7c38955 (Arduino)
qg4dnkyIKEyj3AXut8OJVebK/gS1IyT+2BwCbZXjLSuOV7G8pEnozuJUfjS1YP39 (openssl)

Естественно, что дальше ничего тоже совпасть не может.

Как получить идентичные строки?

Алексей.
Алексей. аватар
Offline
Зарегистрирован: 02.02.2018

llaabbss пишет:
Результат шифрования Arduino не совпадает с результатом шифрования openssl:
aa0e1d9e4c88284ca3dc05eeb7c38955 (Arduino)
qg4dnkyIKEyj3AXut8OJVebK/gS1IyT+2BwCbZXjLSuOV7G8pEnozuJUfjS1YP39 (openssl)

Естественно, что дальше ничего тоже совпасть не может.

Как получить идентичные строки?


пых-пых выполняя openssl_encrypt получил данные уже закодированные в бейс64, потому как не сказали верни OPENSSL_RAW_DATA
зачем то ещё раз результат кодируете на base64_encode и выводите два результата.
если декодируете из бейс64 то что вернул openssl_encrypt (тот который называется ciphered_text) получите

0xaa, 0x0e, 0x1d, 0x9e, 0x4c, 0x88, 0x28, 0x4c, 0xa3, 0xdc, 0x05, 0xee, 0xb7, 0xc3, 0x89, 0x55,
0xe6, 0xca, 0xfe, 0x04, 0xb5, 0x23, 0x24, 0xfe, 0xd8, 0x1c, 0x02, 0x6d, 0x95, 0xe3, 0x2d, 0x2b,
0x8e, 0x57, 0xb1, 0xbc, 0xa4, 0x49, 0xe8, 0xce, 0xe2, 0x54, 0x7e, 0x34, 0xb5, 0x60, 0xfd, 0xfd
Теперь посмотрите на то что получилось на ардуине
aa0e1d9e4c88284ca3dc05eeb7c38955
первый бок совпадает,
mbedtls_aes_crypt_ecb немножко шифрует блоками
This function performs an AES single-block encryption or decryption operation.
если собираетесь шифровать остальные блоки, не забудте про паддинг последнего блока.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Алексей. пишет:

верни OPENSSL_RAW_DATA
зачем то ещё раз результат кодируете на base64_encode и выводите два результата.

Да, об OPENSSL_RAW_DATA - это точно подмечено. Спасибо.

Теперь буду читать о блоках.

llaabbss
Offline
Зарегистрирован: 28.12.2017

Конкретно для своего случая я разобрался. Но дальше копать не стал. Сделал только для ECB метода. Да, он не фонтан и у него есть ограничения, но для не очень требовательных задач может подойти. В общем, кому пригодится, то правильно это работает вот так.

Итак, пытаюсь зашифровать сообщение Some_secret_data. Длина этого сообщения не должна превышать 16 байт, потому что ECB на Arduino вернет только первые 16 байт. Возможно, я просто не до конца разобрался, но в этом исполнении это именно так.

PHP

<?php
	// Используемый метод шифрования
	$cipher_method = 'AES-128-ECB';
	
	// Шифруемая строка
	$string_to_be_ciphered = 'Some_secret_data'; // Не более 16 байт. Вот здесь и заключается одно из ограничений. Если вы захотите по этому методу зашифровать сообщение длиннее, чем 16 байт, то дешифруются только первые 16 байт

	// Ключ к шифру 
	$key = 'My_cipher_key___'; // 16 байт (128 бит)

	
	echo '<b>$cipher_method: </b><br>' . $cipher_method . '<br><br>';
	echo '<b>$string_to_be_ciphered: </b><br>' . $string_to_be_ciphered . '<br><br>';
	echo '<b>$key: </b><br>' . $key . '<br><br>';
	
	echo '<hr>';
	echo '<br>';
	
	// Зашифрованная строка
	$ciphered_text = openssl_encrypt($string_to_be_ciphered, $cipher_method, $key); // Уже закодировано в base64
	
	echo '<b>ciphered_text (in base64): </b><br>' . $ciphered_text . '<br><br>';
	
	echo '<hr>';
	echo '<br>';
	
	// Расшифровываем (для самоконтроля)
	$deciphered_text = openssl_decrypt($ciphered_text, $cipher_method, $key);
	
	echo '<b>deciphered_text: </b><br>' . $deciphered_text . '<br><br>';
	
?>

На выходе в PHP получаю L0+zSw7zBTphOCGNtPDbiVx7SNvH7A+530X0Xw3a0QU=
Это и есть зашифрованный текст. 

ARDUINO

#include "mbedtls/aes.h"

extern "C" {
    #include "crypto/base64.h"
}

// Ключ к шифру
char key[] = "My_cipher_key___"; // Тот же самый ключ, что и в PHP, иначе ничего не получится. Это еще одно ограничение для этого метода шифрования

// Шифр, сгенерированный в PHP
char base64CipheredText[] = "L0+zSw7zBTphOCGNtPDbiVx7SNvH7A+530X0Xw3a0QU=";

// Буфер для хранения данных достаточно большой, чтобы вместить все необходимое
unsigned char decipheredTextOutput[100];

size_t outputLength;

#define BAUDS 115200


// Дешифрование в ECB
void decrypt(unsigned char * chipheredText, char * key, unsigned char * outputBuffer){
    
    // Создаю контекст алгоритма
    mbedtls_aes_context aes;
    
    // Инициализирую этот контекст
    mbedtls_aes_init(&aes);
    
    // Задаю ключ дешифрования
    mbedtls_aes_setkey_dec(&aes, (const unsigned char*) key, 128); // 128 бит
    
    // Применяю дешифрование ECB
    mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_DECRYPT, (const unsigned char*)chipheredText, outputBuffer);

    // Очищаю контекст для следующего использования
    mbedtls_aes_free(&aes);

}


void setup() {

    Serial.begin(BAUDS);
    
    // Декодирую base64, поскольку входящее сообщение пришло закодированным в base64
    unsigned char * decoded = base64_decode((const unsigned char *)base64CipheredText, strlen(base64CipheredText), &outputLength);

    free(decoded); // Освобождаю занятую память
    
    // Расшифровываю декодированный текст
    decrypt((unsigned char *)decoded, key, decipheredTextOutput);
    
    Serial.println(F("Deciphered text by mbedtls/aes in Arduino:"));
    
    for (byte j = 0; j < strlen(base64CipheredText) / 2; j++) {
        Serial.print((char)decipheredTextOutput[j]);
    }
    
}

void loop() {
 
}

На выходе Arduino получаю ту самую фразу Some_secret_data

Теперь все работает правильно.

Алексей.
Алексей. аватар
Offline
Зарегистрирован: 02.02.2018

llaabbss пишет:

Конкретно для своего случая я разобрался. Но дальше копать не стал. Сделал только для ECB метода. Да, он не фонтан и у него есть ограничения, но для не очень требовательных задач может подойти.

Мне кажется там всё очевидно,
выполняем дешифрацию каждого блока

0xaa, 0x0e, 0x1d, 0x9e, 0x4c, 0x88, 0x28, 0x4c, 0xa3, 0xdc, 0x05, 0xee, 0xb7, 0xc3, 0x89, 0x55,
0xe6, 0xca, 0xfe, 0x04, 0xb5, 0x23, 0x24, 0xfe, 0xd8, 0x1c, 0x02, 0x6d, 0x95, 0xe3, 0x2d, 0x2b,
0x8e, 0x57, 0xb1, 0xbc, 0xa4, 0x49, 0xe8, 0xce, 0xe2, 0x54, 0x7e, 0x34, 0xb5, 0x60, 0xfd, 0xfd

получаем

00000000 | 4d 79 20 73 65 6e 73 69 74 69 76 65 20 69 6e 66 | My sensitive inf
00000010 | 6f 72 6d 61 74 69 6f 6e 20 49 20 77 61 6e 74 20 | ormation I want
00000020 | 74 6f 20 63 69 70 68 65 72 07 07 07 07 07 07 07 | to cipher.......

в последнем блоке видим стандартный падиинг для  pkcs#7