当前位置: 首页 > 知识库问答 >
问题:

AES 128 在 Arduino ESP8266 和在线工具中有不同的结果

廖夜洛
2023-03-14

我想通过AES 128 CBC加密文本,但在Arduino和在线工具中结果不同。我尝试了不同的Arduino库,但仍然有相同的问题。我在arduino中的代码如下。

#include <Crypto.h>
#include <ebase64.h>

#define BLOCK_SIZE 16

byte key[BLOCK_SIZE] = {0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30};
byte iv[BLOCK_SIZE] = {0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30};

void bufferSize(char* text, int &length)
{
int i = strlen(text);
int buf = round(i / BLOCK_SIZE) * BLOCK_SIZE;
length = (buf < i) ? buf + BLOCK_SIZE : length = buf;
}

void encrypt(char* plain_text, char* output, int length)
{
byte enciphered[length];

AES aesEncryptor(key, iv, AES::AES_MODE_128, AES::CIPHER_ENCRYPT);
aesEncryptor.process((uint8_t*)plain_text, enciphered, length);

int encrypted_size = sizeof(enciphered);
char encoded[encrypted_size];
base64_encode(encoded, (char*)enciphered, encrypted_size);

strcpy(output, encoded);
}

void decrypt(char* enciphered, char* output, int length)
{
length = length + 1; //re-adjust
int decodedLen = base64_dec_len(enciphered, length);
char decoded[length];

Serial.println(enciphered);
base64_decode(decoded, enciphered, length);
bufferSize(enciphered, length);
byte deciphered[length];
AES aesDecryptor(key, iv, AES::AES_MODE_128, AES::CIPHER_DECRYPT);

aesDecryptor.process((uint8_t*)decoded, deciphered, length);
strcpy(output, (char*)deciphered);
}

void setup()
{
Serial.begin(115200);
while (!Serial) {
; //wait
}

char plain_text[] = "Now is the time ABCDABC";

// encrypt
int length = 0;
bufferSize(plain_text, length);
Serial.println(length);
char encrypted[length];
encrypt(plain_text, encrypted, length);

Serial.println(encrypted);

// decrypt

length = strlen(encrypted);
char decrypted[length];
decrypt(encrypted, decrypted, length);

Serial.println(decrypted);
}
void loop()
{
}

键和IV:

{0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x 30 };

或者

{ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' };

文本:“现在是ABCDABC的时候了”;

加密的是

1a7OeiH628V7IIoLU6 3n70Dzp6FBQjlGPxSwnuXdzo=

和AES在线工具。[https://www.devglan.com/online-tools/aes-encryption-decryption]

密钥:0000000000000000

IV:0000000000000000

正文:现在是时候了

我在网上加密,结果是

1a7OeiH628V7IIoLU6 3n7ILev6IwcZYVNLalS/TBEg=

所以我无法互相解密。有人可以帮助我吗?多谢!

共有2个答案

幸阳波
2023-03-14

在这两种情况下,您的加密数据都是正确的。

1a7OeiH628V7IIoLU6+3n70Dzp6FBQjlGPxSwnuXdzo=

解码为:

d5 ae ce 7a 21 fa db c5 7b 20 8a 0b 53 af b7 9f 

bd 03 ce 9e 85 05 08 e5 18 fc 52 c2 7b 97 77 3a

1a7OeiH628V7IIoLU6+3n7ILev6IwcZYVNLalS/TBEg=

解码为:

d5 ae ce 7a 21 fa db c5 7b 20 8a 0b 53 af b7 9f 

b2 0b 7a fe 88 c1 c6 58 54 d2 da 95 2f d3 04 48

正如你所看到的,前16个字节是可以的。那可以解释为:两种情况下的Key和IV都是一样的。在您的情况下,如果整个块都正常,只有最后一个块有问题,似乎问题出在填充模式

您的文本:“现在是 ABCDABC 的时间”有 24 个字节(带有空结尾字符),但此加密算法需要 16 个字节的倍数。因此,必须将其填充到 32 个字节。它将有 8 个填充字节。但有什么价值呢?

我用Arduino AESLib实验了同样的问题。我发现2.0以下的版本只支持一种填充模式(不幸的是与在线工具不兼容),这是唯一的选择,自己做。但是在2.0.2版中,他们改进了它,增加了对多种模式的支持。

大多数在线工具使用作为默认的PKCS7填充,但出于兼容性原因,Arduino AESLib使用数组模式初始化。

所以我需要打电话:

aes.setPadMode(paddingMode::CMS); 

在使用doaaesencrypt之前,doaaes_decrypt<-code>函数。

这些功能根据配置管理所有填充和大小调整问题。

在您的情况下,您可以调用

aesEncryptor.process((uint8_t*)plain_text, enciphered, length);

它没有填充管理,必须在调用之前完成。

因此,该函数在plain_text[]数组的末尾使用了额外的8个字节作为其未初始化内存值的填充。

孙岳
2023-03-14

看起来这是其中一个例子,一个加密库的作者甚至比执行这种壮举的“在线工具”的作者更无知:

   /**
     * Either encrypt or decrypt [in] and store into [out] for [length] bytes, applying padding as needed
     * 
     * Note: the length must be a multiple of 16 bytes
     */
    void process(const uint8_t *in, uint8_t *out, int length);

现在没有指定使用哪个填充,也没有指定如何移除它。此外,显然输入不应该总是16的倍数,这没有任何意义。

然而,没有填充的解密可以用于恢复明文:

4e6f77206973207468652074696d6520414243444142430020000000feefeffe
4e6f77206973207468652074696d652041424344414243090909090909090909
 N o w   i s   t h e   t i m e   A B C D A B C

这里第一个是你的加密。显然,它根本没有显示正确的填充。它是一个零字节,一个<code>02</code>字节,然后是一些零,后面是<code>feefeff</code>,这非常像是一种检测未初始化内存或类似内存的方法。在线图书馆使用PKCS#7兼容的填充。

我看代码的第一个想法是,你在声明包含密文的数组时是错误的:

byte enciphered[length];

显然,如果密文的长度由于填充而扩大了明文的长度,这是不正确的。所以这里可能有缓冲区溢出。然而,即使对于最后一个块,您仍然得到原始的明文,所以库也一定是错误的。

这个故事的寓意:不要在GitHub上使用可怕的单人库。库需要经过测试,并有一个团队支持它,以便对加密货币足够值得信赖。

 类似资料:
  • 我有相同的数据和加密密钥,相同的算法,相同的模式,但不同的结果。 C#代码: 结果:13A6DAD3119F29A8C4BF6D5BD11564E4E1A93F85B7F2AD9E8E97756688754DE32A23ADE41DFD9F76186D8E25E66D0DCF458ECAA026F16463811C48FC814E50B10FF57FDDB0C0761088D1AC4DDDAE74

  • 正如gcloud组件文档所说,我们可以使用以下命令安装一些工具,如:、: 我可以使用原来的minikube和(例如,通过命令安装)来替换gcloud组件工具吗?

  • 我正在使用tomcat、jsp和MSSQL2008,希望获得一些汇总数据,如每日、每周、每月和每年。从这里,我搜索了如何对来自MSSQL的这些摘要数据使用datapart()函数。在JSP中,我使用 在MSMS中,查询指令进行测试。 我在JSP程序中遇到了两个问题,但在MS SQL Server Management Studio中使用相同的查询可以很好地工作。 null 我的问题是:

  • 我有一个使用本教程创建的抽屉和滑动选项卡的项目。我正在使用支持库使材料设计可用于较老的android版本。我还使用了而不是。我有一个连接到工具栏菜单: 我已经找了好几个星期了,为了有效果。我做错什么了吗? 我如何才能有每个片段的特定菜单?我认为隐藏菜单项可能是更容易实现的选择,但如果你们有任何其他方法来实现,我将不胜感激。

  • BatchWrit在Laqmbda中不适用于异步。代码将插入一条记录,但它不能。但是,当我删除异步时,它可以工作。 结果如下。没有错误。 你们有同样的行为吗?

  • 问题内容: 该查询工作正常。但是问题是,产品表和类别表都具有名为“ name”和“ id”的字段。因此,当我获取此查询的结果时,它只给我一个名称和一个ID,但同时又需要ID和名称。 我如何做到这一点而不必重命名字段?是否可以使用自定义名称(例如product_name和category_name)返回? 问题答案: 您可以将别名添加到字段: