patrickpissurno / fastify-esso

The easiest authentication plugin for Fastify, with built-in support for single sign-on (SSO)
https://npm.im/fastify-esso
MIT License
52 stars 6 forks source link

Decrypting Bearer in C# #10

Closed bnaambo closed 3 years ago

bnaambo commented 3 years ago

Iam using Fastify-esso in a Api for Software Login. i try to decrypt the Wristband Data in C#. now the issue is when i run the data trough decryption i get text in chinese back??

 internal string Decrypt()
        {
            if (data == null || data.Length < 32 || data.Length % 2 != 0)
            {
                throw new Exception("Invalid Data");
            }

            Console.WriteLine(data.Substring(32));
            byte[] encryptedwristband = Encoding.UTF8.GetBytes(data.Substring(32));
            byte[] iv = StringToByteArray(data.Substring(0, 32));

            using (Aes aes = new AesManaged())
            {
                aes.Padding = PaddingMode.PKCS7;
                aes.KeySize = 128;          // in bits
                aes.Key = key;  // 16 bytes for 128 bit encryption
                aes.IV = iv;   // AES needs a 16-byte IV
                                              // Should set Key and IV here.  Good approach: derive them from
                                              // a password via Cryptography.Rfc2898DeriveBytes
                byte[] cipherText = null;
                byte[] plainText = null;

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(encryptedwristband, 0, encryptedwristband.Length);
                    }

                    cipherText = ms.ToArray();
                }

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherText, 0, cipherText.Length);
                    }

                    plainText = ms.ToArray();
                }
                return Encoding.Unicode.GetString(plainText);
            }
        }
patrickpissurno commented 3 years ago

Thanks for trying out fastify-esso.

I created a simple demo app in C# that successfully decrypts the token.

Utils.cs

using System;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace Demo
{
    class Utils
    {
        public static string HexFromBytes(byte[] bytes)
        {
            return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
        }

        public static byte[] BytesFromHex(string hex)
        {
            var bytes = new byte[hex.Length / 2];

            for (var i = 0; i < bytes.Length; i++)
            {
                var val = hex.Substring(i * 2, 2);
                bytes[i] = byte.Parse(val, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
            }

            return bytes;
        }

        internal static async Task<string> Decrypt(byte[] key, string data)
        {
            if (data == null || data.Length < 32 || data.Length % 2 != 0) // iv in hex format will always have 32 characters
                throw new Exception("Invalid data");

            var iv = BytesFromHex(data.Substring(0, 32));
            var encrypted = BytesFromHex(data.Substring(32));

            using (var aes = new RijndaelManaged { Mode = CipherMode.CBC, IV = iv, Key = key, Padding = PaddingMode.PKCS7 })
            {
                var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

                using (var stream = new MemoryStream(encrypted))
                {
                    using (var cStream = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
                    {
                        using (var reader = new StreamReader(cStream))
                        {
                            return await reader.ReadToEndAsync();
                        }
                    }
                }
            }
        }
    }
}

It can be used like this:

Program.cs

using System;
using System.Text;
using CryptSharp.Utility;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            var key = SCrypt.ComputeDerivedKey(Encoding.UTF8.GetBytes("11111111111111111111"), Encoding.UTF8.GetBytes("authorization"), 16384, 8, 1, 1, 32);

            var token = "Bearer 308d1f7e556cb65872339cfc4e26dc8ad3619bd3cb974356b60ef643e80630ad";

            Console.WriteLine(Utils.Decrypt(key, token.Substring(7)).Result);
            Console.ReadLine();
        }
    }
}

Outputs:

{"a":"test"}

The above example uses this NuGet Package to derive the key from the secret, in a similar way to how fastify-esso internally does.

You don't need to use that same Scrypt library. Any Scrypt library will do just fine. In fact, you don't even need to use one. You can use the following Node.js script to manually derive the key:

const crypto = require('crypto');
const key = crypto.scryptSync('11111111111111111111', 'authorization', 32);
console.log(key.toString('hex'));
//c1206785f5bcb655b610872eb06343756ac841aa4a31238a4a6ec1d4b94ae62e

And then replace the following line with the resulting key:

//var key = SCrypt.ComputeDerivedKey(Encoding.UTF8.GetBytes("11111111111111111111"), Encoding.UTF8.GetBytes("authorization"), 16384, 8, 1, 1, 32);
var key = Utils.BytesFromHex("c1206785f5bcb655b610872eb06343756ac841aa4a31238a4a6ec1d4b94ae62e");

In all the above examples 11111111111111111111 is the secret and authorization is the header name. You should replace those with the ones you're currently using in your application.

Remember: they both must match across all applications.

I tested the above code with .NET Framework 4.8, but it should also work with .NET Core and .NET 5+. ASP.NET should also work as is (but it may require some changes, be advised). I've never used ASP.NET myself so I can't help you with that.

Feel free to ask any questions.

Hope it helps!

Thanks.

bnaambo commented 3 years ago

Which version of Cryptsharp do you use? the lasted one doesnt contain ComputeDerivedKey.

patrickpissurno commented 3 years ago

I’m not actually using CryptSharp, to be honest. I’m using this NuGet package: https://www.nuget.org/packages/SCrypt/2.0.0.2?_src=template. It’s a CryptSharp’s fork, and thus I don’t really know which version of the full CryptSharp would work.

But you don’t need to use the same library. Just pick whatever one works best for you.

PS: make sure you set the Scrypt parameters to be the same as the ones I showed in the above example. Otherwise the derived key will end up being different and thus it won’t work.

Cheers.

patrickpissurno commented 3 years ago

Closing due to inactivity. Feel free to reopen it if you need to.