【问题标题】:Linux libcrypto AES-128 CBC Encryption/Decryption works on Ubuntu but not Raspberry PiLinux libcrypto AES-128 CBC 加密/解密适用于 Ubuntu,但不适用于 Raspberry Pi
【发布时间】:2017-09-14 15:44:07
【问题描述】:

以下示例在 64 位桌面 Ubuntu 16.04 上正确加密和解​​密为相同的原始字符串,但是当相同的代码在 Raspberry Pi (ARM)(以及另一个自定义 Linux ARM 板)上编译和运行时,它会失败解密为原始字符串。 Raspberry Pi 和其他 ARM 板都解密为相同但不正确的值。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/crypto.h>

/* AES key for Encryption and Decryption */
const static unsigned char aes_key[]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};

/* Print Encrypted and Decrypted data packets */
void print_data(const char *tittle, const void* data, int len);

int main( )
{
    /* Input data to encrypt */
    unsigned char aes_input[]={0x0,0x1,0x2,0x3,0x4,0x5};

    fprintf(stderr,"%s\n",SSLeay_version(SSLEAY_VERSION));

    /* Init vector */
    unsigned char iv[AES_BLOCK_SIZE];
    memset(iv, 0x00, AES_BLOCK_SIZE);

    /* Buffers for Encryption and Decryption */
    unsigned char enc_out[sizeof(aes_input)];
    unsigned char dec_out[sizeof(aes_input)];

    /* AES-128 bit CBC Encryption */
    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key);
    AES_cbc_encrypt(aes_input, enc_out, sizeof(aes_input), &enc_key, iv,         AES_ENCRYPT);
    /* AES-128 bit CBC Decryption */
    memset(iv, 0x00, AES_BLOCK_SIZE); // don't forget to set iv vector again, else you can't decrypt data properly
    AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
    AES_cbc_encrypt(enc_out, dec_out, sizeof(aes_input), &dec_key, iv, AES_DECRYPT);

    /* Printing and Verifying */
    print_data("\n Original ",aes_input, sizeof(aes_input)); // you can not print data as a string, because after Encryption its not ASCII

    print_data("\n Encrypted",enc_out, sizeof(enc_out));

    print_data("\n Decrypted",dec_out, sizeof(dec_out));

    return 0;
}

void print_data(const char *tittle, const void* data, int len)
{
    printf("%s : ",tittle);
    const unsigned char * p = (const unsigned char*)data;
    int i = 0;

    for (; i<len; ++i)
        printf("%02X ", *p++);

    printf("\n");
}

Ubuntu 结果:

 OpenSSL 1.0.1f 6 Jan 2014

 Original  : 00 01 02 03 04 05 

 Encrypted : D5 40 D0 BB 16 1D 

 Decrypted : 00 01 02 03 04 05 

树莓派结果:

OpenSSL 1.0.2l  25 May 2017

Original  : 00 01 02 03 04 05 

Encrypted : D5 40 D0 BB 16 1D 

Decrypted : D3 87 81 20 2B B9

自定义板结果:

OpenSSL 1.1.0f  25 May 2017

Original  : 00 01 02 03 04 05 

Encrypted : D5 40 D0 BB 16 1D 

Decrypted : D3 87 81 20 2B B9 

自定义板(更新 OpenSSL 以匹配 Ubuntu):

 OpenSSL 1.0.1f 6 Jan 2014

 Original  : 00 01 02 03 04 05 

 Encrypted : D5 40 D0 BB 16 1D 

 Decrypted : D3 87 81 20 2B B9

为什么开源 libcrypto 在 Ubuntu 和 2 台不同的 ARM 机器上表现不同?

【问题讨论】:

  • 您的openssl 版本是否跨平台相同?我知道不同的openssl 版本和libcrypto 在解密中不包含相同的结果存在问题。
  • 我刚刚更新了帖子 - 我将定制板的 RFS 降级为 Ubuntu 的匹配版本,但仍然失败。
  • 我认为 AES_cbc_encrypt 的输出大小必须是 AES_BLOCK_SIZE 的倍数。
  • @n.m.感谢您的意见。我在 Pi 上再次尝试使用 16 字节的字符串进行加密,它成功了。所以某些版本的 libcrypto 必须静默填充数据,而某些版本必须加密而不抱怨数据不是 AES_BLOCK_SIZE 的倍数。似乎有缺陷...感谢您的帮助

标签: c linux encryption openssl libcrypto


【解决方案1】:

通常在 CBC 模式下,您使用的缓冲区大小是密码块大小的倍数。这是 CBC 的本质,在 CBC 类型例程的每个 openssl 手册页中都提到了它(不幸的是,我在 AES_cbc_encrypt 上找不到手册页或任何文档)。

错误的缓冲区大小似乎完全靠运气在某些平台上工作。要查看实际发生的情况,请为enc_out 多分配一个字节,并在加密后将多余的字节清零。解密将失败。

unsigned char enc_out[sizeof(aes_input) + 1];
...
AES_cbc_encrypt(aes_input, enc_out, sizeof(aes_input), &enc_key, iv, AES_ENCRYPT);
enc_out[sizeof(aes_input)] = 0;

修改后的代码在我的机器上的输出:

Original  : 00 01 02 03 04 05 

Encrypted : D5 40 D0 BB 16 1D 00 

Decrypted : 89 FB 06 F4 CD 6A 

未修改的代码会产生“正确”的输出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 2020-04-28
    • 2020-11-29
    • 1970-01-01
    • 2019-08-17
    • 2020-04-15
    相关资源
    最近更新 更多