代码之家  ›  专栏  ›  技术社区  ›  Juned Ansari

php中的c#MCRYPT_RIJNDAELĀ256加解密类

  •  3
  • Juned Ansari  · 技术社区  · 6 年前

    注:

    C代码

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace pharmarackencryption
    {
        class Program
        {
            private const string initVector = "aw90rela942f65u2";
    
            // This constant is used to determine the keysize of the encryption algorithm.
            private const int keysize = 256;
    
            public static string Encrypt(string plainText, string passPhrase = "testing")
            {
                byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
                byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
                PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
                byte[] keyBytes = password.GetBytes(keysize / 8);
                RijndaelManaged symmetricKey = new RijndaelManaged();
                symmetricKey.Mode = CipherMode.CBC;
                ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
                MemoryStream memoryStream = new MemoryStream();
                CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
                cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                cryptoStream.FlushFinalBlock();
                byte[] cipherTextBytes = memoryStream.ToArray();
                memoryStream.Close();
                cryptoStream.Close();
                return Convert.ToBase64String(cipherTextBytes);
            }
    
            public static string Decrypt(string cipherText, string passPhrase = "testing")
            {
                byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
                byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
                PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
                byte[] keyBytes = password.GetBytes(keysize / 8);
                RijndaelManaged symmetricKey = new RijndaelManaged();
                symmetricKey.Mode = CipherMode.CBC;
                ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
                MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
                CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
                byte[] plainTextBytes = new byte[cipherTextBytes.Length];
                int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                memoryStream.Close();
                cryptoStream.Close();
                return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
            }
    
            static void Main(string[] args)
            {
                Program p = new Program();
                string enc_password = Encrypt("437217");
                string dec_password = Decrypt("C9xJGa03dRQx9ePm0nLnHg==");
                Console.WriteLine(enc_password);
                Console.WriteLine(dec_password);
            }
        }
    }
    

    我在php中发现了一些类似的代码

    PHP代码:

    <?php 
        // key/iv in ASCII binary data, $str base64
        function decrypt_stuff($key, $str, $iv) {
            // $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($str), MCRYPT_MODE_CBC, $iv);
            $plaintext_dec = openssl_decrypt(base64_decode($str), "aes-256-cbc", $key,  OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
            return $plaintext_dec;
        }
    
        // key/iv in ascii binary data, $str ascii
        function encrypt_stuff($key, $str, $iv) {
            // $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $str, MCRYPT_MODE_CBC, $iv));
            if (($l = (strlen($str) & 15)) > 0) { $str .= str_repeat(chr(0), 16 - $l); }
            $ciphertext = base64_encode(openssl_encrypt($str, "aes-256-cbc", $key,  OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv));
            return $ciphertext;
        }
    
        echo encrypt_stuff("testing","437217","aw90rela942f65u2");
        //Result : LTbhEHjFgfa5PDJQXJEdKQ==
    

    4 回复  |  直到 6 年前
        1
  •  5
  •   t.m.adam    6 年前

    您的PHP代码会产生不同的结果,因为您使用的键不同。在你的C代码里 PasswordDeriveBytes 创建键,这是Microsoft对PBKDF1的实现。

    answer 由Maarten Bodewes,翻译成PHP。

    function passwordDeriveBytes($password, $salt, $iterations = 100, $len = 32) {
        $key = $password . $salt;
        for($i = 0; $i < $iterations; $i++) {
            $key = sha1($key, true);
        }
        if (strlen($key) < $len) {
            $hx = passwordDeriveBytes($password, $salt, $iterations - 1, 20);
            $counter = 0;
            while (strlen($key) < $len) {
                $counter += 1;
                $key .= sha1($counter . $hx, true);
            }
        }
        return substr($key, 0, $len);
    }
    

    此外,您还需要手动对数据进行编码和填充。您正在执行零字节填充,但在C代码中使用的是PKCS7(默认和首选)填充。最好让我 openssl

    function encrypt_stuff($key, $str, $iv) {
        return openssl_encrypt($str, "aes-256-cbc", $key, 0, $iv);
    }
    
    function decrypt_stuff($key, $str, $iv) {
        return openssl_decrypt($str, "aes-256-cbc", $key, 0, $iv);
    }
    

    使用派生自 passwordDeriveBytes ,此PHP代码生成与C代码相同的结果。

    $key = passwordDeriveBytes("testing", null);
    $enc = encrypt_stuff($key,"437217","aw90rela942f65u2");
    echo $enc;
    //C9xJGa03dRQx9ePm0nLnHg==
    

    • Rfc2898DeriveBytes 在C#:

      Rfc2898DeriveBytes kdf = new Rfc2898DeriveBytes(password, salt, iterations);
      byte[] key = kdf.GetBytes(32);
      

      hash_pbkdf2

      $key = hash_pbkdf2("sha1", $password, $salt, $iterations, 32, true);
      

      salt的长度应至少为8字节,迭代次数应至少为10000。

    • 你没用盐。你应该为每个密码使用一个随机的盐,它使你的钥匙更坚固。

    • 你使用的是静态静脉注射。静脉注射应该是独特的和不可预测的。你可以用 RNGCryptoServiceProvider :

      byte[] iv = new byte[16];
      RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
      rng.GetBytes(iv);
      

      openssl_random_pseudo_bytes :

      $iv = openssl_random_pseudo_bytes(16);
      

      你也可以用这个代码来做盐。

    • 你没有使用经过身份验证的加密。如果您使用的是PHP7,那么可以使用GCM,但不幸的是.NET没有提供任何AEAD算法。但是,你可以用 bouncycastle ,如果选择使用经过身份验证的加密。


    但是你的密码 每次你使用它,因为你应该使用随机IV。如果你有IV,你可以正确解密密文。IV不一定是秘密的,你可以把它存储在密文旁边。

    mcrypt 具有 MCRYPT_RIJNDAEL_256 RijndaelManaged

    symmetricKey.BlockSize = 256;
    

    但是你不应该使用 麦克里普

        2
  •  1
  •   Joseph_J    6 年前

    我不熟悉这个问题的结尾。不过,我会指出一些可能与你的问题有关的信息。

    • RIJNDAEL函数中的描述是指块大小,而不是键大小。例如 MCRYPT_RIJNDAEL_256 说明使用的块大小为256。它没有指定密钥大小。
    • 对于openssl AES函数,您指定的是密钥大小。举个例子 aes-256-cbc
    • 所有AES函数的块大小都是128位。所以你可以用 MCRYPT_RIJNDAEL_128 MCRYPT泳u RIJNDAEL泳128 以及 因为它们都使用128位块大小。
    • 所以出于这些原因 aes-256-cbc标准 不能与一起使用

    • 这个是多余的。如果您正在使用 您需要确保使用的是256位密钥。显然,要确保您使用的是相同的密钥来加密和解密。确保你的静脉注射是正确的。我会让他们都静态测试。一旦你得到它的工作修补与添加IV到密码字符串加密和分离的IV从密文解密

    • 使用 openssl_random_pseudo_bytes() 生成256位(32字节)密钥。你也可以使用 openssl\u random\u pseudo\u bytes() 生成你的静脉注射。

    LibSodium 图书馆。它现在是PHP最新版本的原生版本,并且有一个C#库。你可以在Github上很容易找到它。

    一旦你开始这样做,我将学习如何验证/验证你的加密。这是一个很好的起点。 Authentication Read

    希望有帮助。

        3
  •  0
  •   nhlm    6 年前

    不建议使用可逆算法在数据库中存储密码,应使用昂贵的哈希值存储密码。您应该考虑将密码存储切换到Argon2这样的散列。

    检查此项: http://php.net/manual/en/function.password-hash.php

        4
  •  -1
  •   sabkaraja    6 年前

    mcrypt已被移动。未删除。你可以试着安装这个

    sudo apt-get -y install gcc make autoconf libc-dev pkg-config
    sudo apt-get -y install php7.2-dev
    sudo apt-get -y install libmcrypt-dev
    sudo pecl install mcrypt-1.0.1
    

    PS:未测试