用PHP解密C#加密

用PHP解密C#加密,c#,php,encryption,rijndaelmanaged,C#,Php,Encryption,Rijndaelmanaged,不久前,我实现了一个C#web API来提供信息。 此信息经过加密,并被其他C#或经典ASP网站使用。 这就是我使用EncryptRijndael和DecryptRijndael方法进行加密/解密的方式 using System; using System.Text; namespace Encryption_Test { using System.IO; using System.Security.Cryptography; using System.Text.Reg

不久前,我实现了一个C#web API来提供信息。
此信息经过加密,并被其他C#或经典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
    }
}
使用系统;
使用系统文本;
名称空间加密测试
{
使用System.IO;
使用System.Security.Cryptography;
使用System.Text.RegularExpressions;
使用System.Windows.Forms;
类RijndaelManagedEncryption
{
//http://www.codeproject.com/Tips/704372/How-to-use-Rijndael-ManagedEncryption-with-Csharp
#区域Rijndael加密
/// 
///对给定文本进行加密,并将字节数组作为BASE64字符串返回
/// 
///要加密的文本
///盐这个词
///加密文本
公共静态字符串EncryptRijndael(字符串文本、字符串盐、字符串输入密钥)
{
if(string.IsNullOrEmpty(text))
抛出新的ArgumentNullException(“文本”);
var aesAlg=新管理(salt,输入键);
var blockSize=aesAlg.blockSize;
var strK=System.Text.Encoding.ASCII.GetString(aesAlg.Key);
字符串s=strK;
var encryptor=aesAlg.CreateEncryptor(aesAlg.Key,aesAlg.IV);
var msEncrypt=newmemoryStream();
使用(var csEncrypt=newcryptostream(msEncrypt,encryptor,CryptoStreamMode.Write))
使用(var swEncrypt=newstreamwriter(csEncrypt))
{
书写(文本);
}
返回Convert.tobase64字符串(msEncrypt.ToArray());
}
#端区
#Rijndael区双重加密
/// 
///检查字符串是否为base64编码
/// 
///base64编码字符串
/// 
公共静态bool IsBase64String(string base64String)
{
base64String=base64String.Trim();
返回(base64String.长度%4==0)&&
Regex.IsMatch(base64String,@“^[a-zA-Z0-9\+/]*={0,3}$”,RegexOptions.None);
}
/// 
///解密给定的文本
/// 
///加密的BASE64文本
/// 
/// 
///盐这个词
///解密文本
公共静态字符串DecryptRijndael(字符串密文、字符串salt、字符串输入密钥)
{
if(string.IsNullOrEmpty(密文))
抛出新的ArgumentNullException(“密文”);
如果(!IsBase64String(密文))
抛出新异常(“密文输入参数不是base64编码”);
字符串文本;
var aesAlg=新管理(salt,输入键);
var decryptor=aesAlg.CreateDecryptor(aesAlg.Key,aesAlg.IV);
var cipher=Convert.FromBase64String(密文);
使用(var msDecrypt=新内存流(密码))
{
使用(var csDecrypt=new CryptoStream(msDecrypt,decryptor,CryptoStreamMode.Read))
{
使用(var srDecrypt=newstreamreader(csDecrypt))
{
text=srDecrypt.ReadToEnd();
}
}
}
返回文本;
}
#端区
#新日达地区管理
/// 
///创建一个新的RijndaelManaged类并初始化它
/// 
/// 
/// 
///盐这个词
/// 
私有静态RijndaelManaged NewRijndaelManaged(字符串salt,字符串inputKey)
{
如果(salt==null)抛出新的ArgumentNullException(“salt”);
var saltBytes=Encoding.ASCII.GetBytes(salt);
var键=新的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);
//stringi=System.Text.Encoding.Default.GetString(aesAlg.IV);
//字符串l=k+i;
#区域测试PHP
///*
//因此,PHP链中的一周点似乎是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;
#端域测试
回归方程;
}
#端区
}
}
在接近结尾时,您可以看到注释掉的,我只是通过将提供的参数转换为字节[]来设置Key和IV。这对于PHP来说似乎没问题,但我不想忽略Rfc2898DeriveBytes

它工作得很好,消费网站能够减少信息量

现在是我的(其他人的问题,但我想提供帮助),一个PHP站点现在需要使用我的Web API。他们似乎做不到这一点。他们认为这是由于IV的产生方式

现在我想知道

  • 他们不能胜任这项工作
  • 我的实施使他们无法做到这一点
  • 现在我对PHP知之甚少,但通常可以遵循其代码块的流程。 如果有人能首先告诉我是否有可能用PHP实现这个目标,我将不胜感激,如果有,也许可以提供一些如何实现这个目标的建议

    注意-这是利用Rfc2898DeriveBytes,我认为这是问题的症结所在,并将此问题与其他类似问题区分开来

    一个例子
    • 要加密的字符串:
      合作是成功的关键
    • Salt:
      这是密码
      
      <?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!