Digital Signature Verification using BouncyCastle - ECDSA with SHA 256, C# - c#

Following is my scenario
- I read data from a barcode and its converted into a plain text. This text is a combination of barcode data + digital signature. Digital signature is appended to the end, which enables me to separate out the actual data and digital signature data. Digital signature data is hashed using sha256
-User send me a public key as windows certificate file ( .cer extension).
Required implementation :
-Need to extract public key from the certificate and validate the public key against the barcode data and the digital signature provided.
Here is the code I am trying to use to verify signature
//Note :
//1. certPath : is the path where my certificate is located
//2. GetStreamdata get the stream of data from the certificate.
//Get the certificate data here
Org.BouncyCastle.X509.X509Certificate cert1 = new X509CertificateParser().ReadCertificate(GetStreamData(cerPath));
//get the public key
ECPublicKeyParameters ecPublic = (ECPublicKeyParameters)cert1.GetPublicKey();
//create a signerutility with type SHA-256withECDSA
ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
//initial signer with the public key
signer.Init(false, ecPublic);
//get signature in bytes : digitalsignature parameter contains signature that should be used.
byte[] dBytes = encoding.GetBytes(digitalsignature);
//block/finalise update to signer : data : is the actual data.
signer.BlockUpdate(data, 0, data.Length);
try
{
//verify signature
verified = signer.VerifySignature(dBytes);
}
catch(Exception ex)
{
_log.LogException(ex);
}
what was I able to achieve was : extract public using bouncy castle libraries
Problem :
Exception thrown on signer.verifysignature
Message=Unable to cast object of type 'Org.BouncyCastle.Asn1.DerApplicationSpecific' to type 'Org.BouncyCastle.Asn1.Asn1Sequence'.
Source=BouncyCastle.Crypto

The problem was that I had to encode digitalsignature value in iso-8859-1. I was encoding in ASCII before.
This solves the problem and I was able to validate signature.

Related

EPPlus - Create and validate digital signature

is it possible to add a digital signature to an excel document with EPPlus and validate a digital signature of an existing excel document?
Maybe you can go with a detached signature.
You can create a signature using the following code:
X509Certificate2 certificate = new X509Certificate2(certPath, password);
byte[] signature;
using (RSA rsa = certificate.GetRSAPrivateKey())
{
signature = rsa.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
where data is a byte array
Then store it to an external file
For validating the signature you need your xlsx file and the external signature file.
Then you can verify the signature using the following code
X509Certificate2 publicCertificate = new X509Certificate2(certPath);
var valid = false;
using (RSA rsa = publicCertificate.GetRSAPublicKey())
{
valid = rsa.VerifyData(fileData, signatureData, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
where fileData is a byte array of your xlsx file and signatureData is a byte array of your signature file
Tell me if it worked =)

C# Verifying PDF signature

Trying to validate PDF signature isn't working. The PDF were signed by Adobe Acrobat and then trying to verify it with the public key of the client certificate.
So I get the public key of the client certificate, hash the PDF and verify if the hash is equal to the pdf signature, but it fails.
HttpClientCertificate cert = request.ClientCertificate;
X509Certificate2 cert2 = new X509Certificate2(cert.Certificate);
PdfReader pdfreader = new PdfReader("path_to_file");
AcroFields fields = pdfreader.AcroFields;
AcroFields.Item item = fields.GetFieldItem("Signature1");
List<string> names = fields.GetSignatureNames();
foreach (string name in names){
PdfDictionary dict = fields.GetSignatureDictionary(name);
PdfPKCS7 pkcs7 = fields.VerifySignature(name);
Org.BouncyCastle.X509.X509Certificate pdfSign = pkcs7.SigningCertificate;
// Get its associated CSP and public key
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert2.PublicKey.Key;
// Hash the data
SHA256 sha256 = new SHA256Managed();
byte[] pdfBytes = System.IO.File.ReadAllBytes("path_to_pdf");
byte[] hash = sha256.ComputeHash(pdfBytes);
// Verify the signature with the hash
bool ok = csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), pdfSing.GetSignature());
}
First, to verify whether the signature correctly you can simply use the PdfPKCS7 object you already retrieved, more exactly its Verify method:
/**
* Verify the digest.
* #throws SignatureException on error
* #return <CODE>true</CODE> if the signature checks out, <CODE>false</CODE> otherwise
*/
virtual public bool Verify()
Thus, you can simply call
bool ok = pkcs7.Verify();
and ok is true only if the document hash matches the hash in the signature.
Concerning your attempt to calculate the document hash like this
byte[] pdfBytes = System.IO.File.ReadAllBytes("path_to_pdf");
byte[] hash = sha256.ComputeHash(pdfBytes);
This indeed gives you the hash value of the complete PDF.
For document types with integrated signatures like PDFs, though, this is not the hash of interest because the complete PDF obviously includes the integrated signature!
Thus, you have to find the space reserved for the signature in the PDF and ignore it during hash calculation, cf. this answer on Information Security Stack Exchange, in particular this image:
In case of multiple signatures you furthermore have to consider that the earlier signatures only sign a former revision of the PDF, so the hash is to be calculated only for a starting segment of the file, cf. this image from the answer referenced above:
The iText(Sharp) method PdfPKCS7.Verify() takes all this into account.

