0

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;
            }
2
  • Can you post what you tried in C#? Commented Aug 5, 2021 at 21:57
  • I added what I have. plaintext always comes back with garbled data Commented Aug 5, 2021 at 22:15

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.