.net C#中的CryptoJS.AES.decrypt

kcrjzv8t  于 2023-05-19  发布在  .NET
关注(0)|答案(3)|浏览(266)

我需要将此代码JavaScript更改为C#
var CryptoJS = require("crypto-js"); var bytes = CryptoJS.AES.decrypt(ciphertext, secretkey); var originalText = bytes.toString(CryptoJS.enc.Utf8);
示例
已编码的JSON或字符串:
U2FsdGVkX1+pmKonC+E+MGs9BltH/axDE3IRYIV+vHF0yuteP4JAzuQ/CmmSgY2xkqeAhl02bIL5cJhsE1NOsc79ENadltxt2QEBymquSnbUsuhtxHptgGUXV0XuSPPQAt4/Rk2bDaR7qJw2LJKh4U1/pqeJUlqP2qLdtBTLs7E+W2TVh0/yMAVyuGUctEtx41qOClFzyfPxNydtSO6vzQ+3OOrI4Ov7ZgX07OJIF5sAq+m3pJQspL93UHbKS1w7a4dJUn2s+7JRYASkD9IBsheXI//SiE3yJv3c/dOs3VFDl4ok+m0MkgMwHQ0ELySUx1/UVTY6lefenO2RgASE52ATwIyKy7rdf4GKnrYpU7rdMZwcu1enI8Jpz5Ri3pFioyJSiPPDVKIecDQJ+UsQpsszWA6mQb3YMRhIxJrdcjSGEIHPGTHFEYgVpSO9y4EeGKLvX5oJ0tQDhO+QW1LQszcojRsgFuyFkdAsjNVzRNK3K4qE6Ua8j6t/kyE9i/MW7DQ0nT3d3CozLGS68PdEI34kljArY6Hmrgkt4InvBKdMvfffogKE3NtwBhf/3nK5
密码或密钥:
F2Gs3zjSjd3
输出:
[{"file":"https://b-g-eu-9.feetcdn.com:2223/v3-hls-playback/c83527cf3b73ecffcf91595b165e137b7bf0f0ff2cf816d8667161afea2370e71690359b5976a5dc5c03de31f949fb1b200f2bce6c273a4130adf84021cf6552384560a824abbe8461d68ffcd0cebd910f40863d28243932cc345541a0cd0c8e12788b9dd7cfed3537ba53fcaa365bf0afb6fac7ae10374d4d89c7a50d37988df1625da6a6e248a2c6ac5183c26a1b0b1d9e24ecaa036a31c306f7714c3c7b2c/playlist.m3u8","type":"hls"}]
我尝试在这个page和工作很好,但我需要C#的实现。
请帮助
我尝试了C#中的一些AES解密变体,但运气不好。

6l7fqoea

6l7fqoea1#

啊我发现这个工作100%

