【问题标题】:QT OpenSSL C++ and PHP AES/CBCQT OpenSSL C++ 和 PHP AES/CBC
【发布时间】:2018-11-11 22:18:00
【问题描述】:

我必须在 C++ 库和 php 之间进行统一的数据加密。这真的是我对 AES 的第一次冒险。我一直在阅读我能阅读的内容,并试图弄清楚。我想出了下面的代码。我似乎无法获得匹配的输出。几天来,我一直试图弄清楚这一点。

我注意到 php 和 CPP 版本的输出非常接近。 从 CPP 函数我们得到ta4SK7e1ziUMnBchxqol/TT82wNS8TmJQ/kFls+I04HuK4nP7kDT4J2zYJDB6WIx,从 php 我们得到ta4SK7e1ziUMnBchxqol/TT82wNS8TmJQ/kFls+I04H6XsCH1kfyiS/gu2oi57yY。如果你看,他们真的很近。只有最后几个字节不同。

所以我知道我很接近了,但我真的看不出我做错了什么。

这里是 C++ 代码:

QByteArray encryptAES(QByteArray passphrase, QByteArray plainText, QByteArray myiv)
{
    unsigned char* Key = (unsigned char*) passphrase.data();
    unsigned char* IV = (unsigned char*) myiv.data();

    /** Setup the AES Key structure required for use in the OpenSSL APIs **/
    AES_KEY* AesKey = new AES_KEY();
    AES_set_encrypt_key(Key, 256, AesKey);

    /** take an input string and pad it so it fits into 16 bytes (AES Block Size) **/
    const int UserDataSize = (const int)plainText.size();   // Get the length pre-padding
    int RequiredPadding = (AES_BLOCK_SIZE - (UserDataSize % AES_BLOCK_SIZE));   // Calculate required padding
    for(int i=0; i < RequiredPadding; i++) {
        plainText.push_back('\0');
    }

    unsigned char * UserData = (unsigned char*) plainText.data(); // Get the padded text as an unsigned char array
    const int UserDataSizePadded = (const int)plainText.size();// and the length (OpenSSl is a C-API)

    /** Peform the encryption **/
    unsigned char EncryptedData[UserDataSizePadded] = {0}; // Hard-coded Array for OpenSSL (C++ can't dynamic arrays)
    AES_cbc_encrypt(UserData, EncryptedData, UserDataSizePadded, (const AES_KEY*)AesKey, IV, AES_ENCRYPT);

    QByteArray encrypted = QByteArray(reinterpret_cast<char*>(EncryptedData), UserDataSizePadded);

    return encrypted;
}

QByteArray decryptAES(QByteArray passphrase, QByteArray encryptedText, QByteArray myiv)
{
    unsigned char* Key = (unsigned char*) passphrase.data();
    unsigned char* IV = (unsigned char*) myiv.data();
\
    /** Setup an AES Key structure for the decrypt operation **/
    AES_KEY* AesDecryptKey = new AES_KEY(); // AES Key to be used for Decryption
    AES_set_decrypt_key(Key, 256, AesDecryptKey);   // We Initialize this so we can use the OpenSSL Encryption API

    /** Decrypt the data. Note that we use the same function call. Only change is the last parameter **/
    unsigned char DecryptedData[encryptedText.size()] = {0}; // Hard-coded as C++ doesn't allow for dynamic arrays and OpenSSL requires an array
    AES_cbc_encrypt((unsigned char*) encryptedText.data(), DecryptedData, encryptedText.size(), (const AES_KEY*)AesDecryptKey, IV, AES_DECRYPT);

    QByteArray decrypted = QByteArray(reinterpret_cast<char*>(DecryptedData), encryptedText.size());

    return decrypted;
}

int main(int argc, char *argv[])
{
    QByteArray plainText("This string was AES-256-CBC encrypted.");
    QByteArray phpEnc = QByteArray("ta4SK7e1ziUMnBchxqol/TT82wNS8TmJQ/kFls+I04H6XsCH1kfyiS/gu2oi57yY");
    QByteArray key = QByteArray::fromBase64("pE4B5J5u18U55BTJho//Fioy2bEURa5W/o7HrO1O7/s=");
    QByteArray iv = QByteArray::fromBase64("Gi9kSb/a5f0h7Mb+sRWQdQ==");
    qDebug() << "AES Test KEY: " << key.toBase64();
    qDebug() << "AES Test IV: " << iv.toBase64();
    QByteArray enc = encryptAES(key,plainText, iv);
    qDebug() << "AES Test Encrypt: " << enc.toBase64();
    qDebug() << "AES Test Decrypt: " << decryptAES(key, enc, iv);
    qDebug() << "AES Test Decrypt PHP: " << decryptAES(key, phpEnc, iv);
}

