加密大于 RSA 密钥(模数)大小的数据。将拆分数据加密成块,似乎不起作用。有任何想法吗?

Encrypting data larger than the RSA key (modulus) size. Encryption of splitted data into chunks, seems not to be working. Any ideas?

请先阅读此内容:

  1. Generate random key for symmetric algorithm
  2. Encrypt the data using symmetric algorithm and the random key
  3. 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);
}