[英]OpenSSL inconsistency in C++ and PHP
我正在尝试编写一段代码来加密/解密将存储在数据库中的数据(例如密码)。 目标是数据可以在 C++、PHP 和 Java 中使用。 问题是我没有在 C++ 和 PHP 中获得相同的加密数据(我没有处理 Java jet)。 C++代码:
void CSSLtestDlg::TryIt()
{
CString msg, tmp;
/* A 256 bit key */
unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"01234567890123456";
/* Message to be encrypted */
unsigned char *plaintext = (unsigned char *)"Some_plain_text";
msg = "Original text is: Some_plain_text";
/* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, dependant on the
* algorithm and mode
*/
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
int decryptedtext_len, ciphertext_len;
/* Initialise the library */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
/* Encrypt the plaintext */
ciphertext_len = encryptIt (plaintext, strlen ((char *)plaintext),
key, iv, ciphertext);
ciphertext[ciphertext_len] = '\0';
tmp.Format("\nEncrypted text (in HEX) is: %s", StrToHex(ciphertext));
msg += tmp;
/* Decrypt the ciphertext */
decryptedtext_len = decryptIt(ciphertext, ciphertext_len,
key, iv, decryptedtext);
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
tmp.Format("\nDecrypted text is: %s", decryptedtext);
msg += tmp;
AfxMessageBox(msg);
/* Clean up */
EVP_cleanup();
ERR_free_strings();
}
int CSSLtestDlg::encryptIt(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. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, 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;
}
int CSSLtestDlg::decryptIt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *key, unsigned char *iv, unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the decryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
/* Finalise the decryption. Further plaintext bytes may be written at
* this stage.
*/
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
plaintext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
结果:
Original text is: Some_plain_text
Encrypted text (in HEX) is: 39D35A2E6EF8F8E36F3BC1FD8B6B32
Decrypted text is: Some_plain_text
PHP代码:
$key = "01234567890123456789012345678901";
$iv = "01234567890123456";
$msg = "Some_plain_text";
if(function_exists('openssl_encrypt'))
{
echo("Original text is:" . $msg . "<br>");
$encrypted_msg = openssl_encrypt($msg, "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv);
if ($encrypted_msg == FALSE)
$log->logDebug("openssl_encrypt error!");
else
{
echo("Encrypted text (in HEX) is:" . strToHex($encrypted_msg) . "<br>");
$decrypted_msg = openssl_decrypt($encrypted_msg, "aes-256-cbc", $key, OPENSSL_RAW_DATA , $iv);
echo("Decrypted text is:" . $decrypted_msg . "<br>");
}
}
else echo("openssl_encrypt doesn't exists!<br>");
function strToHex($string)
{
$hex = '';
for ($i=0; $i<strlen($string); $i++)
{
$ord = ord($string[$i]);
$hexCode = dechex($ord);
$hex .= substr('0'.$hexCode, -2);
}
return strToUpper($hex);
}
结果:
Original text is:Some_plain_text
Encrypted text (in HEX) is:39D35A2E6EF8F8E36F3BC1FD8B06B302
Decrypted text is:Some_plain_text
所以我得到 39D35A2E6EF8F8E36F3BC1FD8B6 B32 (C++) 与 39D35A2E6EF8F8E36F3BC1FD8B06 B302 (PHP) 相对。 最后,HEX 数据将存储在 DB 中并稍后检索。 预先感谢所有的帮助,并为我的语言不好而道歉。
所以问题出在 StrToHex() 函数中的 C++ 代码中(我忘记在原始问题中发布)所以这里是:
CString StrToHex(unsigned char* str)
{
CString tmp;
CString csHexString;
int nCount = strlen((char *)str);
for( int nIdx =0; nIdx < nCount; nIdx++ )
{
int n = str[nIdx];
//tmp.Format( _T("%X"), n ); --> this is wrong
tmp.Format( _T("%02X"), n ); // --> this is OK
csHexString += tmp;
}
return csHexString;
}
第二个输出中还有另一个额外的 0 (B6/B06)。 这些可能是输出中唯一的低字节,并且您有不同的格式设置。
如果你展示你的 C++ StrToHex,它可能是一个简单的格式字符串修复,比如 %x 到 %0x。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.