在 C Sharp 中使用 RSA 对 128 字节的字节数组进行签名

发布于 2024-11-14 15:32:12 字数 1546 浏览 1 评论 0原文

我对密码学完全陌生,我需要使用我用 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 的字符串时我收到一条错误消息: CryptographicException 未处理:长度错误 (好吧,它可能不准确地说“长度错误”,我得到丹麦语的错误,那就是“Forkert længde”,它直接翻译为“长度错误”)。

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

提前致谢, LordJesus

编辑:

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

I am completely new to cryptography and I need to sign a byte array of 128 bytes with an RSA key i have generated with C sharp. The key must be 1024 bits.

I have found a few examples of how to use RSA with C sharp and the code I'm currently trying to use is:

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

This code works fine with small strings (and thus short byte arrays) but when I try this with a string of 128 characters I get an error saying:
CryptographicException was unhandled: Wrong length
(OK, it might not precisely say 'Wrong length', I get the error in danish, and that is 'Forkert længde' which directly translates to 'Wrong length').

Can anyone tell me how I can encrypt a byte array of 128 bytes with a RSA key of 1024 bits in C sharp?

Thanks in advance,
LordJesus

EDIT:

Ok, just to clarify things a bit: I have a message, from which i make a hash using SHA-256. This gives a 32 byte array. This array is padded using a custom padding, so it ends up being a 128 byte array. This padded hash should then be signed with my private key, so the receiver can use my public key to verify that the message received is the same as the message sent. Can this be done with a key of 1024 bits?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

少女七分熟 2024-11-21 15:32:12

如果您想签名,您就不想加密。签名和加密是不同的算法。更糟糕的是,有一种著名的签名算法称为 RSA,还有一种著名的非对称加密算法也称为 RSA,并且该签名算法最初提出(并且仍然在许多地方)为“您使用私钥”。这简直令人困惑。

在 RSA 加密中,要加密的数据(使用公钥)必须用 填充PKCS#1(RSA 标准)将其描述为“Type 2 padding”,然后将结果(其长度与模数相同)通过 RSA 核心的模幂运算进行处理(在核心,但 RSA 不仅仅是模幂;填充对于安全性非常重要)。

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

无论哪种方式,普通的 RSA 引擎都会自行执行类型 1 或类型 2 填充,并且大多数 RSA 签名引擎也会自行处理标识所使用的哈希函数的结构。 RSA 签名引擎(例如 RSACryptoServiceProvider)可以与 SignHash() 配合使用,后者需要哈希值(从 SHA-256 获取的 32 字节,没有) em> 任何类型的封装结构或类型 1 填充 - RSACryptoServiceProvider 自行处理),或 SignData(),它期望数据被签名(然后引擎也会进行哈希计算)。

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

If you want to sign you do not want to encrypt. Signatures and encryption are distinct algorithms. It does not help that there is a well-known signature algorithm called RSA, and a well-known asymmetric encryption algorithm also called RSA, and that the signature algorithm was first presented (and still is in many places) as "you encrypt with the private key". This is just plain confusing.

In RSA encryption, the data to encrypt (with the public key) must be padded with what PKCS#1 (the RSA standard) describes as "Type 2 padding", and the result (which has the same length than the modulus) is then processed through the modular exponentiation which is at the core of RSA (at the core, but RSA is not only a modular exponentiation; the padding is very important for security).

When signing, the data to sign must be hashed, then the hash value is embedded in a structure which describes the hash function which was just used, and the encoded structure is itself padded with a "Type 1 padding" -- not the same padding than the padding for encryption, and that's important, too.

Either way, a normal RSA engine will perform the type 1 or type 2 padding itself, and most RSA signature engines will also handle themselves the structure which identifies the used hash function. A RSA signature engine such as RSACryptoServiceProvider can work either with SignHash(), which expects the hash value (the 32 bytes obtained from SHA-256, without any kind of encapsulating structure or type 1 padding -- RSACryptoServiceProvider handles that itself), or SignData(), which expects the data to be signed (the engine then does the hash computation too).

To sum up, if you do any kind of padding yourself, then you are doing it wrong. If you used Encrypt() to compute a signature, then you are doing it wrong, too.

