提问者:小点点

SHA1与RSA加密:错误的长度错误


可能我有几个误解。

AFAIK使用RSA-SHA1对字节数组进行签名会生成与所用RSA密钥长度相同的字节数组(签名)。是吗?

从另一个边签名,大致意味着使用SHA1生成一个哈希(所以它有160位长),然后用或不用填充方案用私有key.Is加密它,对吗?

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

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

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

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

EDIT2:例如,看看下一个签名的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位长),然后用或不用填充方案用私有key.Is加密它,对吗?”。

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

另一个混淆的来源是.NETRSACryptoProvider的Encrypt方法的含义。事实证明,该方法有两个参数:一个字节数组和一个指示填充函数的标志。它获取字节数组,应用填充,然后使用公钥“加密”。它对签名场景没有用处。RSACryptoProvider中的解密和加密操作不是简单的。您可以“解密”任何被“加密”的东西,但不能反过来。

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


共1个答案

匿名用户

AFAIK使用RSA-SHA1对字节数组进行签名会生成与所用RSA密钥长度相同的字节数组(签名)。是吗?

通常是的,虽然大小当然会被编码为八位字节流(又名字节数组),但签名的大小实际上可能大7位。密钥大小通常是8(位)的倍数,所以这不会出现太多。

从另一个边签名,大致意味着使用SHA1生成一个哈希(所以它有160位长),然后用或不用填充方案用私有key.Is加密它,对吗?

不,你永远不应该在没有填充的RSA中执行模幂运算;为了安全,填充方案是必需的。请注意,这里不应该谈论加密。加密是用来提供机密性的。RSA签名生成和加密都使用模幂运算——尽管密钥不同——并不意味着一个等同于另一个。

值得注意的是,PKCS#1 v1.5加密的填充方案不同于用于签名生成的填充方案。此外,还有较新的OAEP加密填充方案和用于签名生成的PSS填充方案,它们相当不同。

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

执行模幂运算,然后验证结果,是的。但是由于验证需要以安全的方式验证填充,你应该让API来处理这个问题。

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

尝试编写一些用于验证的东西,例如本例中的方法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