c# - 带有 RSA 加密的 SHA1 : bad length error

标签 c# encryption cryptography

可能我有几个误解。

据我所知,使用 RSA-SHA1 对字节数组进行签名会生成与所使用的 RSA key 长度相同的字节数组(签名)。是这样吗?

从另一方签名来看,大致意味着使用 SHA1 生成哈希(因此长度为 160 位),然后使用或不使用填充方案使用私钥对其进行加密。对吗?

稍后,为了恢复此哈希(无论有或没有填充模式),我需要使用公钥对签名进行加密。是这样吗?

我的逻辑有些问题,因为我无法使用公钥加密签名。

或者我的代码是错误的。我正在使用 .net RSACryptoServiceProvider,它在尝试加密签名时会引发错误的数据长度错误...我认为加密意味着使用公钥应用 RSA,对吧? 尝试解密时会引发“找不到 key ”异常。正如预期的那样,因为我只有公钥。

编辑: 给定一个字节数组和 RSACryptoServiceProvider 我可以加密、解密和 SignData。我认为 SignData(没有填充模式来简化问题)是应用 SHA,然后解密的快捷方式。对于加密,我的意思是使用公钥作为输入来应用 RSA 公式,对于解密,我的意思是使用私钥作为输入来应用 RSA 公式(完全相同的公式)。这个定义可以吗?

编辑2: 例如,看一下下一个签名的 xml:http://www.facturae.gob.es/formato/Versiones/factura_ejemplo2_32v1.xml

以及下一个 powershell 脚本:

$signb64="oYR1T06OSaryEDv8VF9/JgWmwf0KSyOXKpBWY4uAD0YoMh7hedEj8GyRnKpVpaFanqycIAwGGCgl vtCNm+qeLvZXuI0cfl2RF421F8Ay+Q0ani/OtzUUE49wuvwTCClPaNdhv2vfUadR8ExR7e/gI/IL 51uc3mEJX+bQ8dxAQ2w=";
$certB64="MIIDtDCCAx2gAwIBAgICAIcwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMCRVMxDzANBgNVBAgT Bk1hZHJpZDEPMA0GA1UEBxMGTWFkcmlkMQ4wDAYDVQQKEwVNSVR5QzEbMBkGA1UECxMSTUlUeUMg RE5JZSBQcnVlYmFzMRQwEgYDVQQDEwtDQSB1c3VhcmlvczAeFw0wOTEwMTUxNjA5MzRaFw0xMDEw MTUxNjA5MzRaMHExCzAJBgNVBAYTAkVTMQ8wDQYDVQQIEwZNYWRyaWQxDzANBgNVBAcTBk1hZHJp ZDEOMAwGA1UEChMFTUlUeUMxGzAZBgNVBAsTEk1JVHlDIEROSWUgUHJ1ZWJhczETMBEGA1UEAxMK VXN1YXJpbyA1NDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAroms65axKuQK18YDfD/x6DIn 0zKZ+6bv1K2hItJxel/JvU3JJ80/nY5o0Zbn+PrvlR2xF3poWYcPHLZpesgxhCMfnP7Jb5OUfceL g44m6T9P3PG1lSAZs3H6/TabyWGJy+cNRZMWs13KnB9fDAjJ5Jw0HVkwYNwmb1c7sHCuyxcCAwEA AaOCAVgwggFUMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTYhqU2tppJoHl+S1py BOH+dliYhzCBmAYDVR0jBIGQMIGNgBT1oWqod09bsQSMp35I8Q6fxXaPG6FypHAwbjEPMA0GA1UE CBMGTWFkcmlkMQ8wDQYDVQQHEwZNYWRyaWQxDjAMBgNVBAoTBU1JVHlDMRswGQYDVQQLExJNSVR5 QyBETkllIFBydWViYXMxEDAOBgNVBAMTB1Jvb3QgQ0ExCzAJBgNVBAYTAkVTggEDMAkGA1UdEQQC MAAwNgYDVR0SBC8wLYYraHR0cDovL21pbmlzdGVyLThqZ3h5OS5taXR5Yy5hZ2UvUEtJL0NBLmNy dDA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vbWluaXN0ZXItOGpneHk5Lm1pdHljLmFnZS9QS0kv Y3JsLmNybDANBgkqhkiG9w0BAQsFAAOBgQAhAN/KVouQrHOgd74gBJqGXyBXfVOeTVW+UTthhfCv DatXzTcrkYPQMfBAQMgGEa5KaQXcqKKhaoCUvrzFqE0HnAGX+ytX41oxZiM2fGNxRZcyUApLEX67 m8HOA/Cs2ZDlpU2W7wiOX5qr+ToTyfXsnRwPWvJ8VUmmXwyMEKcuzg==";

