2016-03-11 82 views
1

也许我有几个误解。使用RSA加密的SHA1:长度错误错误

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

从另一侧签名,大致意味着使用SHA1生成一个哈希(所以它是160个长),然后使用或不使用填充方案使用私钥对其进行加密。是吗?

后来,为了恢复这个散列(有或没有填充架构),我需要用公钥加密签名。是对的吗?

我的逻辑中有些东西坏了,因为我无法用公钥加密签名。

或者我的代码有误。我正在使用.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叮咬长),然后使用或不使用填充方案使用私钥进行加密。是吗?“

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

混淆的另一个来源是.NET RSACryptoProvider的加密方法的含义。事实证明,这个方法有两个参数:一个字节数组和一个表示填充函数的标志。它需要字节数组,应用填充,然后用公钥“加密”。这对签名方案没有用处。在RSACryptoProvider中解密和加密的操作不是很简单。你可以“解密”任何“加密”,但不能反过来。

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

+0

您使用的是什么尺寸的RSA密钥? –

+1

你忘了告诉我们你的代码吗?寻求调试帮助的问题(“为什么这个代码不工作?”)必须包含所需的行为,特定的问题或错误以及**在问题本身**中重现它所需的最短代码。 –

+0

我用2048长键做了测试。 – Eduard

回答

2

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位大。密钥大小通常是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中执行模幂运算;为了安全性需要填充方案。请注意,你不应该在这里谈论加密。加密用于提供机密性。 RSA签名生成和加密都使用模幂运算 - 尽管使用不同的密钥 - 并不意味着其他值相等。

请务必注意,the padding scheme for PKCS#1 v1.5 encryptionthe one used for signature generation不同。此外,还有更新的OAEP padding scheme for encryption和,它们相当不同。

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.

试试核查书面代替,就像方法VerifyHash所看到的this example


您可以试着找到一个原始的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 
+0

您能详细说明一下吗“RSA签名生成和加密都使用模幂运算 - 尽管使用不同的键 - 并不意味着其他运算符相等吗?我编辑了这个问题,以澄清这一点... – Eduard

+0

我避免填充计划,以简化问题,而不是安全的最佳做法。 – Eduard

+0

@Eduard这很好,但要注意PKCS#1 v1.5加密方案的加密[*与用于签名生成的加密方案不同*(https://tools.ietf.org/html/rfc3447)。也许这个难题有助于解决问题。忽略填充方案没有多大意义。它是必需的,它必须在那里,它必须被验证。 –