Verify electronic signature in .NET

I have a set of questions:
What does a .p7s file contain? I read that it usually is an encrypted message sent to an e-mail, but in my case I have a file and a .p7s file on my hdd. The file is much larger than the .p7s, so I am wondering what is in it (and of course how to later use it).
2.this question occurs mostly because I have no naswer for 1. - If I have my public key in the form of a byte array, how can I verify the signature in C#? I found this on the internet, but again, it uses some text gotten from an e-mail and I honestly don't know what is happening:
public static bool Verify(byte[] signature, string text)
{
X509Certificate2 certificate = new X509Certificate2(#"D:\My-CV.docx.p7s");
if (signature == null)
throw new ArgumentNullException("signature");
if (certificate == null)
throw new ArgumentNullException("certificate");
//hash the text
// Methode 3 for Hashing
System.Security.Cryptography.SHA1 hash3 = System.Security.Cryptography.SHA1.Create();
System.Text.UnicodeEncoding encoder = new System.Text.UnicodeEncoding();
byte[] combined = encoder.GetBytes(text);
byte[] hash3byte = hash3.ComputeHash(combined);
//Adding the text from the email, to a contentInfo
ContentInfo content = new ContentInfo(hash3byte);
// decode the signature
SignedCms verifyCms = new SignedCms(content, true);
verifyCms.Decode(signature);
// verify it
try
{
verifyCms.CheckSignature(new X509Certificate2Collection(certificate), false);
return true;
}
catch (CryptographicException)
{
return false;
}
}
Can someone help me with this?
The .p7s file is containing the signature of your document. The content is not encrypted, but it's look like.
The document file is much larger, because it contains the date, the .p7s the signature.
To check the signature, you need the public part of the certificate with which the document was signed.
You can check this two posts to check the signature :
Check signature for x509 certificate
In C#, sign an xml with a x.509 certificate and check the signature
The last thing is to load the signature data, from the p7s file.
I make some search, and come back to you.

Verify detached signature (*.p7s files) and X509Certificate2

I receive an XML document as a string parameter in my method. The XML document is:
  
<Document>
    <ZipContainer> Zip_File_In_Base64 </ZipContainer>
    <X509Certificate> Certificate_In_Base64 </X509Certificate>
</Document>
From this string I extract the ZIP file in base64 format and X509Certificate2 certificate in base64 format. The ZIP file contains:
file describing the contents of the ZIP file as XML (file packageDescription.xml);
files with the contents of transmitted documents (for example, *.doc files);
files with content of detached digital signature (*.p7s files - detached digital signature);
From the archive should be extracted signature that signed documents (detached digital signature may be more than one). Detached digital signature are stored in files with .p7s extension. Each signature must be done to check its agreement with digital signature, with which the user is logged in to the portal.
The must consist of two steps:
See method certificateValidator() (see this method below): This is a of detached signature, contained in the .p7s files with their corresponding files that are signed, these *. P7s-files.
For example: a pair of related files: ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s and
ZayavUL_3594c921f545406d9b8734bbe28bf894.doc.
See method certificateValidator(): This verifies certificate from a file .p7s with a certificate that is extracted from the XML document input string.
Questions
The method signatureValidator (see this method below) is not currently used detached signature of the files .p7s. I did try, but without success. How do I properly verify the detached signature of .p7s file for its corresponding file?
In the method certificateValidator (see this method below) how do I verify the conformity of the certificate extracted from the .p7s file, with a certificate extracted from input string in Base64 format?
The line of code foreach (X509Certificate2 x509 in signCms.Certificates) { } ---> Certificates Collection always is empty. Why?
Input parameters
Dictionary <string, byte[]> dictP7SFiles (key - the name of the file *.p7s, value - array of bytes, representing *.p7s file)
Dictionary <string, byte[]> dictNotP7SFiles (key - the name of the file that is signed using detached signature from *.p7s file, value - array of bytes, representing file)
X509Certificate2 userCertX509 - certificate object, extracted from the input xml-document (where it has the format Base64)
Code
Here below are testing implementation of verification steps (see above this 2 steps):
private bool certificateValidator(Dictionary<string, byte[]> dictP7SFiles,
Dictionary<string, byte[]> dictNotP7SFiles, X509Certificate2 userCertX509)
{
bool isValid = false;
try
{
foreach (KeyValuePair<string, byte[]> pair in dictP7SFiles)
{
ContentInfo contentInfo = new ContentInfo(pair.Value);
SignedCms signCms = new SignedCms(contentInfo, true);
if (signCms.Certificates.Count != 0)
{
//Certificates Collection always is empty. Why?
foreach (X509Certificate2 x509 in signCms.Certificates)
{
if ((x509.SerialNumber != userCertX509.SerialNumber)
|| (x509.Thumbprint != userCertX509.Thumbprint))
{
isValid = false;
return isValid;
}
}
isValid = true;
return isValid;
}
}
}
catch (Exception ex)
{
//here process exception code
}
return isValid;
}
private bool signatureValidator(Dictionary<string, byte[]> dictP7SFiles,
Dictionary<string, byte[]> dictNotP7SFiles, X509Certificate2 userCertX509)
{
bool isValid = false;
try
{
byte[] data = dictP7SFiles["ZayavUL_3594c921f545406d9b8734bbe28bf894.doc"];
byte[] publicKey;
byte[] signature;
object hasher = SHA1.Create(); // Our chosen hashing algorithm.
// Generate a new key pair, then sign the data with it:
using (var publicPrivate = new RSACryptoServiceProvider())
{
signature = publicPrivate.SignData(data, hasher);
publicKey = publicPrivate.ExportCspBlob(false); // get public key
}
// Create a fresh RSA using just the public key, then test the signature.
using (var publicOnly = new RSACryptoServiceProvider())
{
publicOnly.ImportCspBlob(publicKey);
isValid = publicOnly.VerifyData(data, hasher, signature); // Return True
//isValid = ByteArrayCompare(dictP7SStreams["ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s"], signature);
byte[] p7sDetachedSignature = File.ReadAllBytes(#"D:\ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s");
isValid = ByteArrayCompare(p7sDetachedSignature, signature);
}
}
catch (Exception)
{
//here process exception code
}
return isValid;
}
The main thing you are doing wrong is to regenerate the CMS and signature. You should parse the CMS message, then indicate the external content during verification.
How do I properly verify the detached signature of .p7s file for its corresponding file?
Take a look at the following Java code on SO to see how to verify signatures; C# should use the same architecture and it should therefore work similarly.
In the method certificateValidator (see this method below) how do I verify the conformity of the certificate extracted from the .p7s file, with a certificate extracted from input string in Base64 format?
Decode the base 64 certificate and perform chain verification and validation of the certificate. How much validation you want to perform (e.g. checking the effective date) is up to you.
The line of code foreach (X509Certificate2 x509 in signCms.Certificates) { } ---> Certificates Collection always is empty. Why?
You simply didn't put one in during construction of the new CMS structure.
You certainly should not regenerate the signature either. Normally you would not have the private key during verification, and the algorithm may not match the one used within the CMS document. Furthermore, even if it would, signature generation is not always deterministic (you may get different signature values).

How to use c# to decrypt an MD5 hash that is encrypted using RSA1024

I trying to verify the integrity of a file at work and an having a hard time of it. I'm not very well versed with encryption and hashing, so bear with me.
I have some files that have an MD5 hash located at the end of them. I have written code to grab the bytes that I think are the hash and they seen to be uniformly 128 bytes long. In the file, just before the hash, is the keyword "RSA1024", which I have taken to mean the hash is encrypted using RSA 1024.
I have what I know is the RSA key in a file, and have read out the bytes (always 258 bytes long). I have seen many tutorials which use FromXmlString() to pull in the key, but this RSA key was not generated using the .net framework, and is not in an XML format.
I have written the following method to decrypt the hash data using the key, and it throws this error when executing ImportCspBlob() - System.Security.Cryptography.CryptographicException: Bad Version of provider.
Any ideas?
public byte[] DecryptRSA(byte[] encryptedData, byte[] keyData)
{
CspParameters param = new CspParameters();
param.Flags = CspProviderFlags.UseExistingKey;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
rsaProvider.ImportCspBlob(keyData);
byte[] decryptedData = rsaProvider.Decrypt(encryptedData, false);
return decryptedData;
}
Basic Algorithm
It may sound strange to want to "decrypt an MD5 hash", and especially when one says that they want to "decrypt it with a public key". But that is how digital signatures work. With RSA you can:
encrypt with private key
decrypt with the public key
The message digest is encrypted with the private key, and can then only be decrypted with the public key. That way you know that only the person with the private key could have signed the message.
Your key is most likely not a CSP-type key (it is most likely DER encoded). You can decrypt it using Bouncy Castle with the DER key like this:
RsaPrivateCrtKeyParameters privateKey = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(key);
byte[] rv = null;
RsaEngine eng = new RsaEngine();
eng.Init(false, privateKey);
int size = eng.GetOutputBlockSize();
rv = eng.ProcessBlock(cipher, 0, cipher.Length);
EDIT: to addressing GregS scenario that it may be a signature verify operation
If you are trying to verify a signature, you would need a certificate used to verify a message, the original message text, and the existing message signature to compare against.
What you do is pass in the original message text (minus the signature), the bytes of the message signature, and the path to the certificate you will use to verify the passed in signature.
Then, you will hash the original message and compare the result against the passed in signature.
Here is some code to illustrate:
private bool VerifySignature(string messageText, byte[] messageSignature, string certificatePath)
{
// Load the certificate from a file
X509Certificate2 cert = new X509Certificate2(certificatePath);
// Get public key
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key;
// Next, hash the messageText
SHA1Managed sha1 = new SHA1Managed();
byte[] messageBytes = Encoding.Unicode.GetBytes(messageText);
byte[] hash = sha1.ComputeHash(messageBytes);
// Verify the signature with the hash
return csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), messageSignature);
}
MD5 is one-way hash. But you might check out hashing algorithm. There are some ways to break this hash, just do some research ;)

Categories

Resources