How To verify signature in C# without passing a padding algorithm - c#

I receive a digital signature signed with this algorithm sha256WithRSAEncryption and I want to verify it against a data the only valid way that. I found this:
var x509 = new X509Certificate2(File.ReadAllBytes("cer.cer"));
using (var rsa = x509.GetRSAPublicKey()){
Console.WriteLine(rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
But there is no padding used in the signing, so is there is another way to verify the signature without providing a padding?

Related

Verifying a RSA signature made by Crypto Node.JS in C#

I'm trying to build a web service using Express/NodeJS which signs a piece of information. The signed data is received and verified by a client written in C#. You'll have to forgive my inexperience in cryptography and its associated technologies.
First off, I generate a certificate for the C# client and a private key for the NodeJS application using OpenSSL;
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days
365
In the NodeJS application, I have the following code;
const crypto = require('crypto')
const fs = require('fs')
var pem = fs.readFileSync('./keys/key.pem');
var key = pem.toString('ascii');
var privateKey = crypto.createPrivateKey({
'key': key,
'format': 'pem',
'passphrase': '<PASSPHRASE>',
});
function sign(identifier){
var sign = crypto.createSign('RSA-SHA256');
sign.update(identifier);
var sig = sign.sign(privateKey, 'base64');
return sig;
}
exports.sign = sign;
In this case, the parameter identifier is the data to be signed. The client will receive this, and the signature generated, sig.
In the C# client I have the following snippet;
X509Certificate2 cert = new X509Certificate2(Convert.FromBase64String(pub));
using (var sha256 = SHA256.Create())
{
using (var rsa = cert.GetRSAPublicKey())
{
bool results = rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
Console.WriteLine(results.ToString());
}
}
The pub is the generated certificate in Base64, it is stored in a const string. The data contains the same information as identifier in the NodeJS application, but it's converted to bytes using Convert.FromBase64String(...), and likewise the signature is the data returned from sig in the NodeJS application, only converted from Base64 to byte data.
When all information is inserted, VerifyData() returns false, this leads me to believe that there's some kind of missmatch between the cryptographic configurations of the web service and the client.
Any ideas?
As pointed out in the comments, the problem was that data in the C# client was converted to from Base64 when the data in the NodeJS application read from UTF-8.
The solution was to convert the string using Encoding.UTF8.GetBytes()
Thanks for the quick response!

Is there a 100% managed way to create an X509 certificate? [duplicate]

I am trying to use pure .net code to create a certificate request and create a certificate from the certificate request against an existing CA certificate I have available (either in the Windows Certificate store or as a separate file).
I know that I have the classes X509Certificate and X509Certificate2 available to load certificates and get access to their information, but I don't see any classes or functionality within the System.Security.Cryptography namespace that could be used to create a certificate request or to sign such a certificate request to create a new signed certificate.
And that although the documentation on the System.Security.Cryptography.Pkcs namespace says:
The System.Security.Cryptography.Pkcs namespace provides programming
elements for Public Key Cryptography Standards (PKCS), including
methods for signing data, exchanging keys, requesting certificates,
public key encryption and decryption, and other security functions.
So, how can I create a certificate request and fulfill that request to create a new X509 certificate using only pure .net classes from System.Security.Cryptography?
Note:
I don't want to use an external executable like openssl or MakeCert
I don't want to use BouncyCastle
I don't want to use Windows Certificate Enrollment API
I don't want to use the native Win32 API functions
Short answer: You can starting in .NET Framework 4.7.2.
This functionality was originally added to .NET Core 2.0 in the form of the CertificateRequest class, which can build a PKCS#10 certification signing request or an X.509 (self-signed or chained) public key certificate.
The classes for that feature were made available in .NET Framework 4.7.2.
using (RSA parent = RSA.Create(4096))
using (RSA rsa = RSA.Create(2048))
{
CertificateRequest parentReq = new CertificateRequest(
"CN=Experimental Issuing Authority",
parent,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
parentReq.CertificateExtensions.Add(
new X509BasicConstraintsExtension(true, false, 0, true));
parentReq.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(parentReq.PublicKey, false));
using (X509Certificate2 parentCert = parentReq.CreateSelfSigned(
DateTimeOffset.UtcNow.AddDays(-45),
DateTimeOffset.UtcNow.AddDays(365)))
{
CertificateRequest req = new CertificateRequest(
"CN=Valid-Looking Timestamp Authority",
rsa,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
req.CertificateExtensions.Add(
new X509BasicConstraintsExtension(false, false, 0, false));
req.CertificateExtensions.Add(
new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation,
false));
req.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.8")
},
true));
req.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(req.PublicKey, false));
using (X509Certificate2 cert = req.Create(
parentCert,
DateTimeOffset.UtcNow.AddDays(-1),
DateTimeOffset.UtcNow.AddDays(90),
new byte[] { 1, 2, 3, 4 }))
{
// Do something with these certs, like export them to PFX,
// or add them to an X509Store, or whatever.
}
}
}
Longer answer if you're stuck on older versions: To accomplish your goal without adding any new P/Invokes, you would need to read and understand the following documents:
ITU-T X.680-201508, the ASN.1 language
IETF RFC 5280 or ITU-T X.509, the documents that explain the fields in X.509 certificates.
IETF RFC 2986, explains the PKCS#10 certification signing request
ITU-T X.690, explains the BER encoding family for ASN.1 (including DER) which tells you how to read and write bytes to achieve the semantic meaning from X.509 / PKCS#10.
And then you could write a DER writer/reader, and just emit the bytes for what you want.
I cant comment on the answer above, so this serves as a comment.
#Keith
if the issue is the private key used for the server certificate is missing the private key i hope this explains whats going on.
To combine the public and private keys in the answer above,
cert = RSACertificateExtensions.CopyWithPrivateKey(cert, rsa);
This will bundle the private key with the certificate for exporting to PFX with
File.WriteAllBytes("filename", cert.Export(X509ContentType.Pfx, "passphrase for export"));
for the example provided above.
The method CreateSelfSigned returns a X509Certificate2 object with the public and private key attached.
Where as when signing against a root, or subordinate
The Create method will only create the public key component in the X509Certificate2 object.
I think this is because the usual certificate methods would use the CSR to sign against and return the public key for acceptance by the client which would never expose the private key to the signing server.

