使用C语言的openssl库进行简单的AES加密解密

我想加密一个包含少量String的结构,然后解密它。 我尝试了以下代码。 原始代码可以从网上找到,它运行得很好。 我将它的输入更改为结构。 以下是代码。

#include  #include  #include  #include  #include  #include  typedef struct ticket { /* test field */ int ticketId; char username[20]; char date[20]; } USR_TICKET; // a simple hex-print routine. could be modified to print 16 bytes-per-line static void hex_print(const void* pv, size_t len) { const unsigned char * p = (const unsigned char*)pv; if (NULL == pv) printf("NULL"); else { size_t i = 0; for (; iusername); printf("Ticket Id - %d\n", dyc->ticketId); printf("Date - %s\n", dyc->date); return 0; } 

问题是结构的前两个成员只是正确解密。 之后数据会被破坏。 我在这做错了什么?

几乎可以说这是OpenSSL的一个问题。 似乎传递给AES_cbc_encryptlength参数是> AES_BLOCK_SIZE而不是其整数倍(即length mod AES_BLOCK_SIZE != 0 ),那么最后一个块使用初始 IV而不是前一个密文块加密,应该是CBC模式的案例。

您可以通过以下两种方式之一解决此问题:

将结构复制到大小为AES_BLOCK_SIZE的整数倍的AES_BLOCK_SIZE ,或者分为两部分加密 – 完整块,后跟单个部分块。 后者具有避免额外内存使用的优点,可以按如下方式完成:

 size_t fullBlocks = inputslength - (inputslength % AES_BLOCK_SIZE); size_t remainingBlock = inputslength - fullBlocks; AES_cbc_encrypt((unsigned char *)&ticket, enc_out, fullBlocks, &enc_key, iv_enc, AES_ENCRYPT); AES_cbc_encrypt((unsigned char *)&ticket + fullBlocks, enc_out + fullBlocks, remainingBlock, &enc_key, iv_enc, AES_ENCRYPT); 

然后,您应该可以解密,因为您目前没有问题。 但值得注意的是,您应该将dec_out声明为与dec_out相同的大小,因为您在解密时当前正在超越dec_out缓冲区。

编辑:

我把它作为OpenSSL中的一个错误提出来: https : //rt.openssl.org/Ticket/Display.html? id = 3182 & user = think & pass = guest虽然有一些争论,这是否实际上是一个错误,或者只是(没有记录) )未定义的行为,一般的共识是应该使用EVP例程而不是这些低级函数。

问题可能出在您正在使用的结构中,主要是因为struct padding和成员大小。 尝试序列化您的输入,它必须工作。 以一种简单的方式,尝试分配一个char缓冲区并逐个将结构内容复制到缓冲区并尝试加密该缓冲区,同时解密也遵循相同的方法。 在此之后发布您正在观察的内容。 我们必须能够更好地评论这一点。

原始代码为您完成了填充。 问题是您将错误的明文长度传递给AES函数。 您应该将encslength (填充长度)传递给AES_cbc_encrypt 。 只需改变这一行

 AES_cbc_encrypt((unsigned char *)&ticket, enc_out, inputslength, &enc_key, iv_enc, AES_ENCRYPT); 

 AES_cbc_encrypt((unsigned char *)&ticket, enc_out, encslength, &enc_key, iv_enc, AES_ENCRYPT); 

这应该可以解决您的问题。

至少我也认为在这里使用structsizeof(a_struct_type)不是一个好习惯。

struct USR_TICKET的实际二进制序列和sizeof的结果将根据不同的填充和字节对齐实现而变化。

这是测试结果。

1)首先,我下载最新的openssl1.0.2c并构建它,并在OS X 10.10.3上使用此库测试代码,代码工作正常。

2)我试着进行了5次测试。 每次,即使original纯文本也会因struct填充而改变(在我的操作系统上,每次都会更改最后4个字节)。

3)因此,结构的相同输入产生了不同的plain text ,最终产生了不同的密文。 当用户尝试使用相同的密钥和iv加密相同的输入信息(此处为raving, 1, 2015-6-25 )时,用户可能会对不同的密文输出感到困惑。

4)此外,只需更改struct内部定义,这将在描述(3)中产生相同的关注。

 typedef struct ticket { /* test field */ int ticketId; char username[19]; // here try to change from 20 to 19 char date[20]; // here try to change from 20 to other size } USR_TICKET; 

PS。 一些输出来自上面的描述(2),

输出1:

 Give a key length [only 128 or 192 or 256!]: 128 Username - ravinda Ticket Id - 1 Date - 2015-06-25 original: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 BB 3A 50 encrypt: BA 32 86 CC 71 55 2F 73 ED A1 C9 DE 00 32 1A 20 D9 A5 16 52 8A CD F0 F7 38 04 76 38 5A 47 35 3B A3 07 97 41 C4 C2 05 53 74 93 91 26 7E DE 40 47 decrypt: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 BB 3A 50 Username - ravinda Ticket Id - 1 Date - 2015-06-25 

输出2:

 Give a key length [only 128 or 192 or 256!]: 128 Username - ravinda Ticket Id - 1 Date - 2015-06-25 original: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 0B 10 5A encrypt: BE 60 0F FC 17 A3 42 4A 95 7C 39 DB BF 2C BA 59 42 DC 0C AD B2 20 76 6A 04 E3 DE 11 3E D0 AF 88 A5 B9 D2 25 D4 AE F0 B7 82 9F 13 39 80 39 61 9D decrypt: 01 00 00 00 72 61 76 69 6E 64 61 00 00 00 00 00 00 00 00 00 00 00 00 00 32 30 31 35 2D 30 36 2D 32 35 00 00 00 00 00 00 58 0B 10 5A Username - ravinda Ticket Id - 1 Date - 2015-06-25