OpenSSL AES_CBC-256解密字符串并不总是正确的

时间:2014-03-06 19:06:19

标签: c++ qt encryption openssl aes

我遇到OpenSSL AES CBC-256的问题,导致几乎15%的消息未正确解码。该程序使用QT,这就是我使用QT类型的原因。有没有办法解决这个问题,或者我应该放弃使用AES进行加密。

void fillIV(unsigned char* IN) //Function to fill initialization vector with alphanumerics (for now,in future replaced by RAND())
{
QString charset="ABCDEFGIJKLMNOPQRSTOWXYZabcdefghijklmnopqrstuwxyz0123456789";
for(int i=0;i<AES_BLOCK_SIZE;i++)
{
    IN[i]=charset[qrand()%charset.length()].toAscii(); //Random QChar from QString 
}
}

bool qorgIO::TEST(QString Password,MainWindow *main)    
 {
    //ENCRYPT SECTION-------------------------------------------------------------------
    QString OUT="HEADERHEADERHEA";
    {
        QString data="<ORG><CALENDAR></CALENDAR></ORG>";
        if(data.length()%AES_BLOCK_SIZE==0)
        {
            data+=".";
        }
        //To prevent the length of data being multiplicity of 16(AES_BLOCK_SIZE)
        //It cause a bunch of trash following the decrypted text

        if(Password.length()< 32)
        {
            Password.append(QString(32-Password.length(),'\0'));
        }
        //Password is padded to 32 chars == 256 bits

        AES_KEY *aesKey = new AES_KEY;
        AES_set_encrypt_key((unsigned char*)Password.toAscii().data(), 256, aesKey);
        //Setting AES-KEY Password.toAscii().data() is a char*

        const size_t encslength = ((data.length() + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
        //Size of output: better have 16 bytes free then 16 bytes too little

        unsigned char IV[AES_BLOCK_SIZE+1];               //16 bytes of IV and \0
        fillIV(IV);                                       //Create alphanumeric IV
        //RAND_bytes(IV, AES_BLOCK_SIZE);                 //Random IV
        OUT.append(QByteArray((const char*)IV).toBase64());     
        //Add to output data base64 representation of IV(in future IV will be random chars)
        //IV during enryption change

        unsigned char* aOUT;                                    
        aOUT=new unsigned char[encslength];             //Create the output space
        memset(aOUT, 0, sizeof(encslength));            //Clear the output space

        AES_cbc_encrypt((unsigned char*)data.toAscii().data(),aOUT,data.length(),aesKey,IV,AES_ENCRYPT); 
        //Encrypt the data
        //AES_cbc_encrypt(unsigned char* data,unsigned char* output, AESKEY,unsigned char* IV, MODE) 

        OUT+="\n";
        OUT.append(QByteArray((const char*)aOUT).toBase64()); 
        //Add base64 representation of encoded data

    }
    //END OF ENCRYPT SECTION------------------------------------------------------------

    //Output:
    //HEADERHEADERHEA(base64 IV)\n(base64 data)(dot because data is 16*k charactes long)
    //In this given example: HEADERHEADERHEA(base64 IV)\n(base64 data).

    //DECRYPT SECTION-------------------------------------------------------------------
    QString text=OUT;
    QString Header=text.mid(0,15);                     //Get "HEADERHEADERHEA" 
    QString IV=text.mid(15,text.indexOf("\n")-15);     //Get IV(base64)
    QString Data=text.mid(text.indexOf("\n")+1,text.length()-text.indexOf("\n")-1);
    //Get encrypted data(base64)

    QByteArray IVBA=QByteArray::fromBase64(IV.toAscii());            //Decode base64
    QByteArray DataBA=QByteArray::fromBase64(Data.toAscii()).data(); //Decode base64

    if(Password.length()< 32)
    {
        Password.append(QString(32-Password.length(),'\0'));
    }
    //Password padding

    AES_KEY *aesKey = new AES_KEY;
    AES_set_decrypt_key((unsigned char*)Password.toAscii().data(), 256, aesKey);
    //Set decryption key

    int sizeofinput=DataBA.size();
    //Size of output is <= size of input data

    unsigned char *Output;
    Output=new unsigned char[sizeofinput];              //Create the output array
    memset(Output, 0 , sizeof(sizeofinput));            //Clear the output space

    AES_cbc_encrypt((unsigned char*)DataBA.data(),Output,sizeofinput,aesKey,(unsigned char*)IVBA.data(),AES_DECRYPT);
    //Decryption 
    //AES_cbc_encrypt(unsigned char* data,unsigned char* output, AESKEY,unsigned char* IV, MODE)

    QString Decrypted=Header;                          //Header was plain text
    Decrypted.append((const char*)Output);             //Add output to the text

    //END OF DECRYPT SECTION------------------------------------------------------------

    if(Decrypted!="HEADERHEADERHEA<ORG><CALENDAR></CALENDAR></ORG>.")
    {              
        qDebug()<<Decrypted;    //Show the decrypted string
        //up == "cout<<Decrypted.toStdString()";
        return false;
    }
    else
    {
        return true;
    }
}

解码后的字符串并不总是我想要接收的数据(10000次试验中15%的错误字符串)。这是AES算法的问题(不能容忍密码中的'\ 0')或者在创建代码时我是错误的吗?

对于任何语言错误,我很抱歉。

1 个答案:

答案 0 :(得分:0)

问题是输出中的空字符。构造函数QByteArray(const char *)将数据收集到第一个\ 0。解决方案是使用构造函数QByteArray(const char *,int),它允许将所有数据从输出char流到QByteArray。

AES_cbc_encrypt((unsigned char*)data.toAscii().data(),aOUT,data.length(),aesKey,IV,AES_ENCRYPT); 
    //Encrypt the data
    //AES_cbc_encrypt(unsigned char* data,unsigned char* output, AESKEY,unsigned char* IV, MODE) 

    OUT+="\n";
    //!!OUT.append(QByteArray((const char*)aOUT).toBase64()); 
    //Here we change line to:
    OUT.append(QByteArray((const char*)aOUT,encslength).toBase64());