如何在 C# 中解密来自 openssl_encrypt 的字符串
How to decrypt string from openssl_encrypt in c#
这是我的 php openssl_encrypt:
$text = "does this work";
$key = "1234567890123456789012345678901234567890123456789012345678901234";
$method = "AES-256-CBC";
$cipher_length = openssl_cipher_iv_length($method); //16
$iv_new = openssl_random_pseudo_bytes($cipher_length);
$bin2hex = bin2hex($iv_new); //"a64d63874ba9ee8f5a5028cb40ab70a4"
$openssl = openssl_encrypt($text, $method, $key, 0, $iv_new);
$encrypted = $bin2hex . $openssl;
$encrypted 的值为:
"a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw==" //encrypted in DecryptPHP
这是我的 php openssl_decrypt:
$iv_strlen = 32;
preg_match("/^(.{" . $iv_strlen . "})(.+)$/", $encrypted, $regs);
list(, $_iv, $_crypted_string) = $regs;
$_hex2bin = hex2bin($_iv);
$ctype_xdigit = ctype_xdigit($_iv);
$remainder = strlen($_iv) % 2 == 0;
$new_text = openssl_decrypt($_crypted_string, $method, $key, 0, $_hex2bin);
$new_text 值为:
"does this work"
所以这工作正常,但我怎样才能得到这个字符串:
"a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw=="
并在 C# 中将其转换为“这行得通吗”?我已经尝试了很多东西并不断提出错误的数据。我什至没有运气地尝试过这个。任何帮助将不胜感激。
Decrypt string in C# that was encrypted with PHP openssl_encrypt
这是我的 C# 代码:
string DecryptPHP()
{
//var _key = System.Text.Encoding.UTF8.GetBytes(key);
//var _iv = System.Text.Encoding.UTF8.GetBytes(iv);
var key = key = "1234567890123456789012345678901234567890123456789012345678901234";
var _key = FromHex(key);
var iv = "a64d63874ba9ee8f5a5028cb40ab70a4";
var _iv = FromHex(iv);
//pad key out to 32 bytes (256bits) if its too short
if (_key.Length < 32)
{
var paddedkey = new byte[32];
Buffer.BlockCopy(_key, 0, paddedkey, 0, key.Length);
_key = paddedkey;
}
//get the encrypted data and decrypt
var data_encrypted_string = "yFFQwLuOHeWouyfp0dyrnw==";
byte[] encryptedBytes = Convert.FromBase64String(data_encrypted_string);
return DecryptStringFromBytesAes(encryptedBytes, _key, _iv);
}
byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
return plaintext;
}
这里有些垃圾我没有清理,请见谅。你有两件事要改变。搜索括号中的文本以查找修复位置。
- (修复 1)我在某处读到 php 方法会截断比应有的长度更长的键。您的密钥是 64 个字符,但应该是 32 个字符。
- (修复 2)PaddingMode 看起来应该是
PKCS7
更新
代码保持不变,但我又添加了一段我忘记删除的代码:
- (修复 3)密钥应该是文本,而不是十六进制。
using System;
using System.Security.Cryptography;
using System.IO;
using System.Linq;
using System.Collections.Generic;
//
//
// https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rijndaelmanaged?view=net-5.0
public class Program
{
// full key 1234567890123456789012345678901234567890123456789012345678901234
// Fix 1: php truncates a key longer than what is supported, so I chopped this off to 32
private static string key = "12345678901234567890123456789012";
private static string originalText = "does this work";
private static string encryptedValue = "a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw==";
public static void Main()
{
// Console.WriteLine(OpenSslDecrypt(encryptedValue, key));
Console.WriteLine("decrypted text: " + DecryptPHP(encryptedValue));
}
public static byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
public static string DecryptPHP(string encrypted)
{
var hexSalt = encryptedValue.Substring(0, 32);
byte[] stringSalt = FromHex(hexSalt);
var saltBytes = FromHex(hexSalt);
Console.WriteLine("salt length bytes: " + saltBytes.Length);
var unsaltedEncryptedValue = encryptedValue.Substring(32);
Console.WriteLine("salt: " + hexSalt);
Console.WriteLine("unsaltedEncryptedValue: " + unsaltedEncryptedValue);
//get the encrypted data and decrypt
byte[] unsaltedEncryptedBytes = Convert.FromBase64String(unsaltedEncryptedValue);
// byte[] unsaltedEncryptedBytes = System.Text.ASCIIEncoding.UTF8.GetBytes(unsaltedEncryptedValue);
// Fix 3: key should be text, not hex.
// var _key = FromHex(key);
byte[] keyBytes = System.Text.ASCIIEncoding.UTF8.GetBytes(key);
return DecryptStringFromBytesAes(unsaltedEncryptedBytes, keyBytes, saltBytes);
}
public static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create a RijndaelManaged object
// with the specified key and IV.
// Fix 2: PaddingMode should be PKCS7, based on my tests. It gets rid of the extra ? chars.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
return plaintext;
}
}
dotnetfiddle link: https://dotnetfiddle.net/s2tfmM
这是我的 php openssl_encrypt:
$text = "does this work";
$key = "1234567890123456789012345678901234567890123456789012345678901234";
$method = "AES-256-CBC";
$cipher_length = openssl_cipher_iv_length($method); //16
$iv_new = openssl_random_pseudo_bytes($cipher_length);
$bin2hex = bin2hex($iv_new); //"a64d63874ba9ee8f5a5028cb40ab70a4"
$openssl = openssl_encrypt($text, $method, $key, 0, $iv_new);
$encrypted = $bin2hex . $openssl;
$encrypted 的值为:
"a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw==" //encrypted in DecryptPHP
这是我的 php openssl_decrypt:
$iv_strlen = 32;
preg_match("/^(.{" . $iv_strlen . "})(.+)$/", $encrypted, $regs);
list(, $_iv, $_crypted_string) = $regs;
$_hex2bin = hex2bin($_iv);
$ctype_xdigit = ctype_xdigit($_iv);
$remainder = strlen($_iv) % 2 == 0;
$new_text = openssl_decrypt($_crypted_string, $method, $key, 0, $_hex2bin);
$new_text 值为:
"does this work"
所以这工作正常,但我怎样才能得到这个字符串:
"a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw=="
并在 C# 中将其转换为“这行得通吗”?我已经尝试了很多东西并不断提出错误的数据。我什至没有运气地尝试过这个。任何帮助将不胜感激。
Decrypt string in C# that was encrypted with PHP openssl_encrypt
这是我的 C# 代码:
string DecryptPHP()
{
//var _key = System.Text.Encoding.UTF8.GetBytes(key);
//var _iv = System.Text.Encoding.UTF8.GetBytes(iv);
var key = key = "1234567890123456789012345678901234567890123456789012345678901234";
var _key = FromHex(key);
var iv = "a64d63874ba9ee8f5a5028cb40ab70a4";
var _iv = FromHex(iv);
//pad key out to 32 bytes (256bits) if its too short
if (_key.Length < 32)
{
var paddedkey = new byte[32];
Buffer.BlockCopy(_key, 0, paddedkey, 0, key.Length);
_key = paddedkey;
}
//get the encrypted data and decrypt
var data_encrypted_string = "yFFQwLuOHeWouyfp0dyrnw==";
byte[] encryptedBytes = Convert.FromBase64String(data_encrypted_string);
return DecryptStringFromBytesAes(encryptedBytes, _key, _iv);
}
byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
return plaintext;
}
这里有些垃圾我没有清理,请见谅。你有两件事要改变。搜索括号中的文本以查找修复位置。
- (修复 1)我在某处读到 php 方法会截断比应有的长度更长的键。您的密钥是 64 个字符,但应该是 32 个字符。
- (修复 2)PaddingMode 看起来应该是
PKCS7
更新
代码保持不变,但我又添加了一段我忘记删除的代码:
- (修复 3)密钥应该是文本,而不是十六进制。
using System;
using System.Security.Cryptography;
using System.IO;
using System.Linq;
using System.Collections.Generic;
//
//
// https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rijndaelmanaged?view=net-5.0
public class Program
{
// full key 1234567890123456789012345678901234567890123456789012345678901234
// Fix 1: php truncates a key longer than what is supported, so I chopped this off to 32
private static string key = "12345678901234567890123456789012";
private static string originalText = "does this work";
private static string encryptedValue = "a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw==";
public static void Main()
{
// Console.WriteLine(OpenSslDecrypt(encryptedValue, key));
Console.WriteLine("decrypted text: " + DecryptPHP(encryptedValue));
}
public static byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
public static string DecryptPHP(string encrypted)
{
var hexSalt = encryptedValue.Substring(0, 32);
byte[] stringSalt = FromHex(hexSalt);
var saltBytes = FromHex(hexSalt);
Console.WriteLine("salt length bytes: " + saltBytes.Length);
var unsaltedEncryptedValue = encryptedValue.Substring(32);
Console.WriteLine("salt: " + hexSalt);
Console.WriteLine("unsaltedEncryptedValue: " + unsaltedEncryptedValue);
//get the encrypted data and decrypt
byte[] unsaltedEncryptedBytes = Convert.FromBase64String(unsaltedEncryptedValue);
// byte[] unsaltedEncryptedBytes = System.Text.ASCIIEncoding.UTF8.GetBytes(unsaltedEncryptedValue);
// Fix 3: key should be text, not hex.
// var _key = FromHex(key);
byte[] keyBytes = System.Text.ASCIIEncoding.UTF8.GetBytes(key);
return DecryptStringFromBytesAes(unsaltedEncryptedBytes, keyBytes, saltBytes);
}
public static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create a RijndaelManaged object
// with the specified key and IV.
// Fix 2: PaddingMode should be PKCS7, based on my tests. It gets rid of the extra ? chars.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
return plaintext;
}
}
dotnetfiddle link: https://dotnetfiddle.net/s2tfmM