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)
当前的 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 代码的结果是相同的。