簡體   English   中英

C# AES 和 RSA 文件加密 - 如何使用 IV?

[英]C# AES and RSA File Encryption - How to use IV?

我正在編寫一個程序,它可以在以下情況下工作:

  • 我有一些需要備份到服務器的機密日志文件。
  • 我有一個程序每天都會生成這些日志文件。
  • 這些日志文件很少需要打開。
  • 我只有一個 RSA 公鑰/私鑰對。
  • 該程序只有 RSA 公鑰。
  • 每次程序制作這些機密文件之一時,我都會生成一個隨機的 AES 密鑰。
  • 該程序使用此 AES 密鑰來加密日志文件。
  • 然后我使用 RSA 公鑰來加密 AES 密鑰
  • 然后我將 AES 加密文件和 RSA 加密的 AES 密鑰備份到服務器。

據我了解,該協議適合我的用例。

我遇到的問題是用 C# 編碼。 我遇到了 AES 加密需要初始化向量 (IV) 的情況,我嘗試通過在兩者上使用公共 RSA 密鑰來將其與 AES 密鑰一起加密。 但是 512(2 * 256) 大小比 RSA 樂於加密的要大。 所以我想,既然我每次都像 AES 密鑰一樣隨機創建初始化向量,我可以將 IV 添加到 AES 密文的前面。 但是,我不確定在我的函數中執行此操作的代碼的位置

任何對“協議”或其他將 IV 寫入密文的方法的正確方向的幫助都會很棒。 先感謝您。

static public Tuple<byte[], byte[]> EncryptAES(byte[] toEncryptAES, RSAParameters RSAPublicKey)
    {
        byte[] encryptedAES = null;
        byte[] encryptedRSA = null;

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                AES.KeySize = 256;
                AES.BlockSize = 128;
                AES.Mode = CipherMode.CBC;
                AES.GenerateIV();
                AES.GenerateKey();
                encryptedRSA = RSAEncrypt(AES.Key, RSAPublicKey);

                using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    ms.Write(AES.IV, 0, AES.KeySize); //DOESNT WORK HERE
                    //Can't use CS to write it to the stream else it will encrypt along with file
                    cs.Write(toEncryptAES, 0, toEncryptAES.Length);
                    cs.Close();
                }
                encryptedAES = ms.ToArray();
            }
        }
        return new Tuple<byte[], byte[]>(encryptedAES, encryptedRSA);
    }
    static public byte[] DecryptAES(byte[] toDecryptAES, byte[] AESKeyAndIV, RSAParameters RSAPrivateKey)
    {
        byte[] AESKey = RSADecrypt(AESKeyAndIV, RSAPrivateKey);

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                AES.KeySize = 256;
                AES.BlockSize = 128;
                AES.Key = AESKey;
                ms.Read(AES.IV, 0, AES.KeySize); //Not sure if can read MS here
                AES.Mode = CipherMode.CBC;

                using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    //Would I need to move 0 to 256?
                    cs.Write(toDecryptAES, 0, toDecryptAES.Length);
                    cs.Close();
                }
                return ms.ToArray();
            }
        }
    }

您非常接近,請在創建 CryptoStream 之前寫出 IV

static public Tuple<byte[], byte[]> EncryptAES(byte[] toEncryptAES, RSAParameters RSAPublicKey)
{
    byte[] encryptedAES = null;
    byte[] encryptedRSA = null;

    using (MemoryStream ms = new MemoryStream())
    {
        using (RijndaelManaged AES = new RijndaelManaged())
        {
            AES.KeySize = 256;
            AES.BlockSize = 128;
            AES.Mode = CipherMode.CBC;
            AES.GenerateIV();
            AES.GenerateKey();
            encryptedRSA = RSAEncrypt(AES.Key, RSAPublicKey);

            ms.Write(AES.IV, 0, AES.KeySize); //Move the write here.

            using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(toEncryptAES, 0, toEncryptAES.Length);
                cs.Close();
            }
            encryptedAES = ms.ToArray();
        }
    }
    return new Tuple<byte[], byte[]>(encryptedAES, encryptedRSA);
}

對於解密,請確保循環讀取直到您完全讀取了 IV 的 byte[], Stream.Read不能保證讀取您要求它讀取的所有字節。 我通常會創建一個靜態方法ReadFully來確保讀取所有字節。

private static byte[] ReadFully(Stream stream, int length)
{
    int offset = 0;
    byte[] buffer = new byte[length];
    while(offset < length)
    {
        offset += stream.Read(buffer, offset, length - offset);
    }
    return buffer;
}

然后只需使用該方法讀取IV。 您還想使用cs.Read而不是cs.Write來讀出加密數據並將流置於讀取模式,但是使用.CopyTo並將數據復制到新的 MemoryStream 會更容易。

static public byte[] DecryptAES(byte[] toDecryptAES, byte[] AESKeyAndIV, RSAParameters RSAPrivateKey)
{
    byte[] AESKey = RSADecrypt(AESKeyAndIV, RSAPrivateKey);

    using (MemoryStream source = new MemoryStream(toDecryptAES))
    {
        using (RijndaelManaged AES = new RijndaelManaged())
        {
            AES.KeySize = 256;
            AES.BlockSize = 128;
            AES.Key = AESKey;
            var iv = ReadFully(source, AES.KeySize);
            AES.IV = iv;
            AES.Mode = CipherMode.CBC;

            using (var cs = new CryptoStream(source, AES.CreateDecryptor(), CryptoStreamMode.Read))
            {
                using(var dest = new MemoryStream())
                {
                    cs.CopyTo(dest);
                    return dest.ToArray();
                }
            }
        }
    }
}

對於其他讀者,請注意RSAEncryptRSADecrypt是調用RSACryptoServiceProvider包裝器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM