2016-02-09 29 views
1

我有一段時間在SUSE Linux Enterprise Server下工作正常。最近,它轉移到了OpenSUSE 13.2系統,遇到了一個問題。程序連接到第三方,數據被接收到我們的程序中,其中數據塊由一些標題信息和AES加密數據組成。使用OpenSSL libcrypto庫,我們成功地在SLES下與此係統連接。但是,在OpenSUSE下,我們始終會看到解密數據的末尾包含垃圾的錯誤。我已經確定了問題發生的位置,並且有一個解決方法,但是在查看代碼時,我不明白爲什麼會有問題。使用OpenSUSE 13.2上的memcpy進行解密時的垃圾字符

我已經創建了一個模擬問題的測試程序。該測試程序在SUSE Linux Enterprise Server 11和Red Hat 7.2企業版Linux下正常工作,但在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, "123456789"); 

    // 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,最終輸出看起來像:

0046this是一個測試這是一個測試這是一個測試這是一個測試
0047this被一個測試這是一個測試這是一個測試這是一個測試
0048這是一個測試這是一個測試這是一個測試這是一個測試
0049這是一個測試這是一個測試這是一個測試這是一個測試
0050這是一個測試這是一個測試這是一個測試這是一個測試

在openSUSE,最終輸出可以是這樣的:

0046this是一個測試這是一個測試這是一個測試這是一個測試
0047this是測試這是一個測試,這是一個測試這是一個測試
0048這是一個測試這是一個測試這是一個測試這是一個測試這是一個測試這是一個測試這是一個測試這是一個測試這是一個測試這是一個testest_s ⌡n}⌐*╘¿μ2└╠LS4=Qüü├;〜╕< ^DD0┤T.OQΣq#≈
個 0050this是一個測試這是一個測試這是一個測試這是一個測試

有什麼想法?

由於

+0

填充搞砸了嗎? – Asaph

回答

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

重疊緩衝液和memcpy是在++ C/C未定義的行爲。改爲使用memmove。這聽起來像你有一個可以向前或向後memcpy的glibc版本。在你的情況下,你正在通過HAS_FAST_COPY_BACKWARD的處理器上執行。

下面是該問題的經典錯誤報告:Strange sound on mp3 flash website。但是Adobe的任何內容都不會讓你感到驚訝他們以這個星球上最不安全的軟件而聞名的原因是有原因的。另外,如果你在Valgrind下運行你的二進制文件,這個工具有時會用這個問題標記代碼。我記得看到Valgrind標記它爲Crypto++ library

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; 
} 
0

回答經由另一個源提供:

應該使用的memmove(),而不是的memcpy()由於存儲器重疊。