【问题标题】:PHP and C# AES256 encryption -> decryptionPHP 和 C# AES256 加密 -> 解密
【发布时间】:2017-04-19 19:42:59
【问题描述】:

我想在 PHP 中加密文本并在 C# 中解密,但我不能。

这是我的 PHP 代码:

define('AES_256_ECB', 'aes-256-ecb');
$encryption_key = "SomeSimpleTest";
$data = "Test123";
$encryptedData = openssl_encrypt($data, AES_256_ECB, $encryption_key, 0);

..这是我的 C# 代码:

(AESEncryption.cs 类)

   using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Security.Cryptography;

    namespace AESCrypto
    {
        class AESEncryption
        {
            public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
            {
                byte[] decryptedBytes = null;
                // Set your salt here to meet your flavor:
                byte[] saltBytes = passwordBytes;
                // Example:
                //saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

                using (MemoryStream ms = new MemoryStream())
                {
                    using (RijndaelManaged AES = new RijndaelManaged())
                    {
                        AES.KeySize = 256;
                        AES.BlockSize = 256;

                        var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
                        AES.Key = key.GetBytes(AES.KeySize / 8);
                        AES.IV = key.GetBytes(AES.BlockSize / 8);

                        AES.Mode = CipherMode.ECB;
                        //AES.Padding = PaddingMode.PKCS7;

                        using (CryptoStream cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                            cs.Close();
                        }
                        decryptedBytes = ms.ToArray();
                    }
                }

                return decryptedBytes;
            }

            public static string Decrypt(string decryptedText, byte[] passwordBytes)
            {
                byte[] bytesToBeDecrypted = Convert.FromBase64String(decryptedText);

                // Hash the password with SHA256
                passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

                byte[] decryptedBytes = AES_Decrypt(bytesToBeDecrypted, passwordBytes);

                // Getting the size of salt
                int saltSize = GetSaltSize(passwordBytes);

                // Removing salt bytes, retrieving original bytes
                byte[] originalBytes = new byte[decryptedBytes.Length - saltSize];
                for (int i = saltSize; i < decryptedBytes.Length; i++)
                {
                    originalBytes[i - saltSize] = decryptedBytes[i];
                }

                return Encoding.UTF8.GetString(originalBytes);
            }

            public static int GetSaltSize(byte[] passwordBytes)
            {
                var key = new Rfc2898DeriveBytes(passwordBytes, passwordBytes, 1000);
                byte[] ba = key.GetBytes(2);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < ba.Length; i++)
                {
                    sb.Append(Convert.ToInt32(ba[i]).ToString());
                }
                int saltSize = 0;
                string s = sb.ToString();
                foreach (char c in s)
                {
                    int intc = Convert.ToInt32(c.ToString());
                    saltSize = saltSize + intc;
                }

                return saltSize;
            }

            public static byte[] GetRandomBytes(int length)
            {
                byte[] ba = new byte[length];
                RNGCryptoServiceProvider.Create().GetBytes(ba);
                return ba;
            }
        }

    }

用法:

    using AESCrypto;

    ...
 public string DecryptText(string input, string password)
            {
                // Get the bytes of the string
                byte[] bytesToBeDecrypted = Convert.FromBase64String(input);
                byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
                passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

                byte[] bytesDecrypted = AESEncryption.AES_Decrypt(bytesToBeDecrypted, passwordBytes);

                string result = Encoding.UTF8.GetString(bytesDecrypted);

                return result;
            }

     private void btn1_Click(object sender, EventArgs e)
            {
                textBox1.Text = DecryptText("KEY_ENCRYPTED_WITH_PHP", "SomeSimpleTest");
            }

我什至尝试使用 CBC 但不起作用...加密模式并不重要。我只想让它按应有的方式工作。 谢谢。

【问题讨论】:

  • 您将常量定义为AES_256_ECB,但将其引用为AES_256_ecb(这就是为什么要注意通知级别消息的原因)。
  • 1.仅当加密需要安全时,加密模式才重要。 2.两者的加密模式必须相同,如果是CBC模式,IV必须相同。 3. 加密密钥应该是一个精确支持的长度并且也是相同的。 4. 您应该明确指定两者的填充,PKCS#7(née PKCS#5)是一个不错的选择 5. 验证所有输入/输出的编码(如果有)。
  • 正如扎夫所说。你的关键东西完全不同。 AES-256 需要 256 位密钥。您的 "SomeSimpleTest" 密钥只有 112 位长。这不是一个有效的密钥。此外,您的 PHP 代码没有进行任何密钥派生,因此您在 C# 中不需要 SHA256Rfc2898DeriveBytes。然后设置AES.BlockSize = 256; 并不意味着它是AES。这是 Rijndael,不再是 AES。
  • 切勿使用ECB mode。它是确定性的,因此在语义上不安全。您至少应该使用像CBCCTR 这样的随机模式。最好对您的密文进行身份验证,以免像padding oracle attack 这样的攻击是不可能的。这可以通过 GCM 或 EAX 等认证模式或encrypt-then-MAC 方案来完成。
  • 是的,AES.BlockSize = 128 是默认设置,并且是执行实际 AES 所必需的。您无需更改填充。默认情况下,OpenSSL 和 C# 正在执行 PKCS#7 填充。

标签: c# php encryption aes php-openssl


【解决方案1】:

php代码:

define('AES_128_ECB', 'aes-128-ecb');
$encryption_key = "MY_16_CHAR_KEY:)";
$data = "MyOwnEncryptedSecretText";
$encryptedData = openssl_encrypt($data, AES_128_ECB, $encryption_key, 0);

C#代码:

public String Decrypt(String text, String key)
{
    //decode cipher text from base64
    byte[] cipher = Convert.FromBase64String(text);
    //get key bytes
    byte[] btkey = Encoding.ASCII.GetBytes(key);

    //init AES 128
    RijndaelManaged aes128 = new RijndaelManaged();
    aes128.Mode = CipherMode.ECB;
    aes128.Padding = PaddingMode.PKCS7;

    //decrypt
    ICryptoTransform decryptor = aes128.CreateDecryptor(btkey, null);
    MemoryStream ms = new MemoryStream(cipher);
    CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);

    byte[] plain = new byte[cipher.Length];
    int decryptcount = cs.Read(plain, 0, plain.Length);

    ms.Close();
    cs.Close();

    //return plaintext in String
    return Encoding.UTF8.GetString(plain, 0, decryptcount);
}

及其用法:

string DecryptedText = Decrypt("GENERATED_KEY", "MY_16_CHAR_KEY:)");

现在效果很好:) 谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 2021-09-14
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多