Windows server 2012 "Invalid algorithm specified."

When I try to sign data it always says Invalid algorithm specified. I am using following code:
Here is my Certificate Details.
Please Help me, Thanks.
Instead of
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;
return csp.SignHash(hash, CryptoConfig.MapNameToOid("SHA256"));
use
using (RSA privateKey = cert.GetRSAPrivateKey())
{
return privateKey.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
(Requires .NET 4.6+)
The problem is your RSACryptoServiceProvider object is using the CAPI PROV_RSA_FULL provider, which predates SHA-2. SHA-2 signatures (from the software provider) require the key be in PROV_RSA_AES, a fact mostly controlled by the key creation / PFX import.
There's a workaround you can do for rebinding the provider type to still use the soft-deprecated RSACryptoServiceProvider, but particularly in code like this (where the object does not leave the method) you should switch to using cert.GetRSAPrivateKey() and avoid casting the returned RSA object beyond the algorithm base class.

Hash X509 certificate with SHA 256 in c#

I work on an EBICS implementation in C# and I need to send to my bank the hash of my three certificates in SHA256 format in order to enable EBICS link with it.
I generated them in C# with BouncyCastle and now I have a X509Certificate2 object.
So to hash my certificate I used the following code :
String HashCertificate = Certificat.GetCertHashString();
And he return me the following result :
21952A5F79CA3232A656794EE4532BECF5AE3960
But the length don't match with the lenght of the hash of the bank certificate :
57436AD3D09989ED74F4FCCDBF7668C43F8BF87C933F90B065ED442A22E5B0BF
So I think the GetCertHashString() function return the hash of the certificate in SHA1 format and I have no idea how I can hash it in SHA256.
Can you help me please ?
Thank you in advance
As MSDN says GetCertHashString method always
Returns the SHA1 hash value for the X.509v3 certificate as a hexadecimal string.
regardless of signature algorithm since it is Windows specific thumbprint used internally in certifcates store.
You can calculate any other hash by accessing certificate content from its RawData property, e.g. for SHA256:
using (var hasher = SHA256.Create())
{
var hash = hasher.ComputeHash(cert.RawData);
Console.WriteLine(BitConverter.ToString(hash));
}

Digital signature using bouncy castle and certificate private key

I am developing a feature to digital sign some content. I have valid certificate with a private key. How to digital sign using the private key and bouncy castle?
I tried the following but want some right way to achieve the same using bouncy castle:
X509Certificate2 signingCert =
CryptoHelper.FindCertificate("21A6107EC254457AAF3D4D6FD286FB79");
var rsaObj = (RSACryptoServiceProvider)signingCert.PrivateKey;
_privateKey = rsaObj.ExportParameters(true);
Thanks!
I donĀ“t know exactly what you need based on your code, but there X509 namespace/code is at
bcgit/bc-csharp - X509 and there is an utility class for conversion between System.Security.Cryptography and BouncyCastle
bcgit/bc-csharp - DotNetUtilities.cs
BouncyCastle got lots of test (and examples). Have a look at bcgit/bc-csharp - TestCertificateGen.cs too. Maybe this helps you.
EDIT: In general it should go something like this
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
// Your loaded certificate
X509Certificate cert = null;
// Your loaded RSA key
AsymmetricKeyParameter privateKey = null;
AsymmetricKeyParameter publicKey = cert.GetPublicKey();
ISigner signer = SignerUtilities.GetSigner(cert.SigAlgName);
// Init for signing, you pass in the private key
signer.Init(true, privateKey);
// Init for verification, you pass in the public key
signer.Init(false, publicKey);
Greetings

Categories