Reproducing Ruby OpenSSL private_encrypt output in C#
I have a simple Ruby script that I am using to do a private_encrypt on some HTTP headers to sign a web request that is to be sent to a ruby REST API, the API tests the Base64 encoded string against a Base64 encoded string it generates rather than decoding the Base64 and decrypting the data then testing the original string.
The script I am using is
require "openssl"
require "base64"
path_to_cert = ARGV[0].dup
plain_text = Base64.decode64(ARGV[1].dup)
private_key = OpenSSL::PKey::RSA.new(File.read(path_to_cert))
puts Base64.encode64(private_key.private_encrypt(plain_text))
The fact that the input is Base64 encoded is purely due to linebreaks and spaces in the input argument.
To use this I am having to shell out to ruby using System.Diagnostics.Process and capture the StdOut, while this isn't a major problem and works I'd like to remove the dependency on ruby but I am unable to reproduce the output using the C# RsaCryptoServiceProvider.
If I Base64 Encode the private_encrypt result of "SimpleString" using ruby i consistently get
auReJzoPSW3AhzsfT3EH4rD7lc4y2CJ026xIOiV6kjl2OKIj8GnzrPosoJDg\nSHrvLVKrSxYlegYgJRMx+vaAHSAm7RXrZh5An2SnVuO3qITa2TJ78hTc3bAw\nCDm4i9/4qictjxEFfnPRe6 EYCa4b3dnM5moa1eo9zbQPBa1eS6ItRCX4C0G0\n1tJpQsEvuums363eAhTUAYa6yEWuINLPmE0USW6jfFNnsxw8Nv9SnC+ziomb\n/mwlt9dS5/mzKM8yFMH6hdQYLoqc0QpjT+xaZ1ZyJ6dG5MVG h3JtjIVRTOSd\n+pUU/bo+obEHbrftG8u2uJImLSA+/1e8aapHaa3WNg==
When using the .Net
RsaCryptoSer开发者_JAVA技巧viceProvider.Encrypt("SimpleString", false)
The result is always a different output due to the fact it is encrypting with the public key.
I have also tried
RsaCryptoServiceProvider.SignData
and while this always yields the same result, it is different to the result from ruby.
Can I use some CryptoAPI directly from .Net that will allow me to achieve the same result as Ruby?
What you require is a method of generating "raw signatures". Raw signatures generally consist of modular exponentiation of PKCS#1 v1.5 compatible signature formats, although other padding methods may be used as well. The difference with a normal signing operation is that it does not perform any hashing, and - in the case of PKCS#1 v1.5 compatible signature formats - does not create the ASN.1 structure around the hash value, which is used to identify the hashing method used.
This raw signature formats are not a standardized method of generating signatures and should be avoided. private_encrypt
mainly is used to support deprecated versions of SSL, that uses the method to create a signature for authentication using a concatenation of the raw output of MD5 and SHA1 hash values.
Finally, as Siva suggested, you may use the Bouncy Castle C# libraries to create raw signature formats. The raw signature format is not supported out of the box by most higher level API's, for the reasons given in the second paragraph.
[EDIT2] To accomplish this you need to use the raw "RSA" functionality.
if (mechanism.Equals("RSA"))
{
return (new RsaDigestSigner(new NullDigest()));
}
After that the RsaDigestSigner
class will use the EncodeBlock
method in DigestInfo
to generate the PKCS#1 padding. The NullDigest
does not do nothing, it just returns the data given to it as signature of itself.
Why don't you use Bouncy Castle C#? It provides complete framework for cryptography and there is class to load X509Certificate from PEM file.
You can encrypt using the private key.
Here's at least one example of doing it:
http://www.csharpbydesign.com/2008/04/asymmetric-key-encryption-with.html
Note the use of the PrivateKey property when doing the encryption (although the article references decryption, you can do the same with encryption as well)
精彩评论