2016-03-11 81 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)。也許這個難題有助於解決問題。忽略填充方案沒有多大意義。它是必需的,它必須在那裏,它必須被驗證。 –