使用 OpenSSL C++ 库和 PHP 的 Blowfish 加密数据不一致

fbo*_*s22 5 php c++ encryption openssl

我正在尝试开发一个 C++ 程序,对一些数据进行加密,以便稍后使用基于 PHP 的 Web 服务进行解密。但是,我在使用 PHP 中的 openssl_decrypt() 方法使用 Blow-fish CBC 方法解密数据时遇到问题。

我正在测试此代码 C++ 代码来加密消息并转换为 base64 格式以使用我的 PHP 程序进行解密。这是 C++ 程序的代码。

#include <secureinfra.hpp>
#include <iostream>

int main()
{
    cout << "Unit Test for the crypto system" << endl;
    SecureInfrastructure mySec;

    /* A 256 bit key and IV */
    auto *key = (unsigned char *)"ZdOAq0yn6H1i35TywbLrtqBO4NCjh7Vh";
    auto *iv = (unsigned char *)"01234567";

    /* Message to be encrypted */
    auto *plaintext = (unsigned char *)"The quick brown fox jumps over the lazy dog";

    /* Buffer for ciphertext. Ensure the buffer is long enough for the ciphertext which may be longer than the
     * plaintext, depending on the algorithm and mode. */
    unsigned char ciphertext[128];

    /* Buffer for the decrypted text */
    unsigned char decryptedtext[128];
    int decryptedtext_len, ciphertext_len;

    /* Encrypt the plaintext */
    ciphertext_len = mySec.EncryptMessage(plaintext, strlen((char *) plaintext), key, iv, ciphertext);

    /* Decrypt the ciphertext */
    decryptedtext_len = mySec.DecryptMessage(ciphertext, ciphertext_len, key, iv, decryptedtext);

    /* Add a NULL terminator. We are expecting printable text */
    decryptedtext[decryptedtext_len] = '\0';

    /* Show the encrypted and decrypted text in base64 format */
    string encryptedText = mySec.base64_encode(string(reinterpret_cast<char*>(ciphertext)));
    cout << "Encrypted text (base64) is:\n" << encryptedText << endl;
    cout << "Decrypted text (base64) is:\n" << mySec.base64_encode(string(reinterpret_cast<char*>(decryptedtext))) << endl;

    /* Show the decoded decrypted text */
    cout << "Decoded Decrypted text is:" << endl;
    cout << decryptedtext << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的仅用于解密的 PHP 测试代码如下所示:

<?php
$ciphertext = "ljRvLcfBiDwxRSm1lDXMwDk5S4pRCg9D2F9jxR5C5yy79xoBHQNKjA/FaQ2dNfKvyO0uilZ/";
$key = "ZdOAq0yn6H1i35TywbLrtqBO4NCjh7Vh";
$cipher = "bf-cbc";

if (in_array($cipher, openssl_get_cipher_methods()))
{
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = "01234567";
    // print some parameters
    echo "IV size: ".strlen($iv)."\n";
    echo "Key Used: ".$key."\n";
    echo "Enc Message: ".$ciphertext."\n";
    // Now try to decrypt message...
    $original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv);
    echo "Dec Message: ".$original_plaintext."\n";
}
else
{
    echo "The ".$cipher." is not present in the system...";
}
?>
Run Code Online (Sandbox Code Playgroud)

但是,PHP 程序无法解密由我的 C++ 程序生成的 $ciphertext。当我尝试回显 $original_plaintext 时,它没有显示任何内容。

另外,我注意到 PHP 和 C++ 使用 SSL 加密是不同的。例如,当我尝试使用 PHP(使用 openssl_encrypt 方法)和 C++,使用相同的密钥和 IV 加密短语“The Quick Brown Fox Jumps Over the Lazy Dog”时,加密的 Base64 字符串如下:

在 C++ 中:
ljRvLcfBiDwxRSm1lDXMwDk5S4pRCg9D2F9jxR5C5yy79xoBHQNKjA/FaQ2dNfKvyH3brAV/

在 PHP 中:
hWj7F1fnBXhIWv4sonjhSmJgHWJALFecxxrGe0T1kLrN4TfSMUw/uELj6h5+Laph

我应该如何解决这个问题?我看到一篇类似的文章描述我需要在 C++ 程序上设置密钥大小,但我不确定如何正确执行此操作。

编辑:这是用 C++ 加密消息的方法

int SecureInfrastructure::EncryptMessage(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext)
{
    EVP_CIPHER_CTX *ctx;
    int len, ciphertext_len;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new())) {
        handleErrors();
    }

    /* Initialise the encryption operation. IMPORTANT - ensure you use a key and IV size appropriate for your cipher. */
    if(1 != EVP_EncryptInit_ex(ctx, EVP_bf_cbc(), nullptr, key, iv)) {
        handleErrors();
    }

    /* Provide the message to be encrypted, and obtain the encrypted output. EVP_EncryptUpdate can be called multiple
     * times if necessary */
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) {
        handleErrors();
    }
    ciphertext_len = len;

    /* Finalise the encryption. Further ciphertext bytes may be written at this stage. */
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
        handleErrors();
    }
    ciphertext_len += len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);
    return ciphertext_len;
}
Run Code Online (Sandbox Code Playgroud)

EDIT2:现在这是我的新 EncryptMessages 以及您的建议:

int SecureInfrastructure::Encrypt_BF_CBC(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext)
{
    EVP_CIPHER_CTX *ctx;
    int len;
    int ciphertext_len;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new())) {
        handleErrors();
    }

    /* Initialise the encryption operation with fixed key size */

    EVP_EncryptInit_ex(ctx, EVP_bf_cbc(), NULL, NULL, NULL);
    EVP_CIPHER_CTX_set_key_length(ctx, 32);
    EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);

    /* Provide the message to be encrypted, and obtain the encrypted output. */
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
        handleErrors();
    ciphertext_len = len;

    /* Finalise the encryption. */
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
        handleErrors();
    ciphertext_len += len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}
Run Code Online (Sandbox Code Playgroud)

Base64编码使用的方法:

std::string base64_encode(const std::string& in) { 
    string out; 
    int val = 0, valb = -6; 
    for (unsigned char c : in) { 
        val = (val << 8) + c; 
        valb += 8; 
        while (valb >= 0) { 
            out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]); 
            valb -= 6; 
        } 
    } 
    if (valb > -6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]); 
    while (out.size() % 4) out.push_back('='); 
    return out; 
}
Run Code Online (Sandbox Code Playgroud)

Top*_*aco 2

当前的 C 实现假定密码具有固定的密钥长度,这不适用于Blowfish。对于具有可变密钥长度的密码,该长度被设置为特定值,例如 32 字节,

EVP_EncryptInit_ex(ctx, EVP_bf_cbc(), NULL , key, iv);
Run Code Online (Sandbox Code Playgroud)

必须替换为

EVP_EncryptInit_ex(ctx, EVP_bf_cbc(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(ctx, 32);
EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
Run Code Online (Sandbox Code Playgroud)

EncryptMessage,例如这里。解密也类似。那么 C 代码和 PHP 代码的结果是相同的。