现在是php代码:

<?php
$method = 'AES-256-CBC';
$txt = "This string was AES-256-CBC encrypted.";
$iv = base64_decode("Gi9kSb/a5f0h7Mb+sRWQdQ==");
$key = base64_decode("pE4B5J5u18U55BTJho//Fioy2bEURa5W/o7HrO1O7/s=");
echo "AES Test KEY: ". base64_encode($iv)."\n\n<br>";
echo "AES Test IV: ". base64_encode($key)."\n\n<br>"."\n\n<br>";

$fromCPP = "ta4SK7e1ziUMnBchxqol/TT82wNS8TmJQ/kFls+I04HuK4nP7kDT4J2zYJDB6WIx";

$enc = openssl_encrypt($txt, $method, $key, OPENSSL_RAW_DATA, $iv);
$dec = openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv);

//Test if php isn't padding
$UserDataSize = strlen($txt);
$RequiredPadding == (16 - ($UserDataSize % 16));
$paddedText = $txt;
for($i=0; $i < $RequiredPadding; $i++)
    $paddedText .= "\0";

$enc2 = openssl_encrypt($paddedText, $method, $key, OPENSSL_RAW_DATA, $iv);
$dec2 = openssl_decrypt($enc2, $method, $key, OPENSSL_RAW_DATA, $iv);

//Try to decrypt CPP 
$dec3 = openssl_decrypt(base64_decode($fromCPP), $method, $key, OPENSSL_RAW_DATA, $iv);

echo "AES Test Encrypt: ". base64_encode($enc)."\n\n<br>";
echo "AES Test Decrypt: ". $dec."\n\n<br>";
echo "AES Test Encrypt Padded: ". base64_encode($enc2)."\n\n<br>";
echo "AES Test Decrypt Padded: ". $dec2."\n\n<br>";
echo "AES Test Decrypt CPP: ". $dec3."\n\n<br>";

?>

【问题讨论】:

    标签: php qt c++11 openssl


    【解决方案1】:

    这是填充的区别:

    $txt = "This string was AES-256-CBC encrypted.";
    $key = base64_decode("pE4B5J5u18U55BTJho//Fioy2bEURa5W/o7HrO1O7/s=");
    $iv  = base64_decode("Gi9kSb/a5f0h7Mb+sRWQdQ==");
    $cpp = base64_decode('ta4SK7e1ziUMnBchxqol/TT82wNS8TmJQ/kFls+I04HuK4nP7kDT4J2zYJDB6WIx');
    $php = base64_decode('ta4SK7e1ziUMnBchxqol/TT82wNS8TmJQ/kFls+I04H6XsCH1kfyiS/gu2oi57yY');
    
    var_dump(
        $txt,
        bin2hex($iv),
        bin2hex($cpp),
        bin2hex($php),
        openssl_decrypt($cpp, 'AES-256-CBC', $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv),
        openssl_decrypt($php, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv),
        base64_encode(openssl_encrypt(str_pad($txt, 48, "\0"), 'AES-256-CBC', $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING
    , $iv)),
    );
    

    输出:

    string(38) "This string was AES-256-CBC encrypted."
    string(32) "1a2f6449bfdae5fd21ecc6feb1159075"
    string(96) "b5ae122bb7b5ce250c9c1721c6aa25fd34fcdb0352f1398943f90596cf88d381ee2b89cfee40d3e09db36090c1e96231"
    string(96) "b5ae122bb7b5ce250c9c1721c6aa25fd34fcdb0352f1398943f90596cf88d381fa5ec087d647f2892fe0bb6a22e7bc98"
    string(48) "This string was AES-256-CBC encrypted." // Note the length.
    string(38) "This string was AES-256-CBC encrypted."
    string(64) "ta4SK7e1ziUMnBchxqol/TT82wNS8TmJQ/kFls+I04HuK4nP7kDT4J2zYJDB6WIx"
    

    您可以看到加密数据在最后一个块之前是相同的,这是第一个提示。在添加 OPENSSL_ZERO_PADDING 选项之前解码 CPP 版本的麻烦是第二个。并且使用适当的填充和选项重新编码并获得数据的完全匹配是最终的证明。

    【讨论】:

      【解决方案2】:

      有一个包含 PHP 和 C++ 实现的库,使用 AES-256-CBC 算法进行统一加密。

      https://github.com/mervick/aes-everywhere

      【讨论】:

        猜你喜欢
        • 2019-04-14
        • 2013-08-11
        • 2022-08-17
        • 1970-01-01
        • 2017-08-28
        • 2017-12-10
        • 2022-06-10
        • 2019-08-17
        • 2020-04-15
        相关资源
        最近更新 更多