Reputation: 789
Similar questions were asked many times but I was looking for an answer for 2 days and didn't find what I'm looking for. First of all, I have fair understanding of public/private key security from consuming standpoint. I never looked into the mathematics behind it. I understand that normally you use a public key to encrypt data and a private key to decrypt it. I'm also aware of the other pair of operations: signing data with a private key and verifying it with a public key. In .NET there is RSACryptoServiceProvider implementing or wrapping all those operations. If we look at the Verify method, it is declared as this
public bool VerifyHash(byte[] rgbHash, string str, byte[] rgbSignature)
My problem is that instead of verifying I would like to decrypt the signature data into the original hash which was signed with the private key. Now, I'm a bit confused. I found many answers stating that this is impossible but is it impossible from the API standpoint or from the mathematical standpoint? I would guess that it might be not possible only from the .NET API standpoint because if I use OpenSSL and do this
.\openssl.exe rsautl -verify -certin -inkey dev.crt -in signature.dat -out original.dat
I can decrypt the signature (signature.dat) into the original value (original.dat) that signature was created from. I believe that proves that mathematically it is possible.
Now the big question is there a way to do this with .NET, any workarounds, any libraries, is there anything what will do for me what OpenSSL is capable of doing. Please don't suggest to execute OpenSSL from the code. I cannot package it with the application. I need something else, ideally finding a workaround with the existing RSACryptoServiceProvider.
Updated step by step example:
I created a hash (128 bytes)
3D 0C 20 5C 73 DD 81 73 2A 41 F8 C7 A1 32 86 A5
F5 B5 D4 80 E0 0E 43 D0 7C 81 37 5F E5 AA 85 2A
02 EC 63 FA B1 87 44 92 E7 6D AA 96 EA 5E AA 6D
FC 38 8E C4 21 F6 7E D5 2A C5 9E 0F 27 2A D7 B9
2C C8 7C CF 8E 52 B1 FD AF 1C E6 80 BB 68 81 55
DC 25 7B 8D ED 22 64 87 0F 4D 08 6A B1 33 74 FA
C3 9E AA 12 4A 56 01 AA A5 A8 5E 75 F5 A4 8F EF
F7 E4 AA DB 58 E7 61 96 F7 40 B7 A1 CA 49 E5 FC
Then I executed
.\openssl.exe rsautl -sign -inkey dev.key -in hash.dat -out signed_hash.dat
to generate a signature where the signed hash result is this. It's 256 bytes
69 A3 DF A1 F6 4C 88 8B 83 E7 C1 BD 4E 12 D6 24
4B 5F 52 23 A4 3B 4F 27 11 37 C0 4C FA 99 3D 43
2B E5 0E 37 EF BB 2B 10 FF 28 4D 84 93 5A A2 75
52 DA C8 83 75 6A B2 29 91 79 AC 0C 12 8D C6 50
3A B4 71 CA 3F CD 15 73 2C 33 1E FA 4D E3 35 3A
68 A5 6E 1D 2B FD 91 03 3D 2E 97 C0 1A 4F A7 E2
FF 65 5A F9 96 3E 1B 68 A6 57 43 B4 62 35 32 F5
17 DF 76 55 8F 89 81 34 F2 B6 24 83 B8 76 8D E3
AD DB 7E 38 DE C0 94 5B 90 15 D7 4F 25 86 90 1C
B4 12 94 A4 0E BD 76 BB CF 54 2F 24 4D DE B5 8D
C8 40 DD 16 81 50 20 BD 11 A1 65 07 9B 00 D8 C1
60 D9 B2 4F 64 F7 4E 02 A7 B6 8B E6 2A D1 AC EF
3C E7 C5 4D 95 6D 70 B7 31 A2 60 AE 37 D3 83 21
23 BD 25 34 1E B7 D9 EA 05 7A A3 C3 9C DB DA A4
A6 14 11 C6 40 0D BD CB DD C2 F2 87 3A B8 A2 E3
7E 80 D5 8B 01 91 4B B2 0A 42 54 B6 3B 7F 41 3C
Then if I do this
.\openssl.exe rsautl -verify -certin -inkey dev.crt -in signed_hash.dat -out original_hash.dat
I get back my original hash. The public exponent value retrieved from the RSAParameters for the public key is this
01 00 01
and the Modulus is this
aa 0e 02 74 4c b5 06 87 f6 ae 4c 2c 71 76 59 7a
84 47 07 db 8e dd 8a 58 2c ba e5 1b 91 45 3e de
7d a9 d4 0a b9 cf 9f c2 19 cf af d3 30 fd 55 fb
81 d0 ef 68 ef c7 b0 fc 49 c9 4f fd 20 e9 ea 04
31 57 8f c2 1e 85 76 86 63 12 e0 00 01 17 02 80
76 fc f9 bc 09 61 80 6b a3 0b 8e de 1d b2 2f d6
ed 18 32 4b 03 0b 3b 2c ca 75 b6 85 95 20 5a 16
dc 4f 33 4b 97 84 fe 3f 9f 04 5b ba 56 44 73 aa
9f b0 7d 44 f4 58 ea a2 9d 35 d9 5c 8d 2d 39 a8
ce ee 19 24 9e 78 74 dc 6d 16 2b d7 24 bf 80 fa
a6 12 bf bd 89 cd 47 d0 bd 19 21 7d 3d 65 7b 06
9b 24 55 3c ca 4c 63 ce 40 ad a3 c5 72 cf 66 79
e0 f2 23 05 fa 20 32 b0 02 96 f1 a3 82 40 b4 b9
ac 9c f1 cf 83 a3 f0 50 83 81 b6 d7 f8 5f 93 21
71 0b f9 26 87 3d 61 17 cc 0c 09 09 b4 40 e4 92
45 fb 77 ca 94 cb 15 fb 54 68 4a c3 31 2d 57 09
What I need to do is to retrieve the original hash from the signed hash in my C#.NET code and I don't know how to do that.
Upvotes: 0
Views: 1056
Reputation: 1973
I don't believe it's possible using .NET crypto API's, at least I was not able to find a way. I was forced to re-implement the RSA algorithm using BigInteger. It's surprisingly straight forward.
BigInteger.ModPow(signature, exponent, modulus)
.Be aware of endianness and sign issues... https://msdn.microsoft.com/en-us/library/dd268207(v=vs.110).aspx
Here is some information on the subject that is specific to Java (and does not have the endianness issues you will face in .NET)... https://www.nayuki.io/page/java-biginteger-was-made-for-rsa-cryptography
Upvotes: 1