Cannot get Openssl signed data to match signed .NET or BouncyCastle signed data signed data

I was this last Friday and still at an impasse.

When I run this command:

echo -n "Data To Sign" | openssl pkeyutl -sign -inkey path/to/my.pem | openssl base64 

via openssl I get the output:

 1c284UkFgC6pqyJ+woSU+DiWB4MabWVDVhhUbBrTtF7CkpG8MjY+KkPFsZm9ZNM8vCjZjf...Kw= 

I want to reproduce this behavior in C #. The first attempt I made was to use openssl to create a .p12 file from my .pem file. I did this by running two 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 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 gives:

 B2qM6MTjoZFSbnckezzpXrKFq67vFgsCPYBmaAbKOFmzVQLIU4a+GC6LWTMdNO4...Q0= 

Unfortunately, the outputs do not match. After battling this for a while, I decided to take the BouncyCastle route suggested by several answers here on SO. Here is the code I used using this 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 gives:

 B2qM6MTjoZFSbnckezzpXrKFq67vFgsCPYBmaAbKOFmzVQLIU4a+GC6LWTMdNO4...Q0= 

The BouncyCastle output matches the output date of the C # code that uses its own libraries in the Security namespace, but I want to combine the openssl 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 / e.g., + 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 OF PRIVATE KEY -----

For the purposes of this question, I generated a new .pem. The above key does not provide anything important, but I provide it to reproduce my steps above.

Things I've reviewed so far:
* Encoding (ASCII vs UTF8)
* Endianess (-rev for openssl still does not match any encoded result)
* hashalg (I could not find anywhere that "SHA1" was officially the correct hash algorithm, but it seems that others used and tried other options did not help)
* newlines (I believe that -n on echo needs to be on par with libraries, but deleting it did not help)
* Ask for SO (pending results :-))

TIA

+4
source share
2 answers

I would suggest that the openssl pkeyutl command actually signs the data directly, rather than signing the data digest.

The openssl docs on pkeyutl contain this suggestive comment:

"Unless otherwise specified, all algorithms support digest: the alg option, which defines the digest used for sign, validation, and verrecoverover operations. The alg value must be the digest name as used in the EVP_get_digestbyname () function, for example, sha1."

I do not see the digest option on your command line. In addition, from the same documents (in the RSA section):

"In PKCS # 1, if the message digest is not set, the data is signed or verified directly instead of using the DigestInfo composition. If the digest is specified, the DigestInfo structure is used and its length must match the type of digest."

See also docs for openssl dgst.

+3
source

RSA signing can use different padding modes (PKCS # 1, PSS, etc.). With the latter, it uses some random salt, so the signature will be different every time. So, first check if openssl generates the same value every time (I did not find which input code for the add-on is used by default, you can change it with the -rsa_padding_mode parameter), and, in fact, if both signatures can be checked correctly the other side.

+1
source

All Articles