蓝眸 2024-11-21 15:32:12

当您在 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,'

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

如果您需要加密大量数据(远大于 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 字节)本文 提供了有关如何执行此操作的示例代码。

The minimum key size for encrypting 128 bytes would be 1112 bits, when you are calling Encrypt with OAEP off. Note that setting the key size like this rsa.KeySize = 1024 won't help, you need to actually generate they key of the right size and use them.

This is what worked for me:

using System;
using System.IO;
using System.Security.Cryptography;

namespace SO6299460
{
    class Program
    {
        static void Main()
        {
            GenerateKey();
            string data2Encrypt = string.Empty.PadLeft(128,'

Note however, that I'm not using a crypto container, and thus, I don't need your AssignParameter, but if you need to use it, modifying the code should be easy enough.

If you ever need to encrypt large quantities of data (much larger than 128 bytes) this article has sample code on how to do this.

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

Note however, that I'm not using a crypto container, and thus, I don't need your AssignParameter, but if you need to use it, modifying the code should be easy enough.

If you ever need to encrypt large quantities of data (much larger than 128 bytes) this article has sample code on how to do this.

悲凉≈ 2024-11-21 15:32:12

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

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

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

进一步挖掘一下,在备注下有这样的内容:

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

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

    <块引用>

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

    不知道“散列的大小”可能是多少,因为文档,AFAICS,除了数字签名之外,没有在任何地方提到“散列”。

  • 如果您运行的是 Windows 2000 或更高版本,并且安装了“高加密包”(同样,不知道您是如何发现这一点的),则该限制规定为

    <块引用>

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

  • 否则(Windows 98、Millenium 或 Windows 2000 或更高版本,没有上述“高加密包”,那么您会得到“不支持直接加密和 OAEP 填充”,限制在哪里

    <块引用>

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

    说...等一下...RSA 是一种非对称算法,对吗?

无价值的文档。谢什。

Apparently, according to this question — how to use RSA to encrypt files (huge data) in C# — RSA can only encrypt data shorter than its key length.

Bizarre. The MSDN docs for`RSACryptoServiceProvider.Encrypt() say that a CryptographicException may be thrown if the length of the rgb parameter is greater than the maximum allowed length.

Well. That seems odd, especially since there doesn't seem to be much in the way of documentation regarding said maximum.

A little further digging, under Remarks has this:

The following table describes the padding supported by different versions
of Microsoft Windows and the maximum length of rgb allowed by the different
combinations of operating systems and padding.

  • If you are running XP or later and you're using OAEP padding, then the limit is stated to be

    Modulus size -2 -2*hLen, where hLen is the size of the hash

    No idea what the "size of the hash" might be, since the docs, AFAICS, don't mention "hash" anywhere except in regards to digital signatures.

  • If you are running Windows 2000 or later with the "high encryption pack" installed (again, no idea how you find that out), then the limit is stated to be

    Modulus size - 11. (11 bytes is the minimum padding possible.)

  • Otherwise (Windows 98, Millenium or Windows 2000 or later without the aforementioned "high encryption pack" then you get "Direct Encryption and OAEP padding not supported", where the limitation is

    The maximum size allowed for a symmetric key.

    Say...wait a second... RSA is an asymmetric algorithm, right?

Worthless documentation. Sheesh.

太傻旳人生 2024-11-21 15:32:12

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

See http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt.aspx. The exception thrown is probably "The length of the rgb parameter is greater than the maximum allowed length."

花之痕靓丽 2024-11-21 15:32:12

通常RSA加密有填充,并且由于您的加密数据大小达到密钥大小,因此没有填充空间。尝试使用较长的密钥或较小的数据大小进行加密。

Usually RSA encryption has padding, and since your encrypted data size goes to the key size, there is no space for padding. Try to use longer key or less data size to encrypt.

梦回旧景 2024-11-21 15:32:12

您真的需要自定义填充吗?如果没有,您可以使用 RSACryptoServiceProvider.SignData 方法< /a>

Do you real need the custom padding? If not you could just use RSACryptoServiceProvider.SignData Method

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文