【问题标题】:Refactor JavaScript decryption into C# - AES 128将 JavaScript 解密重构为 C# - AES 128
【发布时间】:2021-06-19 11:23:31
【问题描述】:

我需要使用可工作的 JavaScript 来解密消息并将其转换为 C#。我有解密信息(下面的“解密”变量),如下所示:AES-128:<salt>:<iv>:<key>。这是 JavaScript:

function decodeString(message, decrypt) {
    var parts = decrypt.split(':', 4);
    var salt = CryptoJS.enc.Hex.parse(parts[1]);
    var iv = CryptoJS.enc.Hex.parse(parts[2]);
    var key = CryptoJS.PBKDF2(parts[3], salt, { keySize: 128/32, iterations: 100 });
    try {
        message = message.replace(/\s+/g, '');
        var d = CryptoJS.AES.decrypt(message, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
        message = d.toString(CryptoJS.enc.Utf8);
    } catch (e) {
        console.error("Encountered a problem decrypting and encrypted page!");
        console.log(e);
    }
    
    return(message);       
}

这是我在 C# 中的内容,但在 CreateDecryptor 调用中出现异常。

using System.Security.Cryptography;

private string DecodeString(string message, string decrypt)
{
    string[] parts = decrypt.ToString().Split(':');
    byte[] salt = Encoding.UTF8.GetBytes(parts[1]);
    byte[] iv = Encoding.UTF8.GetBytes(parts[2]);
    var pbkdf2 = new Rfc2898DeriveBytes(parts[3], salt, 100);
    int numKeyBytes = 128;  // Not sure this is correct
    byte[] key = pbkdf2.GetBytes(numKeyBytes);

    string plainText = null;
    using (AesManaged aes = new AesManaged())
    {
        aes.KeySize = numKeyBytes;  // Not sure if this is correct
        aes.BlockSize = 128;    // Defaults to 128, but not sure this is correct
        aes.Mode = CipherMode.CBC;
        aes.Padding = PaddingMode.PKCS7;

        try
        {
            // The below line has the following exception:
            //    The specified key is not a valid size for this algorithm.
            //    Parameter name: key
            using (var decrypter = aes.CreateDecryptor(key, iv))
            using (var plainTextStream = new MemoryStream())
            {
                using (var decrypterStream = new CryptoStream(plainTextStream, decrypter, CryptoStreamMode.Write))
                using (var binaryWriter = new BinaryWriter(decrypterStream))
                {
                    string encryptedText = Regex.Replace(message, @"\s+", "");
                    binaryWriter.Write(encryptedText);
                }
                byte[] plainTextBytes = plainTextStream.ToArray();
                plainText = Encoding.UTF8.GetString(plainTextBytes);
            }
        }
        catch (Exception ex)
        {
            log.Error("Unable to decrypt message.", ex);
        }

        return plainText;
    }
}

任何建议将不胜感激!

【问题讨论】:

    标签: javascript c# encryption aes pbkdf2


    【解决方案1】:

    在C#代码中存在以下问题:

    • Salt 和 IV 必须经过十六进制解码(而不是 UTF8 编码)。
    • numKeyBytes 以字节为单位指定密钥大小,因此对于 AES-128 为 16(而不是 128)。
    • aes.KeySize 以位为单位指定密钥大小,因此是 numKeyBytes * 8(而不是 numKeyBytes),但也可以省略。
    • 对于aes.BlockSizeaes.Modeaes.Padding,使用默认值(128、CBC、PKCS7),因此无需明确指定。
    • encryptedText 必须经过 Base64 解码。

    一个可能的实现是:

    private string Decrypt(string message, string decrypt)
    {
        string[] parts = decrypt.ToString().Split(':');
        byte[] salt = StringToByteArray(parts[1]);                                                              // Hex decode salt                                            
        byte[] iv = StringToByteArray(parts[2]);                                                                // Hex dedoce IV                                           
        var pbkdf2 = new Rfc2898DeriveBytes(parts[3], salt, 100);
        int numKeyBytes = 16;                                                                                   // AES-128 key size in bytes: 16
        byte[] key = pbkdf2.GetBytes(numKeyBytes);
    
        string plainText = null;
        using (AesManaged aes = new AesManaged())
        {
            aes.KeySize = 192;
            try
            {
                string encryptedText = Regex.Replace(message, @"\s+", "");
                using (var decrypter = aes.CreateDecryptor(key, iv))
                using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(encryptedText)))      // Base64 decode ciphertext
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decrypter, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            plainText = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unable to decrypt message.", ex);
            }
    
            return plainText;
        }
    }
    

    StringToByteArray() 来自here

    我将 Stream 部分更改为类似于 this example,但原始实现也可以正常工作,因此此更改是可选的。

    测试:两个代码都返回数据

    message = "YhyXEjjNAnRUUONwVzlha59tRoWkeEwTkOtSKOicRd/iBKkGgIp+DeWmvEXxAU53";
    decrypt = "AES-128:30313233343536373839303132333435:35343332313039383736353433323130:my passphrase";
    

    明文:

    The quick brown fox jumps over the lazy dog
    

    【讨论】:

    • 简直太棒了!像魅力一样工作。非常感谢您抽出宝贵时间做出回应。我了解到,尽管我在软件领域有 30 年的经验,但我还有很多东西要学习密码学(毫无疑问,还有其他领域)。
    猜你喜欢
    • 1970-01-01
    • 2021-12-20
    • 2013-08-12
    • 2013-08-11
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多