public static string DecryptAes(string encryptedString, string passphrase)
    {
        // encryptedString is a base64-encoded string starting with "Salted__" followed by a 8-byte salt and the
        // actual ciphertext. Split them here to get the salted and the ciphertext
        var base64Bytes = Convert.FromBase64String(encryptedString);
        var saltBytes = base64Bytes[8..16];
        var cipherTextBytes = base64Bytes[16..];

        // get the byte array of the passphrase
        var passphraseBytes = Encoding.UTF8.GetBytes(passphrase);

        // derive the key and the iv from the passphrase and the salt, using 1 iteration
        // (cryptojs uses 1 iteration by default)
        DeriveKeyAndIv(passphraseBytes, saltBytes, 1, out var keyBytes, out var ivBytes);

        // create the AES decryptor
        using var aes = Aes.Create();
        aes.Key = keyBytes;
        aes.IV = ivBytes;
        // here are the config that cryptojs uses by default
        // https://cryptojs.gitbook.io/docs/#ciphers
        aes.KeySize = 256;
        aes.Padding = PaddingMode.PKCS7;
        aes.Mode = CipherMode.CBC;
        var decryptor = aes.CreateDecryptor(keyBytes, ivBytes);

        // example code on MSDN https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-5.0
        using var msDecrypt = new MemoryStream(cipherTextBytes);
        using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
        using var srDecrypt = new StreamReader(csDecrypt);

        // read the decrypted bytes from the decrypting stream and place them in a string.
        return srDecrypt.ReadToEnd();
    }

    /// <summary>
    /// <para>C# equivalent method of EVP_BytesToKey in OpenSSL
    /// https://stackoverflow.com/questions/8008253/c-sharp-version-of-openssl-evp-bytestokey-method</para>
    /// <para>Generate the Key and the IV from the input Passphrase and the Salt</para>
    /// </summary>
    /// <param name="passphrase"></param>
    /// <param name="salt"></param>
    /// <param name="iterations">How many iterations to perform hash</param>
    /// <param name="key">The output 32 byte key</param>
    /// <param name="iv">The output 16 byte iv</param>
    private static void DeriveKeyAndIv(byte[] passphrase, byte[] salt, int iterations, out byte[] key, out byte[] iv)
    {
        var hashList = new List<byte>();

        var preHashLength = passphrase.Length + (salt?.Length ?? 0);
        var preHash = new byte[preHashLength];

        Buffer.BlockCopy(passphrase, 0, preHash, 0, passphrase.Length);
        if (salt != null)
            Buffer.BlockCopy(salt, 0, preHash, passphrase.Length, salt.Length);

        var hash = MD5.Create();
        var currentHash = hash.ComputeHash(preHash);

        for (var i = 1; i < iterations; i++)
        {
            currentHash = hash.ComputeHash(currentHash);
        }

        hashList.AddRange(currentHash);

        while (hashList.Count < 48) // for 32-byte key and 16-byte iv
        {
            preHashLength = currentHash.Length + passphrase.Length + (salt?.Length ?? 0);
            preHash = new byte[preHashLength];

            Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
            Buffer.BlockCopy(passphrase, 0, preHash, currentHash.Length, passphrase.Length);
            if (salt != null)
                Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + passphrase.Length, salt.Length);

            currentHash = hash.ComputeHash(preHash);

            for (var i = 1; i < iterations; i++)
            {
                currentHash = hash.ComputeHash(currentHash);
            }

            hashList.AddRange(currentHash);
        }

        hash.Clear();
        key = new byte[32];
        iv = new byte[16];
        hashList.CopyTo(0, key, 0, 32);
        hashList.CopyTo(32, iv, 0, 16);
    }

Tony Tran tmtxt
CryptoJsStaticHelper.cs

h5qlskok

h5qlskok2#

您需要做的第一件事是将输入数据拆分为salt和实际密文。

static byte[] Signature = new byte[] { 0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0x5f };

byte[] saltedCipher = Convert.FromBase64String(base64Cipher);
if (!Enumerable.SequenceEqual(Signature, saltedCipher.Take(Signature.Length))) return null; // invalid cipher

byte[] salt = saltedCipher.Skip(Signature.Length).Take(8).ToArray();
byte[] cipher = saltedCipher.Skip(Signature.Length + salt.Length).ToArray();

第二步是生成48字节的数据,其中32字节用于AES密钥,16字节用于IV,使用称为EvpKDF的算法(这是CryptoJS默认使用的)。

byte[] kdfOutput = EvpKDF(passwordBytes, salt, 48);
aes.Key = kdfOutput.Take(32).ToArray();
aes.IV = kdfOutput.Skip(32).Take(16).ToArray();

最后,必须使用AES和Key和IV的计算值来实际解密数据。

byte[] decrypted = aesDecryptor.TransformFinalBlock(cipher, 0, cipher.Length);
return Encoding.Default.GetString(decrypted);

我的完整实现看起来像这样:

static byte[] Signature = new byte[] { 0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0x5f };

static string Decrypt(string base64Cipher, string password)
{
    using (Aes aes = Aes.Create())
    {
        byte[] saltedCipher = Convert.FromBase64String(base64Cipher);
        if (!Enumerable.SequenceEqual(Signature, saltedCipher.Take(Signature.Length))) return null; // invalid cipher

        byte[] salt = saltedCipher.Skip(Signature.Length).Take(8).ToArray();
        byte[] cipher = saltedCipher.Skip(Signature.Length + salt.Length).ToArray();

        byte[] passwordBytes = Encoding.Default.GetBytes(password);

        byte[] kdfOutput = EvpKDF(passwordBytes, salt, 48);
        aes.Key = kdfOutput.Take(32).ToArray();
        aes.IV = kdfOutput.Skip(32).Take(16).ToArray();

        using (ICryptoTransform aesDecryptor = aes.CreateDecryptor())
        {
            byte[] decrypted = aesDecryptor.TransformFinalBlock(cipher, 0, cipher.Length);
            return Encoding.Default.GetString(decrypted);
        }
    }
}

