-1

Here is my php for openssl_encrypt:

 $text = "does this work";
 $key = "1234567890123456789012345678901234567890123456789012345678901234";
 $method = "AES-256-CBC";
 $cipher_length = openssl_cipher_iv_length($method); //16
 $iv_new = openssl_random_pseudo_bytes($cipher_length);
 $bin2hex = bin2hex($iv_new); //"a64d63874ba9ee8f5a5028cb40ab70a4"
 $openssl = openssl_encrypt($text, $method, $key, 0, $iv_new);
 $encrypted =  $bin2hex . $openssl;

Value of $encrypted is:

"a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw==" //encrypted in DecryptPHP

Here is my php for openssl_decrypt:

$iv_strlen = 32;
preg_match("/^(.{" . $iv_strlen . "})(.+)$/", $encrypted, $regs);
list(, $_iv, $_crypted_string) = $regs;

$_hex2bin = hex2bin($_iv); 
$ctype_xdigit = ctype_xdigit($_iv);
$remainder = strlen($_iv) % 2 == 0;
$new_text =  openssl_decrypt($_crypted_string, $method, $key, 0, $_hex2bin);

$new_text value is:

"does this work"

So this works fine but how can I take this string:

 "a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw=="

and convert it to "does this work" in C#? I've tried so many things and keep coming up with bad data. I even tried this with no luck. Any help would be greatly appreciated.

Decrypt string in C# that was encrypted with PHP openssl_encrypt

Here is my c# code:

             string DecryptPHP()
            {
    
                //var _key = System.Text.Encoding.UTF8.GetBytes(key);
                //var _iv =  System.Text.Encoding.UTF8.GetBytes(iv);
                var key = key = "1234567890123456789012345678901234567890123456789012345678901234";
                var _key = FromHex(key);
                var iv = "a64d63874ba9ee8f5a5028cb40ab70a4";
                var _iv = FromHex(iv);

                //pad key out to 32 bytes (256bits) if its too short
                if (_key.Length < 32)
                {
                    var paddedkey = new byte[32];
                    Buffer.BlockCopy(_key, 0, paddedkey, 0, key.Length);
                    _key = paddedkey;
                } 

                //get the encrypted data and decrypt
                var data_encrypted_string = "yFFQwLuOHeWouyfp0dyrnw==";
                byte[] encryptedBytes = Convert.FromBase64String(data_encrypted_string);
                return DecryptStringFromBytesAes(encryptedBytes, _key, _iv);
            }

            byte[] FromHex(string hex)
            {
                hex = hex.Replace("-", "");
                byte[] raw = new byte[hex.Length / 2];
                for (int i = 0; i < raw.Length; i++)
                {
                    raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
                }
                return raw;
            }

            static string DecryptStringFromBytesAes(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("iv");

                // Declare the RijndaelManaged object
                // used to decrypt the data.
                RijndaelManaged aesAlg = null;

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

                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };

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

                return plaintext;
            }
bstras21
  • 981
  • 3
  • 11
  • 32

1 Answers1

2

There's some junk in here I didn't clean up, so please excuse that. You have two things to change. Search the text in the parentheses to find where the fix is.

  • (Fix 1) I read somewhere that the php method truncates keys that are longer than they should be. Your key was 64 chars but should be 32 chars.
  • (Fix 2) The PaddingMode looks like it should be PKCS7

UPDATE

The code remains the same, but I added one more piece that I forgot I removed:

  • (Fix 3) The key should be text, not hex.
using System;
using System.Security.Cryptography;
using System.IO;
using System.Linq;
using System.Collections.Generic;
                    // https://stackoverflow.com/questions/68673772/how-to-decrypt-string-from-openssl-encrypt-in-c-sharp
//https://stackoverflow.com/questions/19719294/decrypt-string-in-c-sharp-that-was-encrypted-with-php-openssl-encrypt
// https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rijndaelmanaged?view=net-5.0
public class Program
{
    // full key 1234567890123456789012345678901234567890123456789012345678901234
    
    // Fix 1: php truncates a key longer than what is supported, so I chopped this off to 32
    private static string key = "12345678901234567890123456789012";
    private static string originalText = "does this work";
    private static string encryptedValue = "a64d63874ba9ee8f5a5028cb40ab70a4yFFQwLuOHeWouyfp0dyrnw==";
    
    public static void Main()
    {
        // Console.WriteLine(OpenSslDecrypt(encryptedValue, key));
        Console.WriteLine("decrypted text: " + DecryptPHP(encryptedValue));
    }
    
    public static byte[] FromHex(string hex)
    {
        hex = hex.Replace("-", "");
        byte[] raw = new byte[hex.Length / 2];
        for (int i = 0; i < raw.Length; i++)
        {
            raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return raw;
    }
    
    public static string DecryptPHP(string encrypted)
    {
        var hexSalt = encryptedValue.Substring(0, 32);
        byte[] stringSalt = FromHex(hexSalt);
        
        var saltBytes = FromHex(hexSalt);
        Console.WriteLine("salt length bytes: " + saltBytes.Length);
        var unsaltedEncryptedValue = encryptedValue.Substring(32);
        
        Console.WriteLine("salt: " + hexSalt);
        Console.WriteLine("unsaltedEncryptedValue: " + unsaltedEncryptedValue);

        //get the encrypted data and decrypt
        byte[] unsaltedEncryptedBytes = Convert.FromBase64String(unsaltedEncryptedValue);
        // byte[] unsaltedEncryptedBytes = System.Text.ASCIIEncoding.UTF8.GetBytes(unsaltedEncryptedValue);

        // Fix 3: key should be text, not hex.
        // var _key = FromHex(key);
        byte[] keyBytes = System.Text.ASCIIEncoding.UTF8.GetBytes(key);
        
        return DecryptStringFromBytesAes(unsaltedEncryptedBytes, keyBytes, saltBytes);
    }

    public static string DecryptStringFromBytesAes(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("iv");

        // Declare the RijndaelManaged object
        // used to decrypt the data.
        RijndaelManaged aesAlg = null;

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

        // Create a RijndaelManaged object
        // with the specified key and IV.
        //  Fix 2: PaddingMode should be PKCS7, based on my tests. It gets rid of the extra ? chars.
        aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, KeySize = 256, BlockSize = 128, Key = key, IV = iv };

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

        return plaintext;
    }
}

dotnetfiddle link: https://dotnetfiddle.net/s2tfmM

ps2goat
  • 8,067
  • 1
  • 35
  • 68