使用 C 尖锐的 RSA 对 128 字节的字节数组进行签名

本文关键字:字节 数组 字节数 RSA 使用 | 更新日期: 2023-09-27 17:58:53

我是密码学的新手,我需要用我用 C sharp 生成的 RSA 密钥对 128 字节的字节数组进行签名。密钥必须是 1024 位。

我找到了一些如何将RSA与C sharp一起使用的示例,我目前正在尝试使用的代码是:

public static void AssignParameter()
{
    const int PROVIDER_RSA_FULL = 1;
    const string CONTAINER_NAME = "SpiderContainer";
    CspParameters cspParams;
    cspParams = new CspParameters(PROVIDER_RSA_FULL);
    cspParams.KeyContainerName = CONTAINER_NAME;
    cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
    cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
    rsa = new RSACryptoServiceProvider(cspParams);
    rsa.KeySize = 1024;
}
public static string EncryptData(string data2Encrypt)
{
    AssignParameter();
    StreamReader reader = new StreamReader(path + "publickey.xml");
    string publicOnlyKeyXML = reader.ReadToEnd();
    rsa.FromXmlString(publicOnlyKeyXML);
    reader.Close();
    //read plaintext, encrypt it to ciphertext
    byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
    byte[] cipherbytes = rsa.Encrypt(plainbytes, false);
    return Convert.ToBase64String(cipherbytes);
}

