【问题标题】:Encrypt in PHP, Decrypt in C# (WP7 / Silverlight) using AES / Rijndael使用 AES / Rijndael 在 PHP 中加密,在 C# (WP7 / Silverlight) 中解密
【发布时间】:2013-11-16 17:23:10
【问题描述】:

我在我的 android 应用程序中使用了一个用 PHP 编写的 REST 服务,没有太多麻烦。现在我尝试在 Windows Phone 应用程序中使用它,我已经快疯了!

目前我所知道的:Silverlight will accept only Aes in CBC mode and PKCS7 padding.

我得到:“填充无效且无法删除”异常(参见底部的完整代码):

plaintext = srDecrypt.ReadToEnd();

如果我在 C# 中加密和解密,使用相同的配置,它工作正常。当我尝试从 PHP 加密字符串中用 C# 进行解密时,它会失败并出现上述错误。

我的 PHP 脚本执行以下操作:

function encrypt128($message) {
    $vector = "DB96A56CCA7A69FC";
    $key = "6DBC44F54CA3CFDEDDCA140CA46A99C1"; // PHP md5 function leaves it in lower case, so I just copied the key from C# debug.

    //PKCS7 Padding
    $block = mcrypt_get_block_size('rijndael_128', 'cbc');
    $pad = $block - (strlen($message) % $block);
    $message.= str_repeat(chr($pad), $pad);

    $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
    mcrypt_generic_init($cipher, $key, $vector);
    $result = mcrypt_generic($cipher, $message);
    mcrypt_generic_deinit($cipher);

    return base64_encode($result);
}

在 C#(Silverlight / Windows Phone 7)中,我使用以下内容进行解密:

//Where buffer is the string data I got after calling the PHP REST service.
DecryptStringFromBytes(Convert.FromBase64String(buffer), MD5Core.GetHash("7a272d3e41372c547a272d3e41372c54"), System.Text.Encoding.UTF8.GetBytes("DB96A56CCA7A69FC"));

static string DecryptStringFromBytes(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("Key");

    // Declare the string used to hold
    // the decrypted text.
    string plaintext = null;

    // Create an RijndaelManaged object
    // with the specified key and IV.
    using (AesManaged rijAlg = new AesManaged())
    {
        rijAlg.Key = Key;
        rijAlg.IV = IV;

        // Create a decrytor to perform the stream transform.
        ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.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();
                }
            }
        }
    }
    return plaintext;
}

最大的问题是:我做错了什么?

提前致谢!

【问题讨论】:

  • 如果您在每种方法中加密一个非常小的字符串,并比较输出,它们是否不同?怎么样?
  • 如果我对“Test”进行编码,我会在 C# 中得到“eScuqAGH8L6cKaRG9ii+uw==”,在 PHP 中得到“0RysWwzyHHDnwcf0cIQ8xg==”。
  • 我更改了 StreamWriter 构造函数以测试所有可用的编码类型(UTF8、Unicode、BigEndian),但 C# 仍然生成不同的编码字符串。

标签: c# php silverlight windows-phone-7 encryption


【解决方案1】:

答案如下:

我从 PHP 和 C# 中删除了 MD5 废话,它们现在可以正常工作了。

以防万一您在这里寻找相同的答案,这里有一个示例代码。不要忘记制作自己的密钥和iv(虽然下面的那些可以工作,但不建议使用!)

PHP:

function encrypt128($message) {
    $vector = "0000000000000000";
    $key = "00000000000000000000000000000000";

    $block = mcrypt_get_block_size('rijndael_128', 'cbc');
    $pad = $block - (strlen($message) % $block);
    $message .= str_repeat(chr($pad), $pad);

    $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
    mcrypt_generic_init($cipher, $key, $vector);
    $result = mcrypt_generic($cipher, $message);
    mcrypt_generic_deinit($cipher);

    return base64_encode($result);
}

C#:

