gpt4 book ai didi

c# MCRYPT_RIJNDAEL_256 php中的加密解密类

转载 作者:可可西里 更新时间:2023-11-01 00:54:30 30 4
gpt4 key购买 nike

我正在尝试将 c# 应用程序转换为 php,但我停留在 C# 为基于 RIJNDAEL 算法的加密和解密提供安全类的地方。我正在尝试转换为 php。

注意:我使用的是 php 7.2,因此此版本已弃用 mcrypt。

C#代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace pharmarackencryption
{
class Program
{
private const string initVector = "aw90rela942f65u2";

// This constant is used to determine the keysize of the encryption algorithm.
private const int keysize = 256;

public static string Encrypt(string plainText, string passPhrase = "testing")
{
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}

public static string Decrypt(string cipherText, string passPhrase = "testing")
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}

static void Main(string[] args)
{
Program p = new Program();
string enc_password = Encrypt("437217");
string dec_password = Decrypt("C9xJGa03dRQx9ePm0nLnHg==");
Console.WriteLine(enc_password);
Console.WriteLine(dec_password);
}
}
}

加密:C9xJGa03dRQx9ePm0nLnHg==

我在php中发现了一些类似的代码

PHP代码:

<?php 
// key/iv in ASCII binary data, $str base64
function decrypt_stuff($key, $str, $iv) {
// $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($str), MCRYPT_MODE_CBC, $iv);
$plaintext_dec = openssl_decrypt(base64_decode($str), "aes-256-cbc", $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
return $plaintext_dec;
}

// key/iv in ascii binary data, $str ascii
function encrypt_stuff($key, $str, $iv) {
// $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $str, MCRYPT_MODE_CBC, $iv));
if (($l = (strlen($str) & 15)) > 0) { $str .= str_repeat(chr(0), 16 - $l); }
$ciphertext = base64_encode(openssl_encrypt($str, "aes-256-cbc", $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv));
return $ciphertext;
}

echo encrypt_stuff("testing","437217","aw90rela942f65u2");
//Result : LTbhEHjFgfa5PDJQXJEdKQ==

两者都在做同样的事情,但结果仍然不同

最佳答案

您的 PHP 代码会产生不同的结果,因为您没有使用相同的 key 。在您的 C# 代码中,您使用 PasswordDeriveBytes 创建 key ,这是 Microsoft 对 PBKDF1 的实现。

PHP 不支持 PBKDF1,但我们可以编写一个与 C# 兼容的函数。下面的代码灵感来自这个伟大的 answer由 Maarten Bodewes 翻译成 PHP。

function passwordDeriveBytes($password, $salt, $iterations = 100, $len = 32) {
$key = $password . $salt;
for($i = 0; $i < $iterations; $i++) {
$key = sha1($key, true);
}
if (strlen($key) < $len) {
$hx = passwordDeriveBytes($password, $salt, $iterations - 1, 20);
$counter = 0;
while (strlen($key) < $len) {
$counter += 1;
$key .= sha1($counter . $hx, true);
}
}
return substr($key, 0, $len);
}

此外,您正在手动对数据进行 bese64 编码和填充。您正在执行零字节填充,但在您的 C# 代码中,您使用的是 PKCS7(默认和首选)填充。最好让 openssl 填充和编码您的数据。

function encrypt_stuff($key, $str, $iv) {
return openssl_encrypt($str, "aes-256-cbc", $key, 0, $iv);
}

function decrypt_stuff($key, $str, $iv) {
return openssl_decrypt($str, "aes-256-cbc", $key, 0, $iv);
}

使用从 passwordDeriveBytes 派生的 key ,此 PHP 代码产生与您的 C# 代码相同的结果。

$key = passwordDeriveBytes("testing", null);
$enc = encrypt_stuff($key,"437217","aw90rela942f65u2");
echo $enc;
//C9xJGa03dRQx9ePm0nLnHg==

但是,出于以下原因,我不建议使用此代码。

  • 最好使用 PBKDF2 作为您的 key 。您可以使用 Rfc2898DeriveBytes在 C# 中:

    Rfc2898DeriveBytes kdf = new Rfc2898DeriveBytes(password, salt, iterations);
    byte[] key = kdf.GetBytes(32);

    hash_pbkdf2在 PHP 中:

    $key = hash_pbkdf2("sha1", $password, $salt, $iterations, 32, true);

    salt 长度至少为 8 个字节,迭代次数至少为 10,000。

  • 您没有使用盐。您应该为每个密码使用随机盐,它会使您的 key 更强大。

  • 您正在使用静态 IV。 IV 应该是唯一且不可预测的。您可以使用 RNGCryptoServiceProvider 创建随机 IV :

    byte[] iv = new byte[16];
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    rng.GetBytes(iv);

    openssl_random_pseudo_bytes :

    $iv = openssl_random_pseudo_bytes(16);

    您也可以将此代码用于盐。

  • 您没有使用经过身份验证的加密。如果您使用的是 PHP 7,则可以使用 GCM,但遗憾的是 .NET 不提供任何 AEAD 算法。但是,您可以使用 bouncycastle ,如果您选择使用经过身份验证的加密。


但是您的加密代码应该在您每次使用它时产生不同的结果,因为您应该使用随机 IV。如果您有 IV,则可以正确解密密文。 IV 不必保密;您可以将它存储在密文旁边。

如果您将 mcryptMCRYPT_RIJNDAEL_256 一起使用,您仍然可以使您的 PHP 代码与 C# 兼容,因为 RijndaelManaged 支持 256 位 block 大小.

symmetricKey.BlockSize = 256;

但是您不应该使用 mcrypt,因为它没有维护,并且在 PHP 7 中已弃用。

关于c# MCRYPT_RIJNDAEL_256 php中的加密解密类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52181093/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com