2

I would like to know how to properly encrypt in C#, that Laravel (PHP) can decrypt with it's Encryption?

This is my C# encryption:

    private static readonly Encoding encoding = Encoding.UTF8;

    public static void Main(string[] args)
    {
        string key = "ysWZKXsnB1aS38Qzj5cza01wd3wT1234";
        string text = "Here is some data to encrypt!";

        string encrypted = encrypt(text, key);

        // Display the original data and the encrypted data.
        Console.WriteLine("Original: {0}", text);
        Console.WriteLine("Key: {0}", key);
        Console.WriteLine("Encrypted: {0}", encrypted);
    }

    private static string encrypt(string plainText, string key)
    {
        RijndaelManaged aes = new RijndaelManaged();
        aes.KeySize = 256;
        aes.BlockSize = 128;
        aes.Padding = PaddingMode.PKCS7;
        aes.Mode = CipherMode.CBC;

        aes.Key = encoding.GetBytes(key);
        aes.GenerateIV();

        ICryptoTransform AESEncrypt = aes.CreateEncryptor(aes.Key, aes.IV);
        byte[] buffer = Encoding.ASCII.GetBytes(phpSerialize(plainText));

        String encryptedText = Convert.ToBase64String(Encoding.Default.GetBytes(Encoding.Default.GetString(AESEncrypt.TransformFinalBlock(buffer, 0, buffer.Length))));


        String mac = "";

        mac = BitConverter.ToString(hmacSHA256(Convert.ToBase64String(aes.IV) + encryptedText, key)).Replace("-", "").ToLower();

        var keyValues = new Dictionary<string, object>
        {
            { "iv", Convert.ToBase64String(aes.IV) },
            { "value", encryptedText },
            { "mac", mac },
        };

        JavaScriptSerializer serializer = new JavaScriptSerializer();
        return Convert.ToBase64String(Encoding.ASCII.GetBytes(serializer.Serialize(keyValues)));
    }

The code successfully encrypts, but Laravel returns "Could not decrypt data." when trying to decrypt the code output here.

