使用PHP解密C#加密

时间:2016-09-01 10:46:38

标签: c# php encryption rijndaelmanaged

前段时间我实施了一个C#web API来提供信息 此信息已加密,并由其他C#或Classic ASP网站使用 这是我使用EncryptRijndael和DecryptRijndael方法进行加密/解密的方法。

using System;
using System.Text;

namespace Encryption_Test
{
    using System.IO;
    using System.Security.Cryptography;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;

    class RijndaelManagedEncryption
    {
        //http://www.codeproject.com/Tips/704372/How-to-use-Rijndael-ManagedEncryption-with-Csharp

        #region Rijndael Encryption

        /// <summary>
        /// Encrypt the given text and give the byte array back as a BASE64 string
        /// </summary>
        /// <param name="text" />The text to encrypt
        /// <param name="salt" />The pasword salt
        /// <returns>The encrypted text</returns>
        public static string EncryptRijndael(string text, string salt, string inputKey)
        {
            if (string.IsNullOrEmpty(text))
                throw new ArgumentNullException("text");

            var aesAlg = NewRijndaelManaged(salt, inputKey);

            var blockSize = aesAlg.BlockSize;

            var strK = System.Text.Encoding.ASCII.GetString(aesAlg.Key);
            string s = strK;

            var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
            var msEncrypt = new MemoryStream();
            using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            using (var swEncrypt = new StreamWriter(csEncrypt))
            {
                swEncrypt.Write(text);
            }

            return Convert.ToBase64String(msEncrypt.ToArray());
        }
        #endregion

        #region Rijndael Dycryption
        /// <summary>
        /// Checks if a string is base64 encoded
        /// </summary>
        /// <param name="base64String" />The base64 encoded string
        /// <returns>
        public static bool IsBase64String(string base64String)
        {
            base64String = base64String.Trim();
            return (base64String.Length%4 == 0) &&
                   Regex.IsMatch(base64String, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None);

        }

        /// <summary>
        /// Decrypts the given text
        /// </summary>
        /// <param name="cipherText" />The encrypted BASE64 text
        /// <param name="salt" />
        /// <param name="inputKey"></param>
        /// The pasword salt
        /// <returns>De gedecrypte text</returns>
        public static string DecryptRijndael(string cipherText, string salt, string inputKey)
        {
            if (string.IsNullOrEmpty(cipherText))
                throw new ArgumentNullException("cipherText");

            if (!IsBase64String(cipherText))
                throw new Exception("The cipherText input parameter is not base64 encoded");

            string text;

            var aesAlg = NewRijndaelManaged(salt, inputKey);
            var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
            var cipher = Convert.FromBase64String(cipherText);

            using (var msDecrypt = new MemoryStream(cipher))
            {
                using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (var srDecrypt = new StreamReader(csDecrypt))
                    {
                        text = srDecrypt.ReadToEnd();
                    }
                }
            }
            return text;
        }
        #endregion

        #region NewRijndaelManaged

        /// <summary>
        /// Create a new RijndaelManaged class and initialize it
        /// </summary>
        /// <param name="salt" />
        /// <param name="inputKey"></param>
        /// The pasword salt
        /// <returns>
        private static RijndaelManaged NewRijndaelManaged(string salt, string inputKey)
        {
            if (salt == null) throw new ArgumentNullException("salt");
            var saltBytes = Encoding.ASCII.GetBytes(salt);
            var key = new Rfc2898DeriveBytes(inputKey, saltBytes);

            var aesAlg = new RijndaelManaged();
            aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);  //256 / 8 = 32
            aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8); //128 / 8 = 16
            //string k = System.Text.Encoding.Default.GetString(aesAlg.Key);
            //string i = System.Text.Encoding.Default.GetString(aesAlg.IV);
            //string l = k + i;

            #region testPHP
            ///*
            // So it would seem the week point in the chain for PHP is the Rfc2898DeriveBytes
            // */
            //aesAlg.Key = Encoding.UTF8.GetBytes(inputKey);
            //aesAlg.IV = Encoding.UTF8.GetBytes(salt);

            //k = System.Text.Encoding.Default.GetString(aesAlg.Key);
            //i = System.Text.Encoding.Default.GetString(aesAlg.IV);
            //l = k + i;
            #endregion testPHP

            return aesAlg;
        }
        #endregion
    }
}

你可以看到注释掉的时候,我只是通过将它们转换为byte []来设置Key和IV。这对PHP来说似乎没问题,但我宁愿不省略Rfc2898DeriveBytes。

它工作正常,消费网站能够减少信息。

现在这是我的(其他人的问题,但我想提供帮助),PHP网站现在需要使用我的Web API。他们似乎无法做到。他们认为这是由于创建IV的方式所致。

现在这让我想知道是否

  1. 他们不能胜任工作
  2. 我的实施使他们无法做到这一点。
  3. 现在我对PHP知之甚少,但通常可以遵循其代码块的流程。 我很感激,如果有人能够首先告诉我是否应该有可能用PHP实现这个目标,如果有的话,可能会有一些关于如何做的指示。

    注意 - 这是利用Rfc2898DeriveBytes,我认为这是问题的症结所在,并从其他人那里看出这个问题。

    一个例子

    • 要加密的字符串:Co-operation is the key to success!
    • 盐:This_is_the_password_salt
    • 输入键:This_is_the_input_key
    • 加密字符串:pLgIEjhNGDMfI0IynoAdbey3NKbOJzgUzYAlU14OWOpuZy7/lr7HRtFhiRKfjbZz

1 个答案:

答案 0 :(得分:0)

嗯 - 在找到一个可能会使用hash_hmac的沙箱之后,我似乎已经把它推迟了你们和你们的评论......

使用this site.

以及其中的以下代码(我希望它在实际情况下表现相同)

<?php

class Foo {

public function decrypt_full($key, $iv, $encrypted)
{
$dev = $this->pbkdf2("sha1", $key, $iv, 1000, 48, true);
$derived_key = substr($dev, 0, 32); //Keylength: 32
$derived_iv = substr($dev, 32, 16); // IV-length: 16
return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $derived_key, base64_decode($encrypted), MCRYPT_MODE_CBC, $derived_iv);
}

private function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');

$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);

$output = "";
for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
return substr($output, 0, $key_length);
}

}
//###########################################################################################
$encrypted = "pLgIEjhNGDMfI0IynoAdbey3NKbOJzgUzYAlU14OWOpuZy7/lr7HRtFhiRKfjbZz";
$iv = "This_is_the_password_salt";
$key = "This_is_the_input_key";

$foo = new foo;
echo "<br/>";
echo "Encrypted String: ".$encrypted."<br/>";
echo "Decrypted string: ".$foo->decrypt_full($key, $iv, $encrypted )."<br/>";
?>

输出是......

Key: .g���13f^sI>M��j$\�+�od�mY# �!
IV: �2]��&y�q� WJ��
Decrypted: Co-operation is the key to success!

迫不及待地告诉PHP家伙;)