How can I decrypt an encrypted MCRYPT_RIJNDAEL_256 value in C#, that was encrypted by mcrypt in PHP?

前端 未结 3 1499
不知归路
不知归路 2021-02-19 01:15

I am trying to read a Base64-Encoded value from a Database table managed on the Linux side. In that table there is a column called first_name. On the Linux side I can decrypt t

相关标签:
3条回答
  • 2021-02-19 01:48

    I hit the same problem when comunicating with a legacy system. I had to come up with my own solution as Rijndael with a Blocksize of 256 seems to be not supported by dotnet core.

    Here is my solution using the bouncy castle library:

        public static byte[] Rijandael256Decrypt(byte[] inputBytes, byte[] keyBytes)
        {
            // set up
            IBufferedCipher cipher = new PaddedBufferedBlockCipher(new RijndaelEngine(256), new ZeroBytePadding());
            KeyParameter keyParam = new KeyParameter(keyBytes);
            cipher.Init(false, keyParam);
            int sizeAtLeastRequired = cipher.GetOutputSize(inputBytes.Length);
            byte[] outputBytes = new byte[sizeAtLeastRequired];
    
            // decrypt            
            int length = cipher.ProcessBytes(inputBytes, outputBytes, 0);
            length += cipher.DoFinal(outputBytes, length);
    
            // resize output
            Array.Resize(ref outputBytes, length);
            return outputBytes;
        }
    
    0 讨论(0)
  • 2021-02-19 01:49

    Post is old, but this might help somebody in a future. This function encrypt exactly like mcrypt_encrypt with parameters MCRYPT_RIJNDAEL_256 and MCRYPT_MODE_ECB

        static byte[] EncryptStringToBytes(string plainText, byte[] key)
        {
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (key == null || key.Length <= 0)
                throw new ArgumentNullException("key");
    
            byte[] encrypted;
            using (var rijAlg = new RijndaelManaged())
            {
                rijAlg.BlockSize = 256;
                rijAlg.Key = key;
                rijAlg.Mode = CipherMode.ECB;
                rijAlg.Padding = PaddingMode.Zeros;
                rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                using (var msEncrypt = new MemoryStream())
                    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                            swEncrypt.Write(plainText);
                        encrypted = msEncrypt.ToArray();
                    }
            }
            return encrypted;
        }
    

    And here is function to decrypt it

         static string DecryptStringFromBytes(byte[] cipherText, byte[] key)
         {
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (key == null || key.Length <= 0)
                throw new ArgumentNullException("key");
    
            string plaintext;
            using (var rijAlg = new RijndaelManaged())
            {
                rijAlg.BlockSize = 256;
                rijAlg.Key = key;
                rijAlg.Mode = CipherMode.ECB;
                rijAlg.Padding = PaddingMode.Zeros;
                rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    
                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                using (var msDecrypt = new MemoryStream(cipherText))
                    using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        using (var srDecrypt = new StreamReader(csDecrypt))
                            plaintext = srDecrypt.ReadToEnd();
            }
            return plaintext;
        }
    
    0 讨论(0)
  • 2021-02-19 01:55

    As Paŭlo says, ECB mode does not use an IV. If C# insists on one then use all zero bytes.

    The key "patient_fn_salt" is 15 characters, 120 bits. Your decryption function is expecting 256 bits of key. You need to be very sure that the extra bits are identical in both systems and are being added in the same place in both systems. Even a single bit wrong will result in garbage decryption. Read the PHP documentation very carefully to determine exactly how "patient_fn_salt" is expanded to a 256 bit key. In particular check if the actual key is SHA256("patient_fn_salt").

    As an aside, ECB mode is insecure. Use either CTR mode or CBC mode in preference. CTR mode does not require padding so will probably mean less cyphertext to store.

    ETA: on another read through I notice that the C# side is padding with zeros. What padding is the PHP side using? Zero padding is not a good idea, as it cannot recognise a faulty decryption. PKCS7 padding has a much better chance of recognising a faulty output. Best to explicitly specify the padding on both ends rather than rely on defaults.

    0 讨论(0)
提交回复
热议问题