static byte[] EvpKDF(byte[] password, byte[] salt, int targetSize)
{
    using (MD5 md5 = MD5.Create())
    {
        byte[] output = new byte[targetSize];
        byte[] buffer = null;

        int outputSize = 0;
        while (outputSize < targetSize)
        {
            if (buffer != null)
                buffer = md5.ComputeHash(buffer.Concat(password).Concat(salt).ToArray());
            else buffer = md5.ComputeHash(password.Concat(salt).ToArray());

            Array.Copy(buffer, 0, output, outputSize, buffer.Length);
            outputSize += buffer.Length;
        }

        return output;
    }
}

请注意,这个实现并不完美,还有很多需要改进的地方,但是对于像您作为示例提供的少量数据来说,它应该是不错的。

cnh2zyt3

cnh2zyt33#

试试这个:

using System.Security.Cryptography;
using System.Text;

var data = "U2FsdGVkX1+pmKonC+E+MGs9BltH/axDE3IRYIV+vHF0yuteP4JAzuQ/CmmSgY2xkqeAhl02bIL5cJhsE1NOsc79ENadltxt2QEBymquSnbUsuhtxHptgGUXV0XuSPPQAt4/Rk2bDaR7qJw2LJKh4U1/pqeJUlqP2qLdtBTLs7E+W2TVh0/yMAVyuGUctEtx41qOClFzyfPxNydtSO6vzQ+3OOrI4Ov7ZgX07OJIF5sAq+m3pJQspL93UHbKS1w7a4dJUn2s+7JRYASkD9IBsheXI//SiE3yJv3c/dOs3VFDl4ok+m0MkgMwHQ0ELySUx1/UVTY6lefenO2RgASE52ATwIyKy7rdf4GKnrYpU7rdMZwcu1enI8Jpz5Ri3pFioyJSiPPDVKIecDQJ+UsQpsszWA6mQb3YMRhIxJrdcjSGEIHPGTHFEYgVpSO9y4EeGKLvX5oJ0tQDhO+QW1LQszcojRsgFuyFkdAsjNVzRNK3K4qE6Ua8j6t/kyE9i/MW7DQ0nT3d3CozLGS68PdEI34kljArY6Hmrgkt4InvBKdMvfffogKE3NtwBhf/3nK5";
var key = "F2Gs3zjSjd3";
var inputBytes = Convert.FromBase64String(data);
var keyBytes = new byte[128 / 8];
var keyBytesTemp = Encoding.UTF8.GetBytes(key);
Array.Copy(keyBytesTemp, keyBytes, keyBytesTemp.Length);

byte[] iv;
using (var aes = Aes.Create())
{
    aes.GenerateIV();
    iv = aes.IV;
}

var encrypted = AesCrypt(keyBytes, iv, inputBytes, CryptMode.Encrypt);
var decrypted = AesCrypt(keyBytes, iv, encrypted, CryptMode.Decrypt);

var result = Convert.ToBase64String(decrypted);
if (data == result)
{
    Console.WriteLine("Works");
}

static byte[] AesCrypt(byte[] keyBytes, byte[] iv, byte[] inputBytes, CryptMode cryptMode)
{
    using (var aes = Aes.Create())
    {
        aes.IV = iv;
        aes.Mode = CipherMode.CBC;
        aes.Key = keyBytes;

        aes.Padding = PaddingMode.PKCS7;

        using (var encrypto = CreateCryptoTransform(aes))
        {
            byte[] encryptedBytes = encrypto.TransformFinalBlock(inputBytes, 0, inputBytes.Length);
            return encryptedBytes;
        }

        ICryptoTransform CreateCryptoTransform(SymmetricAlgorithm aes)
        {
            switch (cryptMode)
            {
                case CryptMode.Encrypt: return aes.CreateEncryptor();
                case CryptMode.Decrypt: return aes.CreateDecryptor();
                default: throw new InvalidOperationException($"Unsupported crypt mode {cryptMode}.");
            }
        }
    }
}

public enum CryptMode
{
    Encrypt,
    Decrypt
}

相关问题