我有一个在suse linux企业服务器下运行了一段时间的程序。最近,它被移到了opensuse 13.2系统中,遇到了一个问题。程序与第三方接口,数据被接收到我们的程序中,其中的数据块由一些头信息和aes加密数据组成。使用openssl libcrypto库,我们在sles下成功地与这个系统连接。但是,在opensuse下,我们始终看到一个错误,即解密数据的结尾包含垃圾。我已经确定了问题发生的位置,并且已经找到了解决方法,但是在查看代码时,我不明白为什么会出现问题。
我已经创建了一个模拟问题的测试程序。该测试程序在suse linux企业服务器11和red hat 7.2enterpriselinux上运行良好,但在opensuse 13.2上使用不同版本的openssl库失败。在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这是一个测试这是一个测试
|τzk½_p≥ii w p 8 t g{y e_
n}*2_ ls4=qü_;~<^ d0 t.oq∑q≈
0050这是测试这是测试这是测试这是测试
有什么想法吗?
谢谢

最佳答案

// Generates Garbage
memcpy(encbuf, encbuf+100, enclen);

重叠缓冲区和cc是C/C++中未定义的行为。改为使用memcpy。听起来你有一个glibc版本,它可以向前或向后记忆。在您的例子中,您是在通过memmove的处理器上执行的。
这里有一个关于这个问题的典型错误报告:Strange sound on mp3 flash website。但adobe不会让你吃惊的。有一个原因是他们是地球上最不安全的软件。
此外,如果在valgrind下运行二进制文件,该工具有时会标记有问题的代码。我记得我看到过瓦尔格林为“AA”做的标记:
size_t ArraySink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
{
    // Avoid passing NULL pointer to memcpy. Using memmove due to
    //  Valgrind finding on overlapping buffers.
    size_t copied = 0;
    if (m_buf && begin)
    {
        copied = STDMIN(length, SaturatingSubtract(m_size, m_total));
        memmove(m_buf+m_total, begin, copied);
    }
    m_total += copied;
    return length - copied;
}

关于c - 在OpenSUSE 13.2上使用memcpy解密期间的垃圾字符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35301736/

10-13 07:37