Cannot validate the signature with X509Certificate2 - c#

I am trying to use a self signed certificate to sign a string and then verify that the string is signed correctly.
This is how I create my self signed certificate:
makecert -r -n "CN=AuthCert2" -ss my -a sha1 -pe
After this I export the certificate to a pfx file and try to run the following code:
using System;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Net;
using System.Net.Security;
[TestClass]
public class TestSign
{
[TestMethod]
public void TestSignAndVerify()
{
string toSignString = "This is my string to sign";
byte[] data = UnicodeEncoding.UTF8.GetBytes(toSignString);
SHA1Managed sha1 = new SHA1Managed();
byte[] hash = sha1.ComputeHash(data);
X509Certificate2 signCert = new X509Certificate2("authcert2.pfx", "authpass");
var csp = (RSACryptoServiceProvider)signCert.PrivateKey;
byte[] signedData = csp.SignData(hash, CryptoConfig.MapNameToOID("SHA1"));
RSACryptoServiceProvider csp2 = (RSACryptoServiceProvider)signCert.PublicKey.Key;
bool result = csp2.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), signedData);
}
}
Yet I am always getting result as false. I am sure I am missing something very basic here. Any idea what is going on or how I can debug the problem?
thanks,

There are two things wrong within the code. First of all, the SignData computation already includes calculating the hash (no need to do it yourself) and the second is that you are using VerifyHash instead of VerifyData.

Related

How to generate hash of a file using certificate information and sha-256

Is it possible to generate hash of a file using certificate information?
I have certificate details like this
"details": {
"certificate": "XIIHBTCCBO2gAwIBAgIQGuE3Q0ztnKRiYRN.....",
"public_key": "XIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQE...."
},
Using this information I need to create a digestvalue. Assuming the digest value is hash of a file created using the above certificate.
I am using below code to generate hash, but not able to figure out how to use certificate as well.
public static string SHA256CheckSum(string filePath)
{
using (SHA256 SHA256 = SHA256Managed.Create())
{
using (FileStream fileStream = File.OpenRead(filePath))
return Convert.ToBase64String(SHA256.ComputeHash(fileStream));
}
}

How to get .pfx file when we have .pem and .key files? [duplicate]

I've got a .PEM file that I want to convert to a PKCS12 file (PFX), and I know I can easily accomplish this using the following openssl command:
Create a PKCS#12 file:
openssl pkcs12 -export -in file.pem -out file.p12 -name "My Certificate"
Which is great, but I'd like to do this programmatically using OpenSSL calls. Unfortunately, documentation for OpenSSL is less than ideal.
I've looked into doing this using other libraries:
Using .NET: I can create a X509Certificate2 object from a PEM file, but this only grabs the first certificate and ignores any intermediate CA's in the PEM file.
Using Mentalis.org Security Library: I can create a Certificate object from a PEM file, but I see the following in the documentation:
Remarks
This implementation only reads
certificates from PEM files. It does
not read the private key from the
certificate file, if one is present.
So, that doesn't help me. I need that private key too.
I basically need to recreate the OpenSSL command line tool operation for going PEM>PFX, but in code.
Is there an easier way to do this?
You could use BouncyCastle (assuming C#, because you mentioned .NET).
Let's say localhost.pem here contains both the certificate and the private key, something like this should work:
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
StreamReader sr = File.OpenText("localhost.pem");
IPasswordFinder passwordFinder = new PasswordStore("testtest".ToCharArray());
PemReader pemReader = new PemReader(sr, passwordFinder);
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
X509CertificateEntry[] chain = new X509CertificateEntry[1];
AsymmetricCipherKeyPair privKey = null;
object o;
while ((o = pemReader.ReadObject()) != null)
{
if (o is X509Certificate)
{
chain[0] = new X509CertificateEntry((X509Certificate)o);
}
else if (o is AsymmetricCipherKeyPair)
{
privKey = (AsymmetricCipherKeyPair)o;
}
}
store.SetKeyEntry("test", new AsymmetricKeyEntry(privKey.Private), chain);
FileStream p12file = File.Create("localhost.p12");
store.Save(p12file, "testtest".ToCharArray(), new SecureRandom());
p12file.Close();
}
}
class PasswordStore : IPasswordFinder
{
private char[] password;
public PasswordStore(
char[] password)
{
this.password = password;
}
public char[] GetPassword()
{
return (char[])password.Clone();
}
}
}
You'll probably need something a bit more subtle for the IPasswordFinder and if you want to handle certificate chains correctly.
For more advanced features, you may be able to find more details in the BouncyCastle examples.

RSA.Verify issues in .Net Core 3.0

