使用 RSACryptoServiceProvider (C#) 可以 encrypted/decrypted 的各种字符串的 "limit" 是什么?

What is the "limit" to the variety of strings that can be encrypted/decrypted using RSACryptoServiceProvider (C#)?

以下是我自己实现的Rsa加解密方法,我自己参考了微软的文档

https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsacryptoserviceprovider?redirectedfrom=MSDN&view=net-6.0

public string Encrypt(string plainText)
{
    rsaCsp.ImportParameters(publicKey);

    byte[] data = Encoding.UTF8.GetBytes(plainText);
    byte[] cypher = rsaCsp.Encrypt(data, fOAEP: true);

    string cypherText = Convert.ToBase64String(cypher);

    return cypherText;
}

public string Decrypt(string cypherText)
{
    rsaCsp.ImportParameters(privateKey);

    byte[] data = Convert.FromBase64String(cypherText);
    byte[] decrypted = rsaCsp.Decrypt(data, fOAEP: true);

    string plainText = Encoding.UTF8.GetString(decrypted);

    return plainText;
}

我正在注入密钥和提供程序,以便我可以重复使用特定的密钥,这样我什至可以解密在程序的其他执行中加密的字符串。 (示例:我在一个测试中加密并保存在数据库中,在另一个测试中我在数据库中搜索加密的字符串并解密)。如果我允许 public 和私钥自动生成,这种行为就不可能发生。

private readonly RSAParameters privateKey;
private readonly RSAParameters publicKey;

private readonly RSACryptoServiceProvider rsaCsp;

public RsaCryptoService(
    RSACryptoServiceProvider rsaCsp,
    RSAParameters privateKey,
    RSAParameters publicKey)
{
    this.rsaCsp = rsaCsp;
    this.privateKey = privateKey;
    this.publicKey = publicKey;
}

下面是依赖的构建:

public static void InjectRsaCryptoService(this IServiceCollection services, string userName = "default", int keySize = 2048)
        {
            Services = services;

            RsaKeyPair rsaKeyPair = SecuritySettings.RsaKeys.SingleOrDefault(p => p.UserName == userName);
            if (rsaKeyPair == null)
                throw new lsilvpin_securityException(
                    $"O usuário {userName} não está autorizado a utilizar as ferramentas de segurança.");

            RSAParameters privateKey = rsaKeyPair.PrivateKey.AsParameter();
            RSAParameters publicKey = rsaKeyPair.PublicKey.AsParameter();

            RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(keySize);

            rsaCsp.ImportParameters(publicKey);
            rsaCsp.ImportParameters(privateKey);

            Services.AddTransient(sp =>
            {
                IRsaCryptoService rsa = new RsaCryptoService(rsaCsp, privateKey, publicKey);

                return rsa;
            });
        }

起初我认为它工作正常,但为了安全,我决定进行性能测试,发送随机字符串进行加密和解密。

这是我的性能测试:

[Fact]
public void TestRsaCryptionPerformance()
{
    for (int i = 0; i < 1000; i++)
    {
        var plainText = RandomWordGenerator.Next(new RandomWordParameters(WordMaxLength: 495)) + "@eA8";

        IRsaCryptoService rsa = Services
        .BuildServiceProvider()
        .GetRequiredService<IRsaCryptoService>();

        string publicKey = rsa.GetPublicKey();
        string cypherText = rsa.Encrypt(plainText);
        string decrypted = rsa.Decrypt(cypherText);

        Assert.True(!string.IsNullOrWhiteSpace(publicKey));
        Assert.True(!string.IsNullOrWhiteSpace(cypherText));
        Assert.True(!string.IsNullOrWhiteSpace(decrypted));
        Assert.True(plainText.Equals(decrypted));

        Debug.WriteLine($"PublicKey: {publicKey}");
        Debug.WriteLine($"CypherText: {cypherText}");
        Debug.WriteLine($"Decrypted: {decrypted}");
    }
}

我使用以下方法生成大小在 100 到 499 之间的随机单词:

public static string Next(RandomWordParameters? randomWordParameters = null)
        {
            randomWordParameters ??= new RandomWordParameters();
            if (randomWordParameters.CharLowerBound <= 0 || randomWordParameters.CharUpperBound <= 0)
                throw new RandomGeneratorException("Os limites inferior e superior devem ser positivos.");

            if (randomWordParameters.CharLowerBound >= randomWordParameters.CharUpperBound)
                throw new RandomGeneratorException("O limite inferior deve ser menor do que o limite superior.");

            var rd_char = new Random();
            var rd_length = new Random();
            var wordLength = rd_length.Next(randomWordParameters.WordMinLength, randomWordParameters.WordMaxLength);
            var sb = new StringBuilder();
            int sourceNumber;
            for (int i = 0; i < wordLength; i++)
            {
                sourceNumber = rd_char.Next(randomWordParameters.CharLowerBound, randomWordParameters.CharUpperBound);
                sb.Append(Convert.ToChar(sourceNumber));
            }
            var word = sb.ToString();
            return word;
        }

注意:我使用通过将 33 到 126 之间的整数传递给 Convert.ToChar(int) 方法获得的字符。

当我运行一个1000个随机单词的循环时,我总能找到下面抛出异常的一个:

Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException:'Comprimento inválido.'(无效长度)

被测字符串:a_BdH[(4/6-9m>,9a_J/^t2GCsxo{{W#j*!R![h;TMi/42Yw7Z0yWOb3f15&P:NEI7!vTFm8W.5Q1,d?I9DR>u{M0,$YxP1Cd]MC(gnd$){x[`@L9C7E>z()PS,>w :|?<|j3!KCkC%usV']958^}a2P(SHun'=VR?^qLcj_1nu"UUR|Bu{UlP =mEJ0RIJP#9O$a^g7&I|Q^]_pG0!h} RjiEu_Df8*(@eA8

我想在我正在实施的系统上使用 RSA 加密,但这个测试让我不确定。有人知道这个问题是从哪里来的吗?

注意:encrypt/decrypt 方法可以完美地处理更小、更简单的字符串。 (密码模拟长度可达 20 左右,从弱密码到非常强的密码)

根据 Klaus Gütte 和 Topaco 的评论,我对回复感到满意!

问题是由输入字符串的大小引起的,输入的限制也是根据克劳斯链接的问题输入的大小,这个大小取决于为加密密钥配置的大小Topaco 提到了!

Link 引起澄清:System.Security.Cryptography.CryptographicException : Bad length in RSACryptoserviceProvider

Link 澄清输入大小限制:https://crypto.stackexchange.com/questions/42097/what-is-the-maximum-size-of-the-plaintext-message-for-rsa-oaep/42100# 42100

更具体地说:https://www.rfc-editor.org/rfc/rfc8017#section-7.1.1

打印 RSAES-OAEP-ENCRYPT 标准

在我的特定情况下,encrypt/decrypt 方法接受的字符串的最大长度为 214(长度)。使用 100k 随机字符串进行测试,效果非常好!但是,传递一个字符串大小 >= 215 已经生成“Bad length”异常。

成功,长度 <= 214

215 失败

非常感谢大家的帮助!!