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

时间:2017-11-04 09:52:50

标签: c# rsa rsacryptoserviceprovider

请先阅读此内容:

  • 我知道RSA不是为数据块加密而设计的。但它仍然有可能。
  • 在使用RSA加密数据块时,我了解安全性和性能损失。
  • 我不允许使用混合加密。因此,在我的案例中,以下步骤是不可接受的:
  
      
  1. 为对称算法生成随机密钥
  2.   
  3. 使用对称算法和随机密钥
  4. 加密数据   
  5. 使用您的公钥加密随机密钥,并在数据的下一个(或之前)以加密形式存储。
  6.   

但我必须通过各种方式完成给定的任务 感谢您的理解

我非常抽象和简化了这个例子,以便清楚地说明我正在努力解决的问题。

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。我还尝试将数据(文本),编码加密到 ASCII UTF8 。这也无济于事。

任何想法?(除了使用对称密钥切换到加密。如上所述,我不允许这样做。)

1 个答案:

答案 0 :(得分:1)

我稍微修改了(查找更改后的注释)你的代码,它可以工作:

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);
}