我有一个程序在 SUSE Linux Enterprise Server 下运行了一段时间。最近,它被转移到了一个 OpenSUSE 13.2 系统上,遇到了一个问题。该程序与第 3 方接口,数据被接收到我们的程序中,其中数据块由一些标头信息和 AES 加密数据组成。使用 OpenSSL libcrypto 库,我们成功地在 SLES 下连接到这个系统。但是,在 OpenSUSE 下,我们始终会看到解密数据末尾包含垃圾的错误。我已经确定了问题发生的位置并解决了问题,但是在查看代码时,我不明白为什么会出现问题。
我创建了一个模拟问题的测试程序。该测试程序在 SUSE Linux Enterprise Server 11 和 Red Hat 7.2 Enterprise Linux 上运行良好,但在使用不同版本级别的 OpenSSL 库的 OpenSUSE 13.2 上失败。在 SLES 和 Red Hat 下,解密后的数据被干净地返回。在 OpenSUSE 下,大部分数据都被干净地解密了,除了一些出现在数据块末尾的垃圾。返回的数据块是正确的,然后包含一些垃圾,然后以正确的方式结束。下面是我的示例程序的代码,但导致问题的行是 memcpy(),我将加密数据移到数据块的前面进行处理。我的示例程序中的行如下:
// Generates Garbage
memcpy(encbuf, encbuf+100, enclen);
如果我在将加密数据移动到 encbuf 的开头之前将其移动到临时缓冲区,则不会生成垃圾。
// This does not generate garbage
memcpy(tmpbuf, encbuf+100, enclen);
memcpy(encbuf, tmpbuf, enclen);
我的示例程序采用已定义的明文缓冲区,使用密钥和 IV 对其进行加密,然后将其解密并显示结果。精简代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <openssl/evp.h>
#define EVP_DECRYPT 0
#define EVP_ENCRYPT 1
char clrbuf[100000];
char encbuf[100000];
char tmpbuf[100000];
int clrlen;
int enclen;
char enckey[1024];
unsigned char enciv[16];
main()
{
int rc;
// Set clear text to 50 lines of text
sprintf(clrbuf,
"0001this is a test this is a test this is a test this is a test\n" \
"0002this is a test this is a test this is a test this is a test\n" \
"0003this is a test this is a test this is a test this is a test\n" \
// etc etc etc……………….
"0048this is a test this is a test this is a test this is a test\n" \
"0049this is a test this is a test this is a test this is a test\n" \
"0050this is a test this is a test this is a test this is a test\n"
sprintf(enckey, "this is the key this is the key ");
sprintf(enciv, "1234567890123456");
// Encrypt the data and simulate a 100 byte header by returning encrypted data 100 bytes into the data block
//
memcpy(encbuf, "Some header stuff that will need to be removed", 46);
rc = evp_aes256_cbc(clrbuf, strlen(clrbuf), encbuf+100, &enclen, enckey, enciv, EVP_ENCRYPT);
// Now remove the header by shifting the encrypted data to the start of the data block and decrypt
// This is where doing the memcpy() as coded in OpenSUSE results in garbage at the end of clrbuf
// but everything is returned correctly in SLES and Red Hat
//
// This work fines on all OSes:
// memcpy(tmpbuf, encbuf+100, enclen);
// memcpy(encbuf, tmpbuf, enclen);
memcpy(encbuf, encbuf+100, enclen);
rc = evp_aes256_cbc(encbuf, enclen, clrbuf, &clrlen, enckey, enciv, EVP_DECRYPT);
printf("Decrypt: rc=%d EncLen=%d ClrLen=%d\n", rc, enclen, clrlen);
printf("Data:\n\n<\n%s\n>\n\n", clrbuf);
}
/****************************************************************************/
evp_aes256_cbc(char *InBuf, int InLen, char *OutBuf, int OutLen, char *Key, char *IV, int EncryptFlag)
{
EVP_CIPHER_CTX ctx;
int padlen;
EVP_CIPHER_CTX_init(&ctx);
if (! EVP_CipherInit_ex(&ctx, EVP_aes_256_cbc(), NULL, Key, IV, EncryptFlag))
return(0);
if (! EVP_CipherUpdate(&ctx, OutBuf, OutLen, InBuf, InLen))
return(0);
if (! EVP_CipherFinal_ex(&ctx, OutBuf+(*OutLen), &padlen))
return(0);
*OutLen = *OutLen + padlen;
EVP_CIPHER_CTX_cleanup(&ctx);
return(1);
}
在 SLES 和 Red Hat 上,最终输出如下所示:
0046这是一个测试这是一个测试这是一个测试这是一个测试
0047这是一个测试这是一个测试这是一个测试这是一个测试0048这是一个测试这是一个测试这是一个测试这是一个测试这是一个 0049
这是一个测试
一个测试 这是一个测试 这是一个测试 这是一个测试
0050这是一个测试 这是一个测试 这是一个测试 这是一个测试 这是一个测试
在 OpenSUSE 上,最终输出可能如下所示:
0046这是一个测试这是一个测试这是一个测试这是一个测试0047这是一个测试这是一个测试这是一个测试这是一个测试0048
这是一个测试这是一个测试
╧┬S_úReÅ▌<br>|τZk╠ ½çP≥ii≡w╙p▓8ª'MêÅt▒g{Y¥ΩEô¬ ⌡n}⌐*╘¿µ2└╠LS4=Qüü├;~╕Ç<╗^¿ßD0┤T.OQΣq#≈<br> 0050这是一个测试这是一个测试这是一个测试这是一个测试
有什么想法吗?
谢谢