doncadavona
  • 7,162
  • 9
  • 41
  • 54
  • Possible duplicate of [How to decrypt an AES-256-CBC encrypted string](https://stackoverflow.com/questions/20297973/how-to-decrypt-an-aes-256-cbc-encrypted-string) – online Thomas Jul 28 '17 at 09:32
  • Is that question and answer enough for you? Because in the Laravel docs it is specified that it uses that encryption. – online Thomas Jul 28 '17 at 09:36
  • THe shared link is for decrypting encrypted string coming from Laravel. What I am trying to know is how to encrypt via C# in a proper way so that Laravel can decrypt it too. – doncadavona Jul 28 '17 at 10:04
  • Posted an effective answer for my problem. I hope you find it helpful too guys! Thanks for feedbacks! https://gist.github.com/doncadavona/19bf1423daf2790276dc0a823cd8c579 – doncadavona Aug 11 '17 at 10:37

1 Answers1

6

Here's a gist code I wrote that solved the problem:

using System;
using System.Text;
using System.Security.Cryptography;
using System.Web.Script.Serialization;
using System.Collections.Generic;

namespace Aes256CbcEncrypterApp
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello, world!");

            // The sample encryption key. Must be 32 characters.
            string Key = "8UHjPgXZzXCGkhxV2QCnooyJexUzvJrO";

            // The sample text to encrypt and decrypt.
            string Text = "Here is some text to encrypt!";

            // Encrypt and decrypt the sample text via the Aes256CbcEncrypter class.
            string Encrypted = Aes256CbcEncrypter.Encrypt(Text, Key);
            string Decrypted = Aes256CbcEncrypter.Decrypt(Encrypted, Key);

            // Show the encrypted and decrypted data and the key used.
            Console.WriteLine("Original: {0}", Text);
            Console.WriteLine("Key: {0}", Key);
            Console.WriteLine("Encrypted: {0}", Encrypted);
            Console.WriteLine("Decrypted: {0}", Decrypted);
        }
    }

    /**
     * A class to encrypt and decrypt strings using the cipher AES-256-CBC used in Laravel.
     */
    class Aes256CbcEncrypter
    {
        private static readonly Encoding encoding = Encoding.UTF8;

        public static string Encrypt(string plainText, string key)
        {
            try
            {
                RijndaelManaged aes = new RijndaelManaged();
                aes.KeySize = 256;
                aes.BlockSize = 128;
                aes.Padding = PaddingMode.PKCS7;
                aes.Mode = CipherMode.CBC;

                aes.Key = encoding.GetBytes(key);
                aes.GenerateIV();

                ICryptoTransform AESEncrypt = aes.CreateEncryptor(aes.Key, aes.IV);
                byte[] buffer = encoding.GetBytes(plainText);

                string encryptedText = Convert.ToBase64String(AESEncrypt.TransformFinalBlock(buffer, 0, buffer.Length));

                String mac = "";

                mac = BitConverter.ToString(HmacSHA256(Convert.ToBase64String(aes.IV) + encryptedText, key)).Replace("-", "").ToLower();

                var keyValues = new Dictionary<string, object>
                {
                    { "iv", Convert.ToBase64String(aes.IV) },
                    { "value", encryptedText },
                    { "mac", mac },
                };

                JavaScriptSerializer serializer = new JavaScriptSerializer();

                return Convert.ToBase64String(encoding.GetBytes(serializer.Serialize(keyValues)));
            }
            catch (Exception e)
            {
                throw new Exception("Error encrypting: " + e.Message);
            }
        }

        public static string Decrypt(string plainText, string key)
        {
            try
            {
                RijndaelManaged aes = new RijndaelManaged();
                aes.KeySize = 256;
                aes.BlockSize = 128;
                aes.Padding = PaddingMode.PKCS7;
                aes.Mode = CipherMode.CBC;
                aes.Key = encoding.GetBytes(key);

                // Base 64 decode
                byte[] base64Decoded = Convert.FromBase64String(plainText);
                string base64DecodedStr = encoding.GetString(base64Decoded);

                // JSON Decode base64Str
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                var payload = serializer.Deserialize<Dictionary<string, string>>(base64DecodedStr);

                aes.IV = Convert.FromBase64String(payload["iv"]);

                ICryptoTransform AESDecrypt = aes.CreateDecryptor(aes.Key, aes.IV);
                byte[] buffer = Convert.FromBase64String(payload["value"]);

                return encoding.GetString(AESDecrypt.TransformFinalBlock(buffer, 0, buffer.Length));
            }
            catch (Exception e)
            {
                throw new Exception("Error decrypting: " + e.Message);
            }
        }

        static byte[] HmacSHA256(String data, String key)
        {
            using (HMACSHA256 hmac = new HMACSHA256(encoding.GetBytes(key)))
            {
                return hmac.ComputeHash(encoding.GetBytes(data));
            }
        }
    }
}

The program will encrypt a given text using AES-256-CBC:

Hello, world!
Original: Here is some text to encrypt!
Key: 8UHjPgXZzXCGkhxV2QCnooyJexUzvJrO
Encrypted: eyJpdiI6IkNYVzRsZGprT05YemI0UmhZK0x4RFE9PSIsInZhbHVlIjoidGZieHpiV2hTbVVJKzhNZTd6aDk2WlVIbE1JUmdSYjBKMzh0VTR5dVhkWT0iLCJtYWMiOiIzMzBjYzcyOTg4Zjk1YjFlYWI4ZGY2ZTUyMjllOTkxNDExNzRjM2Q2YmIxOWI2NDk2Y2I1NGEzMDBiN2E3YmNlIn0=
Decrypted: Here is some text to encrypt!

I hope this helps other people that may need to implement AES-256-CBC encryption in C# that is fully compatible with Laravel.

doncadavona
  • 7,162
  • 9
  • 41
  • 54
  • tnks for this solution. i have problem. if you can help me. i used this class in Unity. and work fine. but in laravel i have an error . "The MAC is invalid.". what can i do?. i think the problem is my key. but how to use laravel key in c#? and when set laravel key in c#. i get this error "Error encrypting: Specified key is not a valid size for this algorithm." – kamiyar Jun 30 '18 at 06:29
  • FWIW - I had to implement a different encoding, instead of using `Encoding.UTF8`. In my case it was a base64 string, which required this: `Convert.FromBase64String(key);` – Richard Bailey Jun 29 '21 at 12:42