这段代码适用于小字符串(因此是短字节数组(,但是当我尝试使用 128 个字符的字符串时,我收到一条错误消息:加密异常未处理:长度错误(好吧,它可能不会准确地说"错误的长度",我在丹麦语中得到错误,那就是"Forkert længde",直接翻译为"错误的长度"(。

谁能告诉我如何使用 C sharp 的 128 位 RSA 密钥加密 1024 字节的字节数组?

提前感谢,主耶稣

编辑:

好的,只是为了澄清一下:我有一条消息,我使用 SHA-256 从中创建一个哈希。这将给出一个 32 字节的数组。此数组使用自定义填充进行填充,因此它最终是一个 128 字节的数组。然后,应使用我的私钥对填充哈希进行签名,以便接收方可以使用我的公钥来验证收到的消息是否与发送的消息相同。这可以用 1024 位的密钥来完成吗?

使用 C 尖锐的 RSA 对 128 字节的字节数组进行签名

如果要签名,则不想加密。签名和加密是不同的算法。有一种众所周知的签名算法称为RSA,以及一种众所周知的非对称加密算法也称为RSA,并且签名算法首次呈现(并且仍然在很多地方(作为"您使用私钥加密",这无济于事。这简直令人困惑。

在 RSA 加密中,要加密的数据(使用公钥(必须使用 PKCS#1(RSA 标准(所描述的"类型 2 填充"进行填充,然后通过模块化幂处理结果(其长度与模数相同(,这是 RSA 的核心(在核心,但 RSA 不仅是模块化幂;填充对于安全性非常重要(。

签名

时,必须对要签名的数据进行哈希处理,然后将哈希值嵌入到描述刚刚使用的哈希函数的结构中,并且编码结构本身填充了"类型 1 填充" - 与加密填充不同,这也很重要。

无论哪种方式,普通的 RSA 引擎都会自行执行类型 1 或类型 2 填充,大多数 RSA 签名引擎也会自行处理标识所用哈希函数的结构。像RSACryptoServiceProvider这样的RSA签名引擎可以与SignHash()一起工作,它需要哈希值(从SHA-256获得的32个字节,没有任何封装结构或类型1填充 - RSACryptoServiceProvider处理它本身(,或者SignData(),它期望数据被签名(然后引擎也进行哈希计算(。

总而言之,如果你自己做任何类型的填充,那么你就做错了。如果您使用Encrypt()来计算签名,那么您也做错了。

当您

在关闭 OAEP 的情况下调用Encrypt时,加密 128 字节的最小密钥大小为 1112 位。 请注意,像这样设置密钥大小rsa.KeySize = 1024没有帮助,您需要实际生成正确大小的密钥并使用它们。

这是对我有用的:

using System;
using System.IO;
using System.Security.Cryptography;
namespace SO6299460
{
    class Program
    {
        static void Main()
        {
            GenerateKey();
            string data2Encrypt = string.Empty.PadLeft(128,'$');
            string encrypted = EncryptData(data2Encrypt);
            string decrypted = DecryptData(encrypted);
            Console.WriteLine(data2Encrypt);
            Console.WriteLine(encrypted);
            Console.WriteLine(decrypted);
        }
        private const string path = @"c:'";
        public static void GenerateKey()
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1112);
            string publickKey = rsa.ToXmlString(false);
            string privateKey = rsa.ToXmlString(true);
            WriteStringToFile(publickKey, path + "publickey.xml");
            WriteStringToFile(privateKey, path + "privatekey.xml");
        }
        public static void WriteStringToFile(string value, string filename)
        {
            using (FileStream stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read))
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(value);
                writer.Flush();
                stream.Flush();
            }
        }
        public static string EncryptData(string data2Encrypt)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            StreamReader reader = new StreamReader(path + "publickey.xml");
            string publicOnlyKeyXML = reader.ReadToEnd();
            rsa.FromXmlString(publicOnlyKeyXML);
            reader.Close();
            //read plaintext, encrypt it to ciphertext
            byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data2Encrypt);
            byte[] cipherbytes = rsa.Encrypt(plainbytes,false);
            return Convert.ToBase64String(cipherbytes);
        }
        public static string DecryptData(string data2Decrypt)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            StreamReader reader = new StreamReader(path + "privatekey.xml");
            string key = reader.ReadToEnd();
            rsa.FromXmlString(key);
            reader.Close();
            byte[] plainbytes = rsa.Decrypt(Convert.FromBase64String(data2Decrypt), false);
            return System.Text.Encoding.UTF8.GetString(plainbytes);
        }

    }
}

但是请注意,我没有使用加密容器,因此,我不需要您的AssignParameter,但是如果您需要使用它,修改代码应该很容易。

如果您需要加密大量数据(远大于 128 字节(,本文提供了有关如何执行此操作的示例代码。

显然,根据这个问题——如何在C#中使用RSA加密文件(大量数据(——RSA只能加密短于其密钥长度的数据。

奇怪。MSDN 文档 for'RSACryptoServiceProvider.Encrypt(( 说,如果 rgb 参数的长度大于允许的最大长度,则可能会抛出 CryptographicException。

井。这似乎很奇怪,特别是因为似乎没有太多关于所述最大值的文档。

再进一步挖掘一下,在备注下有这个:

下表描述了不同版本支持的填充 Microsoft 个窗口和不同允许的最大 RGB 长度 操作系统和填充的组合。

  • 如果您运行的是 XP 或更高版本,并且使用的是 OAEP 填充,则限制声明

    模量大小 -2 -2*hLen,其中 hLen 是哈希的大小

    不知道"哈希

    的大小"可能是多少,因为文档AFAICS除了数字签名之外,在任何地方都没有提到"哈希"。

  • 如果您运行的是安装了"高加密包"的Windows 2000或更高版本(同样,不知道您是如何发现的(,则限制为:

    模量大小 - 11。(11 字节是可能的最小填充。

  • 否则(Windows 98,Millenium或Windows 2000或更高版本没有上述"高加密包",则您将获得"不支持直接加密和OAEP填充",其中限制是

    对称密钥允许的最大大小。

    说。。。等一下。。。RSA是一种非对称算法,对吧?

毫无价值的文档。希什。

请参阅 http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt.aspx。引发的异常可能是"rgb 参数的长度大于允许的最大长度"。

通常 RSA 加密具有填充,并且由于加密的数据大小与密钥大小相同,因此没有填充空间。尝试使用更长的密钥或更小的数据大小进行加密。

你真的需要自定义填充吗?如果没有,你可以使用 RSACryptoServiceProvider.SignData Method