$signb=[System.Convert]::FromBase64String($signB64);
$certb=[System.Convert]::FromBase64String($certB64);

$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList @(,$certb)
$rsacsp = [System.Security.Cryptography.RSACryptoServiceProvider] $cert.PublicKey.Key;

$signb.Length*8;
$rsacsp;

$rsacsp.Encrypt($signb,0);

我尝试过:

$rsacsp.Encrypt($signb,[System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1);

而不是

$rsacsp.Encrypt($signb,0);

但我总是收到错误的长度错误:

Exception calling "Encrypt" with "2" argument(s): "Bad Length.

编辑3: 读完后,我发现我的主要问题是“从另一方签名,大致意味着使用 SHA1 生成哈希(因此长度为 160 字节),然后使用或不使用填充方案使用私钥对其进行加密。对吗? ”。

RSA 符号(具有 n 位 key 长度)可以被视为采用任意字节数组并输出 n 位的操作。为了做到这一点,它使用像 SHA1 这样的哈希函数,该函数接受任意字节数组并生成固定输出(SHA1 为 160 位)。现在理论上我可以用私钥“加密”,但是那么输出也将是 160 位长,这不是 RSA 的实现方式。 RSA 签名需要在哈希之后应用填充函数,以便在“加密”之前生成 n 位文本。

另一个令人困惑的来源是 .NET RSACryptoProvider 的 Encrypt 方法的含义。事实证明,这个方法有两个参数:一个字节数组和一个表示填充函数的标志。它采用字节数组,应用填充,然后使用公钥“加密”。对于签名场景来说是没有用的。 RSACryptoProvider 中的解密和加密操作不是对称的。您可以“解密”任何已“加密”的内容,但反之则不行。

最后的困惑在于,加密/解密时使用的“原子”函数和登录时使用的函数是相同的,但它们的使用方式不兼容。

最佳答案

AFAIK signing a byte array with RSA-SHA1 generates a byte array (signature) of the same lenght as the RSA key used. Is that right?

通常是的,虽然大小当然会被编码为八位字节流(也称为字节数组),但签名的大小实际上可能最多大 7 位。 key 大小通常是 8(位)的倍数,因此不会出现太多。

From another side signing, roughly means generate a hash using SHA1 (so it is 160 bites long) and then with or without a padding scheme encrypt it with the private key.Is that right?

不,你不应该在没有填充的情况下在 RSA 中执行模幂运算;为了安全起见,需要填充方案。请注意,您不应该在这里谈论加密。加密用于提供 secret 性。 RSA 签名生成和加密都使用模幂(尽管使用不同的 key )并不意味着其中一个等同。

需要注意的是the padding scheme for PKCS#1 v1.5 encryptionthe one used for signature generation 不同。此外还有更新的OAEP padding scheme for encryptionPSS padding scheme for signature generation这是相当不同的。

Later on, in order to recover this hash (with or without padding schema on it) I would need to encrypt the signature with the public key. Is that right?

进行模幂运算,然后验证结果,可以。但由于验证需要以安全的方式验证填充,因此您确实应该让 API 来处理此问题。

Something is broken in my logic because I'm not able to encrypt the signature with the public key.

尝试编写一些用于验证的内容,例如 this example 中所示的 VerifyHash 方法。 .


您可以尝试找到原始 RSA 实现来找出 RSA 签名中的内容。 您应该只执行此操作来分析签名。

因此,如果您使用公钥“加密”数据(即仅执行模幂运算),您将得到:

0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414a2304127e2fe3b8a8203b219feafdd9b58558310

结果。这显然是用于签名生成的 PCKS#1 v1.5 填充。它包括一个编码的哈希值:

SEQUENCE(2 elem)
  SEQUENCE(2 elem)
    OBJECT IDENTIFIER1.3.14.3.2.26
    NULL
  OCTET STRING(20 byte) A2304127E2FE3B8A8203B219FEAFDD9B58558310

关于c# - 带有 RSA 加密的 SHA1 : bad length error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35951250/

相关文章:

c# - 我可以在没有过多引用的情况下使用控制台应用程序截屏或打印屏幕吗

c# - 我是否应该升级才能使用 SqlDataReader 的新异步方法?

c# - 如何在 Entity Framework 中使用分部类的非数据库属性进行关联

encryption - 如何对加密算法进行逆向工程?

node.js - 使用 OpenPGP.js 解密非装甲 PGP 文件

encryption - 如果攻击者有原始数据和加密数据,他们能确定密码吗?

c# - 使用 C# 在 .NET Framework 3.5 中进行并行编程

c - C中字符总和的问题

cryptography - 这个 RFC 4226 错了吗?

Java 的 'Keystore' 的 Python 等价物?