I'm working with a 3rd party who sends me a certificate via a byte array. They send me 3 strings in an XML document that include, x509Data, SignatureValue, and DigestValue(for debugging).
They want me to validate that the SignatureValue is valid using the certificate public key contained in the x509Data cert. I'm populating the cert fine but when I try to Verify, it always returns false.
Here is my code:
byte[] SignatureValueBytes = Convert.FromBase64String(Signature.SignatureValue);
byte[] x509DataBytes = Convert.FromBase64String(Signature.x509Data);
byte[] DigestValueBytes = Convert.FromBase64String(Signature.DigestValue);
X509Certificate2 cert = new X509Certificate2(x509DataBytes);
using (RSA RSA = (RSA)cert.PublicKey.Key)
{
bool a = RSA.VerifyData(x509DataBytes, SignatureValueBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
Signature.* is the string coming from the XML file. Can some kind soul point out where I'm going wrong here?
Your code, as written, is trying to verify that SignatureValueBytes is a signature that signed x509DataBytes using RSASSA-PKCS1-SHA256.
Assuming you got the RSASSA-PKCS1-SHA256 part right, you probably want to use VerifyHash and DigestValueBytes instead of VerifyData and x509DataBytes. (You also want to use cert.GetRSAPublicKey() instead of cert.PublicKey.Key)
byte[] SignatureValueBytes = Convert.FromBase64String(Signature.SignatureValue);
byte[] x509DataBytes = Convert.FromBase64String(Signature.x509Data);
byte[] DigestValueBytes = Convert.FromBase64String(Signature.DigestValue);
X509Certificate2 cert = new X509Certificate2(x509DataBytes);
using (RSA RSA = cert.GetRSAPublicKey())
{
bool a = RSA.VerifyHash(DigestValueBytes, SignatureValueBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

How can I get an SHA-256 certificate thumbprint?

How can I get the SHA-256 thumbprint of a certificate?
SHA-256 certificates have two thumbprint, and I am able to retrieve the primary thumbprint, but not SHA-256.
If you want to get a certificate's SHA-256 thumbprint, you have to do some manual work. The built-in Thumbprint property is SHA-1 only.
You have to use a SHA-256 class and compute the hash over the certificate's content:
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace MyNamespace {
class MyClass {
public static String GetSha2Thumbprint(X509Certificate2 cert) {
Byte[] hashBytes;
using (var hasher = new SHA256Managed()) {
hashBytes = hasher.ComputeHash(cert.RawData);
}
return hashBytes.Aggregate(String.Empty, (str, hashByte) => str + hashByte.ToString("x2"));
}
}
}
And you convert this code to an extension method if necessary.
Use:
public static String GetSha2Thumbprint(X509Certificate2 cert)
{
Byte[] hashBytes;
using (var hasher = new SHA256Managed())
{
hashBytes = hasher.ComputeHash(cert.RawData);
}
string result = BitConverter.ToString(hashBytes)
// This will remove all the dashes in between each two characters
.Replace("-", string.Empty).ToLower();
return result;
}
After getting the Hashbytes, you have to do the bit convertion.
This post also helped me: Hashing text with SHA-256 in Windows Forms

C# RSA Decryption using Bouncy Castle

I have been given a Base64 Encoded encrypted string, which was encrypted in Java using Bouncy Castle. Example Java snippet below:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key.getPublic());
byte[] encryptedText = cipher.doFinal("xxxxx|xxxxx".getBytes("UTF-8"));
String encodedText = new BASE64Encoder().encode(encryptedText);
I need to decrypt the resulting string using Bouncy Castle, but in C#
I have been given a code snippet on how to do this in Java, but I can't convert this for C# (reasons is we are building a .net site, and is going to be an iFrame within a Java site. The Java site is going to passing in the RSA Encrypted string to the .NET site). Example Java code to decrypt below:
Cipher cipherDec = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipherDec.init(Cipher.DECRYPT_MODE, key.getPrivate());
byte[] decodedText = new BASE64Decoder().decodeBuffer(encodedText);
byte[] decryptedText = cipherDec.doFinal(decodedText);
String finalValue = new String(decryptedText, "UTF-8");
I have downloaded the examples from http://www.bouncycastle.org/csharp/ but there doesn't seem to be an example of inputting a string value to get encrypted, and it then going though the encrypt/decrypt process.
I have been given values for modulus, public exponent, private expontent, prime P, prime q, prime exponent p, prime exponent q and crt coefficient.
I have seen that I can use the following:
IAsymmetricBlockCipher signer = new Pkcs1Encoding(new RsaEngine());
signer.Init(true, pubParameters);
But the signer object doesn't seem to have the same methods as the Java examples above.
Only method I can use is
ProcessBlock(byte[] inbuf, int inOff, int inLen);
But I can't see how to use this in my context.
Any help here would be most appreciated.
To Help others, the final code to convert is as follows:
RsaKeyParameters privParameters = new RsaPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod, pubExp);
IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false, privParameters);
byte[] encdata = System.Convert.FromBase64String("{the enc string}");
encdata = eng.ProcessBlock(encdata, 0, encdata.Length);
string result = Encoding.UTF8.GetString(encdata);
mod, pubExp etc etc are all BigInteger values:
static BigInteger mod = new BigInteger("big int value");
The Following using directives are required:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Math;
Which can be obtained from the bouncycastle site. http://www.bouncycastle.org/csharp/
Have you tried converting the base 64 string to a byte array and then using the process block method? There may be more to it than that but it's definitely the first step I would take.
Here's an example of how to do this: http://msdn.microsoft.com/en-us/library/system.convert.frombase64string.aspx
I'm not sure I understand why you must use Bouncycastle. The following small code snippet shows and RSA encryption/decryption example using only .NET classes:
using System;
using System.Text;
using System.Security.Cryptography;
namespace RsaForDotNet
{
class Program
{
static void Main(string[] args)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
var encrypted_msg = rsa.Encrypt(Encoding.UTF8.GetBytes("Secret Data"), false);
var encoded_msg = Convert.ToBase64String(encrypted_msg);
Console.WriteLine(encoded_msg);
var decoded_msg = Convert.FromBase64String(encoded_msg);
var decrypted_msg = Encoding.UTF8.GetString(rsa.Decrypt(decoded_msg, false));
Console.WriteLine(decrypted_msg);
}
}
}

Categories