简体   繁体   English

PHP 相当于 .net AES 加密

[英]PHP equivalent of .net AES encryption

I am working on a data exchange integration with my client and the data they send me is encrypted using their C# encrypt method (below).我正在与我的客户进行数据交换集成,他们发送给我的数据使用他们的 C# encrypt方法(如下) encrypt

My app is running PHP 5.3 and I need an equivalent code to decrypt the data they send.我的应用程序运行的是 PHP 5.3,我需要一个等效的代码来解密他们发送的数据。 I have the PHP code but it'd not decrypt the client data correctly for me.我有 PHP 代码,但它不会为我正确解密客户端数据。

Clearly I am making some mistake in my encryption/decryption methods, IV key or something.显然,我在加密/解密方法、IV 密钥或其他方面犯了一些错误。 Can anyone spot the mistake?任何人都可以发现错误吗?

Thanks.谢谢。

C# Code (From my client): C# 代码(来自我的客户):

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

public class Program
{
    public static void Main()
    {
        var text = "this is a plain string";
        var enc = Program.Encrypt(text);
        Console.WriteLine(enc);
        Console.WriteLine(Program.Decrypt(enc));
    }

    public static string Encrypt(string clearText)
    {
        var EncryptionKey = "1234567890123456";
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            byte[] IV = new byte[15];
            var rand = new Random();
            rand.NextBytes(IV);
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }

                clearText = Convert.ToBase64String(IV) + Convert.ToBase64String(ms.ToArray());
            }
        }

        return clearText;
    }

    public static string Decrypt(string cipherText)
    {
        var EncryptionKey = "1234567890123456";
        byte[] IV = Convert.FromBase64String(cipherText.Substring(0, 20));
        cipherText = cipherText.Substring(20).Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, IV);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }

                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }

        return cipherText;
    }
}

PHP Code I have:我有 PHP 代码:

public function encrypt($plainText)
{
    $secretKey = '1234567890123456';

    return rtrim(
        base64_encode(
            mcrypt_encrypt(
                MCRYPT_RIJNDAEL_256,
                $secretKey, $plainText,
                MCRYPT_MODE_ECB,
                mcrypt_create_iv(
                    mcrypt_get_iv_size(
                        MCRYPT_RIJNDAEL_256,
                        MCRYPT_MODE_ECB
                    ),
                    MCRYPT_RAND)
            )
        ), "\0"
    );
}

public function decrypt($encodedData)
{
    $secretKey = '1234567890123456';

    return rtrim(
        mcrypt_decrypt(
            MCRYPT_RIJNDAEL_256,
            $secretKey,
            base64_decode($encodedData),
            MCRYPT_MODE_ECB,
            mcrypt_create_iv(
                mcrypt_get_iv_size(
                    MCRYPT_RIJNDAEL_256,
                    MCRYPT_MODE_ECB
                ),
                MCRYPT_RAND
            )
        ), "\0"
    );
}

Can anyone spot the mistake?任何人都可以发现错误吗?

Yes, and the big one isn't really your fault: mcrypt's confusing API strikes again .是的,最大的问题并不是你的错: mcrypt 令人困惑的 API 再次出现

That said, there are actually multiple mistakes here.也就是说,这里实际上有多个错误。

return rtrim( // unnecessary
    base64_encode(
        mcrypt_encrypt(
            MCRYPT_RIJNDAEL_256, // Not AES
            $secretKey, $plainText,
            MCRYPT_MODE_ECB, // BAD, use MCRYPT_MODE_CBC or 'ctr' instead
            mcrypt_create_iv(
                mcrypt_get_iv_size(      // unless you're going make this
                    MCRYPT_RIJNDAEL_256, // configurable, you should just
                    MCRYPT_MODE_ECB      // hard-code this as an integer
                ),
                MCRYPT_RAND) // BAD, use MCRYPT_DEV_URANDOM
        )
    ), "\0"
); 

If you're going to generate an IV, it should be communicated so your recipient can decrypt the same first block successfully.如果你要生成一个 IV,它应该被传达,以便你的接收者可以成功解密同一个第一个块。 The C# code does this, the PHP does not. C# 代码会这样做,而 PHP 不会。

From a cryptography engineering perspective, you should consider, both in C# land and in PHP, deploying an Encrypt then Authenticate protocol.从密码学工程的角度来看,您应该考虑在 C# 领域和 PHP 中部署加密然后身份验证协议。 See this blog post on encryption and authentication .请参阅此有关加密和身份验证的博客文章 Also, all the crypto code you've ever written is probably broken .此外, 您编写的所有加密代码可能都已损坏

It seems like the PHP Script is Using the wrong Mode:似乎 PHP 脚本使用了错误的模式:
https://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.mode%28v=vs.110%29.aspx https://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.mode%28v=vs.110%29.aspx
The C# Functions do not set any Mode so the default is CBC. C# 函数不设置任何模式,因此默认为 CBC。
The PHP part uses ECB instead, which is not only wrong, but insecure. PHP 部分使用 ECB 代替,这不仅错误,而且不安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM