繁体   English   中英

如何在IV前面加上AES密文

[英]How to prepend AES ciphertext with IV

似乎有一种约定,可以在AES加密文件的开头以明文形式存储IV。

在加密和解密过程中同时提供密钥和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);
    }        

有很多错误...正确的代码:

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 :您无法直接读入AesManagedIV属性,您必须读取一个临时缓冲区( bytes ),然后将缓冲区分配给IV

第三个问题:当您拥有KeyIV并且知道要加密还是解密时,必须创建CryptoTransform

啊...请注意,您不是在编写纯文本 IV,因为IV不是文本,而是二进制。 您正在以二进制格式(或以其本机格式...或任何您想调用的格式)编写IV。 除非是明文,否则是指未加密的IV。 然后,是的,您正在编写它的纯文本版本。 但是您仍然不能使用Encoding.UTF8对其进行Encoding.UTF8 ,因为它不是“文本” ...它是二进制数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM