似乎存在一种惯例,其中IV可以在AES加密文件的开头以明文存储。
在加密和解密期间提供密钥和IV时,我可以成功加密和解密文件。这使用下面的代码,稍作修改。如果该代码有帮助,请LMK,我将添加它。
但是,如果我尝试以明文将IV写入文件的开头,我无法解密内容(不确定它是否真的被加密了)。
有人可以指出下面的错误吗?不确定为什么.NET框架没有这个内置选项。
如果有人能指出我没有遵循上述惯例的方式,请指出它们!
using System;
using System.Security.Cryptography;
public class AESBase : IDisposable
{
protected AesManaged AES;
protected ICryptoTransform CryptoTransform;
public AESBase(byte[] key, byte[] iv = null)
{
AES = new AesManaged
{
BlockSize = 128,
KeySize = 256,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = key
};
if (iv != null) { AES.IV = iv; }
}
}
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
internal class AESFiles : AESBase, IFileCrytpo
{
internal AESFiles(byte[] key, byte[] iv) : base(key, iv) { }
#region internal methods
public void Encrypt(string inputFileName, string outputFileName, bool overwriteFile)
{
CryptoTransform = AES.CreateEncryptor(AES.Key, AES.IV);
if (overwriteFile)
{
DeleteFile(outputFileName);
}
Transform(inputFileName, outputFileName, true);
}
public void Decrypt(string inputFileName, string outputFileName, bool overwriteFile)
{
CryptoTransform = AES.CreateDecryptor(AES.Key, AES.IV);
if (overwriteFile)
{
DeleteFile(outputFileName);
}
Transform(inputFileName, outputFileName, false);
}
#endregion public methods
#region private methods
private void Transform(string inputFileName, string outputFileName, bool encrypt)
{
var destination = new FileStream(outputFileName, FileMode.CreateNew, FileAccess.Write, FileShare.None);
if (encrypt)
{
//put the IV unencrypted in the front of the string
destination.Write(AES.IV, 0, AES.BlockSize / 8);
}
var source = new FileStream(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
if (!encrypt)
{
source.Read(AES.IV, 0, AES.BlockSize / 8);
//var temp = Encoding.UTF8.GetString(AES.IV);
}
Transform(source, destination, CryptoTransform);
}
private static void Transform(Stream inputStream, Stream outputStream, ICryptoTransform transform)
{
using (var cryptoStream = new CryptoStream(outputStream, transform, CryptoStreamMode.Write))
{
//inputStream.Position = AES.BlockSize/8 + 1; CryptographicException : Length of the data to decrypt is invalid.
//inputStream.Position = AES.BlockSize/8; CryptographicException : Padding is invalid and cannot be removed.
inputStream.CopyTo(cryptoStream);
cryptoStream.FlushFinalBlock();
}
}
private static void DeleteFile(string fileName)
{
if (File.Exists(fileName))
{
File.Delete(fileName);
}
}
#endregion private methods
}
[TestFixture]
class AESFilesTest
{
private const string Path = @"C:\Users\Joe\Desktop\";
private const string FileInput = "Input.csv";
private const string FileEncrypted = "Encrypted.csv";
private const string FileDecrypted = "Decrypted.csv";
private readonly string _fileContents = String.Format("Test3,Test4" + Environment.NewLine, "Test5,Test6");
private readonly byte[] _key;
private readonly byte[] _iv;
private readonly Engine _engine;
public AESFilesTest()
{
_engine = new Engine();
_key = Encoding.UTF8.GetBytes("CEC520FA51EA0A47E87295FA32442605"); //test key
_iv = Encoding.UTF8.GetBytes("FB423A0BCB2AF4A4"); //test iv
File.WriteAllText(Path + FileInput, _fileContents);
}
[Test]
public void decrypted_text_matches_original()
{
const string inputFileWithPath = Path + FileInput;
_engine.Encrypt(_key, _iv, inputFileWithPath, Path + FileEncrypted, true);
_engine.Decrypt(_key, Path + FileEncrypted, Path + FileDecrypted, true);
var decrypted = File.ReadAllText(Path + FileDecrypted);
Console.WriteLine(decrypted);
Assert.AreEqual(_fileContents, decrypted);
}
答案 0 :(得分:3)
有很多错误......正确的代码:
private void Transform(string inputFileName, string outputFileName, bool encrypt)
{
using (var source = new FileStream(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var destination = new FileStream(outputFileName, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
ICryptoTransform cryptoTransform;
if (encrypt)
{
//put the IV unencrypted in the front of the string
destination.Write(AES.IV, 0, AES.BlockSize / 8);
cryptoTransform = AES.CreateEncryptor(AES.Key, AES.IV);
}
else
{
byte[] bytes = new byte[AES.BlockSize / 8];
source.Read(bytes, 0, bytes.Length);
AES.IV = bytes;
cryptoTransform = AES.CreateDecryptor(AES.Key, AES.IV);
}
Transform(source, destination, cryptoTransform, encrypt);
}
}
private static void Transform(Stream inputStream, Stream outputStream, ICryptoTransform transform, bool encrypt)
{
using (var cryptoStream = new CryptoStream(encrypt ? outputStream : inputStream, transform, encrypt ? CryptoStreamMode.Write : CryptoStreamMode.Read))
{
//inputStream.Position = AES.BlockSize/8 + 1; CryptographicException : Length of the data to decrypt is invalid.
//inputStream.Position = AES.BlockSize/8; CryptographicException : Padding is invalid and cannot be removed.
if (encrypt)
{
inputStream.CopyTo(cryptoStream);
// Not needed. Done by the Dispose()
//cryptoStream.FlushFinalBlock();
}
else
{
cryptoStream.CopyTo(outputStream);
}
}
}
然后删除现在没用的
protected ICryptoTransform CryptoTransform;
一般来说,加密和解密操作的处理完全不同......在很多地方参数都会发生变化。
另一个问题是阅读IV
:您无法直接读取IV
的{{1}}属性,您必须读取临时缓冲区({ {1}})然后将缓冲区分配给AesManaged
。
第三个问题:当您拥有bytes
和IV
并且知道是否要加密或解密时,您必须创建CryptoTransform
。
啊......并注意到你没有写纯文本 IV,因为IV不是文本,它是二进制文件。您正在以二进制格式(或以其原生格式......或任何您想要的方式)编写IV。除非使用明文,否则表示未加密的IV。然后是的,你正在编写它的明文版本。但仍然无法使用Key
对其进行编码,因为它不是" text" ...它是二进制数据。