C# AES 和 RSA 文件加密 - 如何使用 IV?
C# AES and RSA File Encryption - How to use IV?
我目前正在编写一个在以下情况下工作的程序:
- 我有一些机密日志文件需要备份到服务器。
- 我有一个每天生成这些日志文件的程序。
- 这些日志文件很少需要打开。
- 我只有一个 RSA public/private 密钥对。
- 该程序只有 RSA public 密钥。
- 每次程序生成这些机密文件之一时,我都会生成一个 运行dom AES 密钥。
- 程序使用此 AES 密钥加密日志文件。
- 然后我使用 RSA public 密钥来加密 AES 密钥
- 然后我将 AES 加密文件和 RSA 加密的 AES 密钥都备份到服务器。
据我了解,该协议适合我的用例。
我遇到的问题是用 C# 编写代码。我 运行 需要一个初始化向量 (IV) 用于我的 AES 加密,我试图通过在两者上使用 public RSA 密钥来加密它和 AES 密钥。但是 512(2 * 256) 大小大于 RSA 乐于加密的大小。所以我想通了,因为我每次都创建初始化向量 运行domly 就像 AES 密钥一样,我可以将 IV 添加到 AES 密文的前面。但是,我不确定执行此操作的代码将插入到我的函数中的何处
任何在 "protocol" 的正确方向上的帮助或其他将 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
并将数据复制到新的更容易内存流。
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();
}
}
}
}
}
对于其他读者,请注意 RSAEncrypt
和 RSADecrypt
是对 RSACryptoServiceProvider
.
调用的包装器
我目前正在编写一个在以下情况下工作的程序:
- 我有一些机密日志文件需要备份到服务器。
- 我有一个每天生成这些日志文件的程序。
- 这些日志文件很少需要打开。
- 我只有一个 RSA public/private 密钥对。
- 该程序只有 RSA public 密钥。
- 每次程序生成这些机密文件之一时,我都会生成一个 运行dom AES 密钥。
- 程序使用此 AES 密钥加密日志文件。
- 然后我使用 RSA public 密钥来加密 AES 密钥
- 然后我将 AES 加密文件和 RSA 加密的 AES 密钥都备份到服务器。
据我了解,该协议适合我的用例。
我遇到的问题是用 C# 编写代码。我 运行 需要一个初始化向量 (IV) 用于我的 AES 加密,我试图通过在两者上使用 public RSA 密钥来加密它和 AES 密钥。但是 512(2 * 256) 大小大于 RSA 乐于加密的大小。所以我想通了,因为我每次都创建初始化向量 运行domly 就像 AES 密钥一样,我可以将 IV 添加到 AES 密文的前面。但是,我不确定执行此操作的代码将插入到我的函数中的何处
任何在 "protocol" 的正确方向上的帮助或其他将 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
并将数据复制到新的更容易内存流。
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();
}
}
}
}
}
对于其他读者,请注意 RSAEncrypt
和 RSADecrypt
是对 RSACryptoServiceProvider
.