ESP32(PlatformIO)中esp_aes_crypt_ecb最后块加密失败求助
问题:ESP32 AES-ECB加密最后一块数据异常
在ESP32(PlatformIO环境)中实现AES-ECB加密,明文长度31字符,需拆分为3个16字节块。前两块加密结果与在线工具一致,但最后一块加密失败,在线工具解密时提示“Given final block not properly padded”,且ESP32输出的最后块与在线工具结果不符。当前代码中最后一块按C/C++字符串规则以0填充。
相关代码
#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 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'}; 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 inputBlock[16] = {0}; unsigned char output[17] = {0}; unsigned char encrypted[255] = {0}; esp_aes_context aes; 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_LOG_BUFFER_HEXDUMP(TAG, encrypted, 128, ESP_LOG_WARN); esp_aes_free(&aes); } void app_main(){ crypto_aes_ecb("Testing encryption... Testing encryption..."); }
测试结果对比
- ESP32输出加密HexDump:
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
- 在线工具加密结果:
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
问题根源与解决方案
问题根源
- 填充方式不匹配:在线工具默认采用PKCS#7填充,而当前代码使用Zero Padding(全0填充)。PKCS#7规则是:若数据块长度不足16字节,则填充
16 - 剩余字节数个值为该数字的字节。31字节明文的最后一块需要填充1个0x01,而非全0。 - 字符串处理逻辑错误:代码读取到字符串结束符
\0时,会将该\0写入块中再填充0,导致最后一块的第一个字节是无效结束符,而非正确的明文末尾字符加PKCS#7填充。 - 全局变量风险:原代码中
esp_aes_context为全局变量,多任务环境下易引发上下文冲突。 - 密钥长度冗余:AES-256需要32字节密钥,原key数组末尾的
\0属于冗余字符,会导致密钥实际传入长度异常。
修复代码
#include <stdio.h> #include <string.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 // AES-256密钥:32字节,无末尾\0 unsigned char key[32] = {'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'}; void crypto_aes_ecb(char *input){ static const char *TAG = "CryptTest"; esp_aes_context aes; unsigned char encrypted[255] = {0}; size_t inputLen = strlen(input); // 计算总块数:向上取整 size_t totalBlocks = (inputLen + 15) / 16; unsigned char inputBlock[16] = {0}; unsigned char output[16] = {0}; esp_aes_init(&aes); esp_aes_setkey(&aes, key, 256); for(size_t blockIdx = 0; blockIdx < totalBlocks; blockIdx++){ size_t startPos = blockIdx * 16; // 计算当前块需要复制的有效字节数 size_t copyLen = (startPos + 16) <= inputLen ? 16 : (inputLen - startPos); memset(inputBlock, 0, sizeof(inputBlock)); memcpy(inputBlock, input + startPos, copyLen); // 应用PKCS#7填充 int padLen = 16 - copyLen; memset(inputBlock + copyLen, padLen, padLen); ESP_LOGI(TAG, "Block %d input (hex):", blockIdx); ESP_LOG_BUFFER_HEX(TAG, inputBlock, 16, ESP_LOG_INFO); // 加密当前块 esp_aes_crypt_ecb(&aes, ESP_AES_ENCRYPT, inputBlock, output); memcpy(encrypted + blockIdx*16, output, 16); } ESP_LOGW(TAG, "-----------------------------------------------------------------------------------"); ESP_LOGW(TAG, "Key length: %zu bytes", sizeof(key)); ESP_LOGW(TAG, "Input : '%s' (length: %zu)", input, inputLen); ESP_LOG_BUFFER_HEXDUMP(TAG, encrypted, totalBlocks*16, ESP_LOG_WARN); esp_aes_free(&aes); } void app_main(){ crypto_aes_ecb("Testing encryption... Testing encryption..."); }
修复说明
- PKCS#7填充:根据块剩余长度填充对应数值的字节,确保与在线工具填充规则一致。
- 字符串长度计算:通过
strlen获取明文真实长度,避免被\0提前截断。 - 局部上下文:将
esp_aes_context改为函数内局部变量,避免多任务冲突。 - 密钥修正:移除密钥数组末尾的
\0,确保AES-256使用正确的32字节密钥。
内容的提问来源于stack exchange,提问作者Geir
相关产品推荐
相关产品推荐

