我正在写一个Windows应用程序在C#中必须与Mac应用程序(用Cocoa编写)进行交互。此应用程序使用CBC(IV,密钥,盐,HMAC)以AES加密文件。我对加密不太了解,但我认为这就是它的作用。我们使用的可可库是RNCryptor。他们有一个C# version,这是我在Windows端使用的(有一些修改,主要是使用byte[]
而不是字符串)。AES解密非文本文件最终损坏数据
现在文本文件被正确解密,但其他文件(例如,PNG文件)最终被损坏(正确的文件在右边,损坏在左边,使用UTF8编码,你可以看到有一个大量的钻石与S):
我相信这是由于文件的编码,但我想UTF8,预设的Unicode,ASCII ......和输出文件总是与损坏不同的文件大小,是ASCII和默认编码(UTF16我相信)大小最接近。
这是RNCryptor修改后的代码我使用:
public byte[] Decrypt (byte[] encryptedBase64, string password)
{
PayloadComponents components = this.unpackEncryptedBase64Data (encryptedBase64);
if (!this.hmacIsValid (components, password)) {
return null;
}
byte[] key = this.generateKey (components.salt, password);
byte[] plaintextBytes = new byte[0];
switch (this.aesMode) {
case AesMode.CTR:
// Yes, we are "encrypting" here. CTR uses the same code in both directions.
plaintextBytes = this.encryptAesCtrLittleEndianNoPadding(components.ciphertext, key, components.iv);
break;
case AesMode.CBC:
plaintextBytes = this.decryptAesCbcPkcs7(components.ciphertext, key, components.iv);
break;
}
return plaintextBytes;
}
private byte[] decryptAesCbcPkcs7 (byte[] encrypted, byte[] key, byte[] iv)
{
var aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
var decryptor = aes.CreateDecryptor(key, iv);
string plaintext;
using (MemoryStream msDecrypt = new MemoryStream(encrypted))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
return Encoding.UTF8.GetBytes(plaintext);
}
private PayloadComponents unpackEncryptedBase64Data (byte[] encryptedBase64)
{
List<byte> binaryBytes = new List<byte>();
binaryBytes.AddRange (encryptedBase64);
PayloadComponents components;
int offset = 0;
components.schema = binaryBytes.GetRange(0, 1).ToArray();
offset++;
this.configureSettings ((Schema)binaryBytes [0]);
components.options = binaryBytes.GetRange (1, 1).ToArray();
offset++;
components.salt = binaryBytes.GetRange (offset, Cryptor.saltLength).ToArray();
offset += components.salt.Length;
components.hmacSalt = binaryBytes.GetRange(offset, Cryptor.saltLength).ToArray();
offset += components.hmacSalt.Length;
components.iv = binaryBytes.GetRange(offset, Cryptor.ivLength).ToArray();
offset += components.iv.Length;
components.headerLength = offset;
components.ciphertext = binaryBytes.GetRange (offset, binaryBytes.Count - Cryptor.hmac_length - components.headerLength).ToArray();
offset += components.ciphertext.Length;
components.hmac = binaryBytes.GetRange (offset, Cryptor.hmac_length).ToArray();
return components;
}
private bool hmacIsValid (PayloadComponents components, string password)
{
byte[] generatedHmac = this.generateHmac (components, password);
if (generatedHmac.Length != components.hmac.Length) {
return false;
}
for (int i = 0; i < components.hmac.Length; i++) {
if (generatedHmac[i] != components.hmac[i]) {
return false;
}
}
return true;
}
,这是我的代码解密和写入文件:
byte[] decryptedFile = this.decryptor.Decrypt(File.ReadAllBytes(filePath), password);
File.WriteAllBytes(filePath, decryptedFile);
什么可以错在这里?提前致谢。
嘿,谢谢你的回复。不幸的是,除非我做错了什么,这是行不通的。这是修改后的方法:http://pastebin.com/DkXFndbC。该文件最终像很多中文字符一样。 – pmerino
@pmerino看起来你错误地从'msDecrypt'读取()包含* encrypted *字节,而不是从'csDecrypt'这将是* decrypted *字节。 – Iridium
谢谢!尝试重写代码,你有什么想法,现在它工作! – pmerino