我正在尝试将C#加密函数转换为php,但我怀疑存在编码问题,或者IV生成不正确。
这是用于将加密的文本发送到API的,并且我目前已尝试强制使用utf8,但base64编码的字符串始终不同于运行C#函数的字符串。我似乎也找不到在C#中生成IV的确切方法。
可悲的是,我无法更改API解密的方式,因此我不得不以此方式对其进行加密。
C#函数
public void EncryptStringToBytes(string plaintext) {
string key = DateTime.UtcNow.ToShortDateString();
HashAlgorithm algorithm = SHA256.Create();
byte[] bytekey = algorithm.ComputeHash(Encoding.UTF8.GetBytes(key));
using (Aes myAes = Aes.Create()) {
myAes.Key = bytekey;
// Encrypt the string to an array of bytes.
byte[] encrypted = null;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = myAes.CreateEncryptor(myAes.Key, myAes.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream()) {
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
//Write all data to the stream.
swEncrypt.Write(plaintext);
}
encrypted = msEncrypt.ToArray();
}
}
Console.WriteLine(Convert.ToBase64String(encrypted));
Console.WriteLine(Convert.ToBase64String(myAes.IV));
}
}
PHP函数
date_default_timezone_set("UTC");
function encrypt($string) {
// Generate key based on current time
$secret_key = utf8_encode(date('Y-m-d'));
// Hash the key with SHA256
$key = hash('sha256', $secret_key);
// Use AES 128 w/ CBC as encryption method
$encrypt_method = "AES-128-CBC";
// Get cipher length based on encryption method
$cypher_length = openssl_cipher_iv_length($encrypt_method);
// Generate IV -- possible issue
$iv = openssl_random_pseudo_bytes($cypher_length);
// Encrypt input string with the given method, key and IV
$output = openssl_encrypt($string, $encrypt_method, $key, OPENSSL_RAW_DATA , $iv);
$debug_info = [ 'date' => $secret_key, 'key' => $key, 'method' => $encrypt_method, 'cypher_len' => $cypher_length, 'iv' => $iv, 'output' => $output];
return [base64_encode($output), base64_encode($iv), $debug_info];
}
答案 0 :(得分:0)
多亏了bartonjs,我找到了解决方案,我不得不使用AES-256-CBC而不是128。此外,在散列时我没有使用原始输出,这也改变了结果,并且因为我发送了加密数据和IV使用SoapClient的php-soap槽我不需要使用base64_encode,因为SoapClient已经为我做了。
工作代码如下:
function encrypt($string, $debug = false) {
$method = 'aes-256-cbc';
$secret_key = date('Y-m-d', time());
$key = hash('SHA256', $secret_key, true);
$cypher_length = openssl_cipher_iv_length($method);
$iv = random_bytes($cypher_length);
$output = openssl_encrypt($string, $method, $key, OPENSSL_RAW_DATA, $iv);
$debug_info = [ 'date' => $secret_key, 'date_utf8' => utf8_encode($secret_key), 'key' => utf8_encode($key), 'method' => $method, 'cypher_len' => $cypher_length, 'iv' => base64_encode($iv), 'output' => base64_encode($output)];
if($debug){
return [$output, $iv, $debug_info];
}
return [$output, $iv];
}