加密大于 RSA 密钥(模数)大小的数据。将拆分数据加密成块,似乎不起作用。有任何想法吗?
Encrypting data larger than the RSA key (modulus) size. Encryption of splitted data into chunks, seems not to be working. Any ideas?
请先阅读此内容:
- 我知道 RSA 不是为数据块加密而设计的。但还是有可能的。
- 我知道使用 RSA 加密数据块时的安全性和性能损失。
- 我不允许使用混合加密。因此,在我的情况下,以下步骤是不可接受的:
- Generate random key for symmetric algorithm
- Encrypt the data using symmetric algorithm and the random key
- Encrypt the random key using your public key and store it in the encrypted form next (or before) the data.
但我必须完成任务。 感谢理解.
我极大地抽象和简化了示例,以阐明我正在努力解决的问题。
string data = "message 700-1300 letters long";
byte[] bytes = data.ToUtf8EncodedByteArray();
// I'm splitting utf8 encoded bytes into chunks of 32 bytes each.
IEnumerable<IEnumerable<byte>> batches = bytes.ChunkBy(32);
LinkedList<byte[]> encryptedChunks = new LinkedList<byte[]>();
LinkedList<byte[]> decryptedChunks = new LinkedList<byte[]>();
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false;
_publicKey = rsa.ExportParameters(false);
_privateKey = rsa.ExportParameters(true);
rsa.ImportParameters(_publicKey);
byte[] encryptedBatch = null;
foreach (IEnumerable<byte> batch in batches)
{
encryptedBatch = rsa.Encrypt(batch.ToArray(), true);
encryptedChunks.AddLast(encryptedBatch);
}
// Then encryptedChunks.ToArray() will be send over the network
// When encrypted bytes are received at another endpoint, they have to be decrypted.
rsa.ImportParameters(_privateKey);
byte[] decryptedBatch = null;
foreach (byte[] chunk in encryptedChunks)
{
decryptedBatch = rsa.Decrypt(chunk, true);
decryptedChunks.AddLast(chunk);
}
}
// After decryption of each encrypted chunk of data, I project it back into an array of bytes.
byte[] decrypted = decryptedChunks.SelectMany(chunk => chunk).ToArray();
// When trying to display decoded bytes as a string (as it was initially), instead of original message I get hieroglyphs.
Console.Out.WriteLine($"Decrypted message: {decrypted.ToUtf8String()}");
以下是扩展方法(在我的代码中使用),如果需要的话:
public static IEnumerable<IEnumerable<TElement>> ChunkBy<TElement>(
this IEnumerable<TElement> source, int chunkSize)
{
return source
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / chunkSize)
.Select(x => x.Select(v => v.Value).ToArray())
.ToArray();
}
public static byte[] ToUtf8EncodedByteArray(this string source)
{
return Encoding.UTF8.GetBytes(source.ToCharArray());
}
public static string ToUtf8String(this byte[] sourceBytes)
{
return Encoding.UTF8.GetString(sourceBytes);
}
P.S。我也试过在加密数据(文本)之前,encoding它变成ASCII,而不是的UTF8。这也没有帮助。
有什么想法吗?(除了切换到使用对称密钥加密。正如我上面提到的,我不允许这样做。)
我稍微修改了您的代码(查找更改后的注释),它有效:
public static IEnumerable<IEnumerable<TElement>> ChunkBy<TElement>(this IEnumerable<TElement> source, int chunkSize)
{
return source
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / chunkSize)
.Select(x => x.Select(v => v.Value).ToArray())
.ToArray();
}
public static byte[] ToUtf8EncodedByteArray(this string source)
{
// Changed: instead of source.ToCharArray() use source directly
return Encoding.UTF8.GetBytes(source);
}
public static string ToUtf8String(this byte[] sourceBytes)
{
return Encoding.UTF8.GetString(sourceBytes);
}
[STAThread]
public static void Main()
{
// Changed: Generate some sample data...
string data = string.Join(string.Empty, Enumerable.Repeat<string>("abcdefghijklmnopqrstuvwxyz0123456789<>!?", 100));
byte[] bytes = data.ToUtf8EncodedByteArray();
// I'm splitting utf8 encoded bytes into chunks of 32 bytes each.
IEnumerable<IEnumerable<byte>> batches = bytes.ChunkBy(32);
LinkedList<byte[]> encryptedChunks = new LinkedList<byte[]>();
LinkedList<byte[]> decryptedChunks = new LinkedList<byte[]>();
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false;
var _publicKey = rsa.ExportParameters(false);
var _privateKey = rsa.ExportParameters(true);
rsa.ImportParameters(_publicKey);
byte[] encryptedBatch = null;
foreach (IEnumerable<byte> batch in batches)
{
encryptedBatch = rsa.Encrypt(batch.ToArray(), true);
encryptedChunks.AddLast(encryptedBatch);
}
rsa.ImportParameters(_privateKey);
byte[] decryptedBatch = null;
foreach (byte[] chunk in encryptedChunks)
{
decryptedBatch = rsa.Decrypt(chunk, true);
// Changed (critical): instead of chunk (the encrypted data) use the decrypted data
decryptedChunks.AddLast(decryptedBatch);
}
}
// After decryption of each encrypted chunk of data, I project it back into an array of bytes.
byte[] decrypted = decryptedChunks.SelectMany(chunk => chunk).ToArray();
var data2 = decrypted.ToUtf8String();
// Changed: Verify that input and output are the same
var equals = data.Equals(data2);
}
请先阅读此内容:
- 我知道 RSA 不是为数据块加密而设计的。但还是有可能的。
- 我知道使用 RSA 加密数据块时的安全性和性能损失。
- 我不允许使用混合加密。因此,在我的情况下,以下步骤是不可接受的:
- Generate random key for symmetric algorithm
- Encrypt the data using symmetric algorithm and the random key
- Encrypt the random key using your public key and store it in the encrypted form next (or before) the data.
但我必须完成任务。 感谢理解.
我极大地抽象和简化了示例,以阐明我正在努力解决的问题。
string data = "message 700-1300 letters long";
byte[] bytes = data.ToUtf8EncodedByteArray();
// I'm splitting utf8 encoded bytes into chunks of 32 bytes each.
IEnumerable<IEnumerable<byte>> batches = bytes.ChunkBy(32);
LinkedList<byte[]> encryptedChunks = new LinkedList<byte[]>();
LinkedList<byte[]> decryptedChunks = new LinkedList<byte[]>();
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false;
_publicKey = rsa.ExportParameters(false);
_privateKey = rsa.ExportParameters(true);
rsa.ImportParameters(_publicKey);
byte[] encryptedBatch = null;
foreach (IEnumerable<byte> batch in batches)
{
encryptedBatch = rsa.Encrypt(batch.ToArray(), true);
encryptedChunks.AddLast(encryptedBatch);
}
// Then encryptedChunks.ToArray() will be send over the network
// When encrypted bytes are received at another endpoint, they have to be decrypted.
rsa.ImportParameters(_privateKey);
byte[] decryptedBatch = null;
foreach (byte[] chunk in encryptedChunks)
{
decryptedBatch = rsa.Decrypt(chunk, true);
decryptedChunks.AddLast(chunk);
}
}
// After decryption of each encrypted chunk of data, I project it back into an array of bytes.
byte[] decrypted = decryptedChunks.SelectMany(chunk => chunk).ToArray();
// When trying to display decoded bytes as a string (as it was initially), instead of original message I get hieroglyphs.
Console.Out.WriteLine($"Decrypted message: {decrypted.ToUtf8String()}");
以下是扩展方法(在我的代码中使用),如果需要的话:
public static IEnumerable<IEnumerable<TElement>> ChunkBy<TElement>(
this IEnumerable<TElement> source, int chunkSize)
{
return source
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / chunkSize)
.Select(x => x.Select(v => v.Value).ToArray())
.ToArray();
}
public static byte[] ToUtf8EncodedByteArray(this string source)
{
return Encoding.UTF8.GetBytes(source.ToCharArray());
}
public static string ToUtf8String(this byte[] sourceBytes)
{
return Encoding.UTF8.GetString(sourceBytes);
}
P.S。我也试过在加密数据(文本)之前,encoding它变成ASCII,而不是的UTF8。这也没有帮助。
有什么想法吗?(除了切换到使用对称密钥加密。正如我上面提到的,我不允许这样做。)
我稍微修改了您的代码(查找更改后的注释),它有效:
public static IEnumerable<IEnumerable<TElement>> ChunkBy<TElement>(this IEnumerable<TElement> source, int chunkSize)
{
return source
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / chunkSize)
.Select(x => x.Select(v => v.Value).ToArray())
.ToArray();
}
public static byte[] ToUtf8EncodedByteArray(this string source)
{
// Changed: instead of source.ToCharArray() use source directly
return Encoding.UTF8.GetBytes(source);
}
public static string ToUtf8String(this byte[] sourceBytes)
{
return Encoding.UTF8.GetString(sourceBytes);
}
[STAThread]
public static void Main()
{
// Changed: Generate some sample data...
string data = string.Join(string.Empty, Enumerable.Repeat<string>("abcdefghijklmnopqrstuvwxyz0123456789<>!?", 100));
byte[] bytes = data.ToUtf8EncodedByteArray();
// I'm splitting utf8 encoded bytes into chunks of 32 bytes each.
IEnumerable<IEnumerable<byte>> batches = bytes.ChunkBy(32);
LinkedList<byte[]> encryptedChunks = new LinkedList<byte[]>();
LinkedList<byte[]> decryptedChunks = new LinkedList<byte[]>();
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false;
var _publicKey = rsa.ExportParameters(false);
var _privateKey = rsa.ExportParameters(true);
rsa.ImportParameters(_publicKey);
byte[] encryptedBatch = null;
foreach (IEnumerable<byte> batch in batches)
{
encryptedBatch = rsa.Encrypt(batch.ToArray(), true);
encryptedChunks.AddLast(encryptedBatch);
}
rsa.ImportParameters(_privateKey);
byte[] decryptedBatch = null;
foreach (byte[] chunk in encryptedChunks)
{
decryptedBatch = rsa.Decrypt(chunk, true);
// Changed (critical): instead of chunk (the encrypted data) use the decrypted data
decryptedChunks.AddLast(decryptedBatch);
}
}
// After decryption of each encrypted chunk of data, I project it back into an array of bytes.
byte[] decrypted = decryptedChunks.SelectMany(chunk => chunk).ToArray();
var data2 = decrypted.ToUtf8String();
// Changed: Verify that input and output are the same
var equals = data.Equals(data2);
}