byte[] cripted = EncryptStringToBytes("Test", System.Text.Encoding.UTF8.GetBytes("00000000000000000000000000000000"), System.Text.Encoding.UTF8.GetBytes("0000000000000000"));

【讨论】:

  • Marcos,你根本没有使用你的向量。此外,您的向量长度应等于密钥大小。对于密码名称和方法,最好使用MCRYPT_RIJNDAEL_128MCRYPT_MODE_CBC,它们是内部定义的,不会被意外解释为其他任何东西。 System.Text.Encoding.UTF8.GetBytes会给你意想不到的IV数据,你可以使用byte[] Key = new byte[] { 0x00, ....};Encoding.ASCII.GetBytes(...),第一种方法通常用于金融行业的安全密钥定义。
【解决方案2】:

使用 PHP 加密/解密:

class Cipher {
    private $key, $iv;
    function __construct() {
        $this->key = "edrtjfjfjlldldld";
        $this->iv = "56666852251557009888889955123458";
    }
    function encrypt($text) {

        $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
        $padding = $block - (strlen($text) % $block);
        $text .= str_repeat(chr($padding), $padding);
        $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->key, $text, MCRYPT_MODE_CBC, $this->iv);

        return base64_encode($crypttext);
    }

    function decrypt($input) {
        $dectext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->key, base64_decode($input), MCRYPT_MODE_CBC, $this->iv);
        return $dectext;
    }
}

使用 C# 加密/解密:

public class RijndaelSimple
    {
        const string iv = "56666852251557009888889955123458";
        const string key = "edrtjfjfjlldldld";

        static public String EncryptRJ256(string plainText)
        {
            var encoding = new UTF8Encoding();
            var Key = encoding.GetBytes(key);
            var IV = encoding.GetBytes(iv);
            byte[] encrypted;

            using (var rj = new RijndaelManaged())
            {
                try
                {
                    rj.Padding = PaddingMode.PKCS7;
                    rj.Mode = CipherMode.CBC;
                    rj.KeySize = 256;
                    rj.BlockSize = 256;
                    rj.Key = Key;
                    rj.IV = IV;

                    var ms = new MemoryStream();

                    using (var cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
                    {
                        using (var sr = new StreamWriter(cs))
                        {
                            sr.Write(plainText);
                        }
                        encrypted = ms.ToArray();
                    }
                }
                finally
                {
                    rj.Clear();
                }
            }

            return Convert.ToBase64String(encrypted);
        }

        static public String DecryptRJ256(string input)
        {
            byte[] cypher = Convert.FromBase64String(input);

            var sRet = "";

            var encoding = new UTF8Encoding();
            var Key = encoding.GetBytes(key);
            var IV = encoding.GetBytes(iv);

            using (var rj = new RijndaelManaged())
            {
                try
                {
                    rj.Padding = PaddingMode.PKCS7;
                    rj.Mode = CipherMode.CBC;
                    rj.KeySize = 256;
                    rj.BlockSize = 256;
                    rj.Key = Key;
                    rj.IV = IV;
                    var ms = new MemoryStream(cypher);

                    using (var cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Read))
                    {
                        using (var sr = new StreamReader(cs))
                        {
                            sRet = sr.ReadLine();
                        }
                    }
                }
                finally
                {
                    rj.Clear();
                }
            }

            return sRet;
        }

    }

【讨论】:

  • 该代码在 Windows Phone 中不起作用。 WP 没有 RijndaelManaged 类
  • 我尝试了 c# 代码,但这个简单的测试无法解决 string encryptedString = EncryptRJ256(teststring);字符串解密字符串 = DecryptRJ256(加密字符串); Assert.AreEqual(decryptedString, teststring);
  • @AlexMaker,这行得通:string teststring = "The quick brown fox jumps over the lazy dog"; string encryptedString = RijndaelSimple.EncryptRJ256(teststring);字符串解密字符串 = RijndaelSimple.DecryptRJ256(加密字符串); bool bAreEqual = (decryptedString == teststring ? true : false); // bAreEqual = true
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 2014-05-08
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多