I was at this all last Friday and am still stumped.
When I run this command:
echo -n "Data To Sign" | openssl pkeyutl -sign -inkey path/to/my.pem | openssl base64
through openssl I get the output:
1c284UkFgC6pqyJ+woSU+DiWB4MabWVDVhhUbBrTtF7CkpG8MjY+KkPFsZm9ZNM8vCjZjf...Kw=
I want to replicate this behavior in C#. The first attempt I made was using openssl to create a .p12 file from my .pem file. I did this by running the two following openssl commands:
openssl req -new -key path/to/my.pem -x509 -batch > my.crt
openssl pkcs12 -export -in my.crt -inkey path/to/my.pem -out my.p12
and then use the X509Certificate2
and RSACryptoServiceProvider
classes to load the .p12 and sign. Code Below:
var dataToSign = "Data To Sign";
var p12 = new X509Certificate2(@"path\to\my.p12","");
var rsa = (RSACryptoServiceProvider)p12.PrivateKey;
var signedBytes = rsa.SignData(Encoding.UTF8.GetBytes(dataToSign), "SHA1");
var result = Convert.ToBase64String(signedBytes);
which yields:
B2qM6MTjoZFSbnckezzpXrKFq67vFgsCPYBmaAbKOFmzVQLIU4a+GC6LWTMdNO4...Q0=
Unfortunately, the outputs don't match. After fighting with this for a while, I decided to go the BouncyCastle route suggested by several answers here on SO. Here's the code I came up using that library:
StreamReader sr = new StreamReader(@"path\to\my.pem");
PemReader pr = new PemReader(sr);
var pemKeyParams = (RsaPrivateCrtKeyParameters)pr.ReadObject();
var cypherParams = new RsaKeyParameters(true, pemKeyParams.Modulus, pemKeyParams.Exponent);
ISigner sig = SignerUtilities.GetSigner("SHA1withRSA");
sig.Init(true, cypherParams);
var bytes = Encoding.UTF8.GetBytes("Data To Sign");
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
var result = Convert.ToBase64String(signature);
which also yields:
B2qM6MTjoZFSbnckezzpXrKFq67vFgsCPYBmaAbKOFmzVQLIU4a+GC6LWTMdNO4...Q0=
The BouncyCastle output matches the output given by the C# code that uses the native libraries in the Security namespace, but I want to match openssl's output. What am I doing wrong?
Versions -
OpenSSL 1.0.1c
.NET 4.0
BouncyCastle 1.7.0
Windows 7
my.pem -
-----BEGIN PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOtk3bYdQsjeG1Xy 2KgF8ecWcPudPLEnV32OIbtA+h2hXQ853ZRsxusopm7vmqtI2/aVfc2vyw9AGY0U cjqPnyEq7et5oQydo5+aTEW3PenP9DR3MJ273ipPbrYX+I3XzJ+I6//k6DO/OAIA JLlXc9iT1pblSrHymFNEkIFiUgj3AgMBAAECgYBtP1Lmwo3MS8jECwEieh/a8D9f h4ozbd7dFqnxDicGuW1HM8PyrsljOmqD8hAGjroHpznLzFqhqU4ye9rH8wAWsKUj Qst/RjyDU3SNscyU/eg+ezuawUXafpPUEUTJ0aofdHn9GIVipiIi/4uaPP/IYtuC U2smep4C2+geqfTugQJBAP5MTaRQjoYBGKS/Bgd0JB16MHFV6FPDCX3NZ2CLTyZm o8edQZI4SbWoxkJaGqBOqDbz/dSmTLfRNmpAmC+az5sCQQDs+CyDLbs3URvD7ajx JjsJoPbuVmqPBPGmAy/4Qt3QVp9AWk+9uckU90DYMqJp5bdGoeokmA65uuEcvqbs yzfVAkEA018FIlE7RjNfEoEdN9DXvBC2d14a0JTLLOAwz1S8I4UpGWCjAjD7Q53X vYs7mogG1jaUg87+8cNaYZLzbI5XhQJANyqbajqGQB2Awj8cum81BUvU0K2LhxoW i5hoXXprmynfTyL3N2r99gSNswcuqkqRPT9KfBRuMSzhZUi5IZ05tQJBAKdQ3mJZ 1Vys2nEAXbQD5/ldi1+VF/0t4Z+JxqFBjqtsAoASBN+kSiPAnRl3r175oZ9m9gkd 5YISN0L+WD5Bf4U= -----END PRIVATE KEY-----
For the purposes of this question, I generated a new .pem, The above key does not secure anything important, but I provide it for reproducing my steps above.
Things I've considered so far:
* Encoding (ASCII vs UTF8)
* Endianess (-rev to the openssl still doesn't match either coded result)
* hashalg (I couldn't find anywhere that "SHA1" was officially the correct hash algorithm to use, but it seems to be what others were using and trying other options didn't help)
* newlines (I believe the -n on echo is required to be on par with the libraries, but removing it didn't help)
* Asking on SO (results pending :-) )
TIA