【问题标题】:CryptoJs encryption and c# decryption using RijndaelManaged - ErrorCryptoJs 加密和 c# 解密使用 RijndaelManaged - 错误
【发布时间】:2017-02-04 05:24:15
【问题描述】:

我有一个使用 CryptoJs 的 javascript 客户端文件加密。我有一个使用 RijndaelManaged 的​​服务器端文件解密。如果我使用 CryptoJs 进行加密和解密,它工作正常。但是,当我尝试使用 C# 代码解密时,它会引发以下错误。我尝试设置不同的填充、模式等无济于事。

CryptographicException length of the data to decrypt is invalid

CryptoJS 代码:

function encryptFile() {
selectedFiles = document.getElementById("MainContent_fileinput");

$.each(selectedFiles.files, function (i, file) {
    var reader = new FileReader();
    var strKey = " ";
    var strIv = " ";
    var byteArrKey = [169,204,147,221,70,76,207,92,102,12,237,65,5,205,34,106,178,141,138,117,224,153,37,124,54,17,74,223,224,153,72,209];
    var byteArrIV = [169,204,147,221,70,76,207,92,102,12,237,65,5,205,34,106];
    var byteVal;
    var byteValIv;

    reader.onloadend = function (e) {
        for (var i = 0; i < byteArrKey.length; i++) {
            byteVal = byteArrKey[i];
            if (byteVal < 16) { strKey += "0"; }
            strKey += byteVal.toString(16);
        };
        for (var i = 0; i < byteArrIV.length; i++) {
            byteValIv = byteArrIV[i];
            //if (byteValIv < 16) { strIv += "0"; }
            strIv += byteVal.toString(16);
        };
        var encrypted1 = CryptoJS.AES.encrypt(reader.result, strKey, { 'iv': strIv });
        //            var encrypted1 = CryptoJS.AES.encrypt(reader.result, key,
        //                                { keySize: 128 / 8, iv: iv1, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });

        var ct1 = encrypted1.toString();
        var encodedData1 = window.btoa(ct1);
        $.ajax({
            async: 'true',
            url: "MYWEBSERVICE URL",
            method: "POST",
            processData: 'false',
            headers: {
                'content-type': "application/x-www-form-urlencoded",
                'cache-control': "no-cache"
            },
            data: { 'folderPath': folderPath, 'uploadData': encodedData1, 'fileName': file.name + '.encrypted' },

            success: function (response) {
                debugger;
                console.log(response);
            },
            error: function (xhr, textStatus, error) {
                debugger;
                console.log(xhr.statusText);
            }
        });
    };
    reader.readAsDataURL(file);
})
}

使用c#解密:

private static byte[] CreateKey(string pwd)
{
    byte[] bytKey;
    byte[] bytSalt = Encoding.ASCII.GetBytes(pwd);
    PasswordDeriveBytes pdb = new PasswordDeriveBytes(pwd, bytSalt);
    bytKey = pdb.GetBytes(32);
    return bytKey;
}

private static byte[] CreateIV(string pwd)
{
    byte[] bytIV;
    byte[] bytSalt = Encoding.ASCII.GetBytes(pwd);
    PasswordDeriveBytes pdb = new PasswordDeriveBytes(pwd, bytSalt);
    bytIV = pdb.GetBytes(16);
    return bytIV;
}       

private static bool DecryptFile(string strInputFile, string strOutputFile)
{
   bool returnValue = true;
FileStream fsInput = null;
FileStream fsOutput = null;
Int32 intBytesInCurrentBlock;
CryptoStream csCryptoStream = null;

byte[] bytBuffer;   // = new byte[fsInput.Length];

bytKey = CreateKey("123456");
bytIV = CreateIV("123456");

try
{

     using (var fsInput = File.OpenRead(strInputFile))
             using (var fsOutput = File.Create(strOutputFile))
             using (Aes aes = Aes.Create())
             using (ICryptoTransform decryptor = aes.CreateDecryptor(bytKey, bytIV))
             using (var decryptionStream = new CryptoStream(fsOutput, decryptor, CryptoStreamMode.Write))
             using (var base64Decode = new FromBase64Transform())
             using (var cryptoStream = new CryptoStream(decryptionStream, base64Decode, CryptoStreamMode.Write))
             {
                 fsInput.CopyTo(cryptoStream);
                 cryptoStream.Dispose();
                 cryptoStream.FlushFinalBlock();
                 decryptionStream.Dispose();
                 decryptionStream.FlushFinalBlock();
             }
}
catch
{
    throw;
}
finally
{
    csCryptoStream.Close();
    fsInput.Close();
    fsOutput.Close();
}
return returnValue;
}

WebService方法:

byte[] byteUploadFile = Convert.FromBase64String(uploadData);
BinaryWriter binWriter = new         BinaryWriter(File.Open(Path.Combine(folderPath, fileName), FileMode.Create, FileAccess.ReadWrite));
binWriter.Write(byteUploadFile);
binWriter.Close();

【问题讨论】:

    标签: c# encryption cryptography cryptojs rijndaelmanaged


    【解决方案1】:

    您似乎从 javascript 将window.btoa(ct1) 的输出写入文件,这是 Base64 编码的。在 C# 中,您将文件的内容作为二进制数据读取。

    易于阅读:

    string base64 = File.ReadAllText(strInputFile);
    byte[] decoded = Convert.FromBase64String(base64);
    
    using (Aes aes = Aes.Create())
    using (ICryptoTransform decryptor = aes.CreateDecryptor(bytKey, bytIV))
    using (var fsOutput = File.Create(strOutputFile))
    using (var cryptoStream = new CryptoStream(fsOutput, decryptor, CryptoStreamMode.Write))
    {
        cryptoStream.Write(decoded, 0, decoded.Length);
    }
    

    更好的性能(尤其是对于大数据):

    using (var fsInput = File.OpenRead(strInputFile))
    using (var fsOutput = File.Create(strOutputFile))
    using (Aes aes = Aes.Create())
    using (ICryptoTransform decryptor = aes.CreateDecryptor(bytKey, bytIV))
    using (var decryptionStream = new CryptoStream(fsOutput, decryptor, CryptoStreamMode.Write))
    using (var base64Decode = new FromBase64Transform())
    using (var cryptoStream = new CryptoStream(decryptionStream, base64Decode, CryptoStreamMode.Write))
    {
        fsInput.CopyTo(cryptoStream);
    }
    

    在第二个例子中,数据流是:

    fsInput.CopyTo(cryptoStream) ->
        read some data from fsInput
        write data to cryptoStream
            Base64Decode the data in progress
            write decoded data to decryptionStream
                decrypt the data in progress
                    write decrypted to fsOutput
        loop until reading says it's out of data.
    

    然后在} 上(以相反的顺序对每个人调用 Dispose)

    cryptoStream.Dispose() -> cryptoStream.FlushFinalBlock() ->
        base64Decode will throw if there's bad data remaining
    decryptionStream.Dispose() -> decryptionStream.FlushFinalBlock() ->
        throw if padding is bad, otherwise write the final block to fsOutput
    

    【讨论】:

    • 所以,我根据您的建议添加了代码,请参阅原始问题中的DecryptFile()。现在我得到 Padding is invalid and cannot be removed 错误。
    • 另外,我添加了用于在服务器上创建/保存文件的 web 服务方法。看起来 Bsae64 在写入文件时正在转换为二进制。
    • 我也添加了这个aes.Padding = PaddingMode.Zeros;。现在错误消失了。但是,解密后的文件与原始文件不同。原始文件:4KB,加密:7KB,解密:5KB。
    • AES-CBC 最多只添加(或者,为了解密,删除)16 个字节。如果它增长了 3KB(增加了 75%),那么显然正在发生某种其他类型的转换。 Base64 仅增加了 33%(3 个字节 => 4 个字符)。您最初的例外是您解密的数据不是 16 字节的倍数,这意味着 AES-CBC 加密不是最后应用的转换。
    • 你能告诉我这个字符串var ct1 = encrypted1.toString();的格式是什么吗?它是Base64编码的吗? UTF-8?
    【解决方案2】:

    解决如下:

    使用 CryptoJS 进行文件加密:

    function esp() {
        selectedFiles = document.getElementById("MainContent_file1");
        var sfile = selectedFiles.files[0];
        var read = new FileReader();
        read.onload = function (e) {
            var key = CryptoJS.enc.Utf8.parse('7061737323313233');
            var iv = CryptoJS.enc.Utf8.parse('7061737323313233');
            var encrypted = CryptoJS.AES.encrypt(reader.result, key, { keySize: 128 / 8, iv: iv,
                mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7
            });
            var ct = encrypted.toString();
            debugger;
            $.ajax({
                async: 'true',
                url: "http://localhost:51936/WebService1.asmx/FileUpload",
                method: "POST",
                processData: 'false',
                headers: {
                    'content-type': "application/json",
                    'cache-control': "no-cache"
                },
                data: JSON.stringify({ 'folderPath': folderPath, 'uploadData': ct, 'fileName': sfile.name + '.encrypted' }),
                success: function (response) {
                    console.log(response);
                },
                error: function (xhr, textStatus, error) {
                    console.log(xhr.statusText);
                }
            });
        }
        read.readAsDataURL(sfile);
    }
    

    使用 C# 解密:

      [WebMethod]
    public void Decrypt(object sender, EventArgs e)
    {
        string folderPath = "path";
        DirectoryInfo d = new DirectoryInfo(folderPath).GetDirectories().OrderByDescending(ds => ds.LastWriteTimeUtc).First();
    
        try
        {
            foreach (FileInfo file in d.GetFiles())
            {
                string plaintext = "";
                string filename = file.Name;
                byte[] cipherText = new byte[file.Length];
                FileStream fs = file.OpenRead();
                fs.Read(cipherText, 0, (int)file.Length);
                byte[] keybytes = Encoding.UTF8.GetBytes("7061737323313233");
                byte[] iv = Encoding.UTF8.GetBytes("7061737323313233");
                MyWebService.MyWebServicedts = new MyWebService.MyWebService();
                using (var rijAlg = new RijndaelManaged())
                {
                    rijAlg.Mode = CipherMode.CBC;
                    rijAlg.Padding = PaddingMode.PKCS7;
                    rijAlg.FeedbackSize = 128;
    
                    rijAlg.Key = keybytes;
                    rijAlg.IV = iv;
                    var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                    using (var msDecrypt = new MemoryStream(cipherText))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }
                plaintext = plaintext.Substring(23);
                string name = filename.Substring(filename.LastIndexOf("/") + 1);
                name = name.Replace(".encrypted", "");
                dts.FileUpload(folderPath, plaintext, name);
            }
        }
        catch (Exception ex)
        {
            string err = ex.Message;
        }
    }
    

    Webservice 将数据保存为服务器上的文件:

    byte[] byteUploadFile = Convert.FromBase64String(uploadData);
    BinaryWriter binWriter = new         BinaryWriter(File.Open(Path.Combine(folderPath, fileName), FileMode.Create, FileAccess.ReadWrite));
    binWriter.Write(byteUploadFile);
    binWriter.Close();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-08
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-13
      相关资源
      最近更新 更多