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

Posted

技术标签:

【中文标题】加密大于 RSA 密钥(模数)大小的数据。将拆分的数据加密成块,似乎不起作用。有任何想法吗?【英文标题】:Encrypting data larger than the RSA key (modulus) size. Encryption of splitted data into chunks, seems not to be working. Any ideas? 【发布时间】:2017-11-04 09:52:49 【问题描述】:

请先阅读:

我知道 RSA 不是为数据块加密而设计的。但这仍然是可能的。 我知道使用 RSA 加密数据块时的安全性和性能损失。 我不允许使用混合加密。因此,在我的情况下,以下步骤是不可接受的:
    为对称算法生成随机密钥 使用对称算法和随机密钥加密数据 使用您的公钥加密随机密钥,并将其以加密形式存储在数据的旁边(或之前)。

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

我对示例进行了极大的抽象和简化,以明确我正在努力解决的问题。

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


附:在加密数据(文本)之前,我也尝试过将其编码ASCII而不是 UTF8。这也没有帮助。

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

【问题讨论】:

【参考方案1】:

我对您的代码稍作修改(查找更改的 cmets),它可以工作:

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加密输出大小

RSA - 仅使用(!)模数加密?

从javascript中的模数字符串获取RSA密钥大小

密码疑云 ——详解RSA的加密与解密

RSA 密钥私有指数大小

Android Studio/Java - 具有小输入/输出大小的 RSA 加密