使用 RijndaelManaged 的​​ CryptoJs 加密和 c# 解密 - 错误

CryptoJs encryption and c# decryption using RijndaelManaged - Error

我在 javascript 中使用 CryptoJs 进行了客户端文件加密。我有一个使用 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;
}

网络服务方法:

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

从 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

解决如下:

使用 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;
    }
}

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

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