Without using 3rd party BouncyCastle library, is there a way to read a custom private key and sign the message ? (sha256 hash+encryption using private key)<
Microsoft provides a class SignedXML to sign files. To know more, checkout https://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.signedxml(v=vs.110).aspx
Technically, yes. Depending on what kind of key you have the answer gets more tricky.
Edit (2019-Oct): .NET Core 3.0 has built-in support for all of these formats, in their DER-encoded (vs PEM-encoded) forms. I'm adding the .NET Core 3.0+ answers after a sub-heading within each file format.
If you have this type of file, and you're on .NET 4.6 or higher, then yes. You need to have the DER encoded (vs PEM encoded) data blob (see below if it's PEM).
using (CngKey key = CngKey.Import(blob, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSA rsa = new RSACng(key))
{
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
4.6 is required for for RSA, 4.6.1 for ECDSA, 4.6.2 for DSA.
The ImportPkcs8PrivateKey
method is declared on AsymmetricAlgorithm
, and all asymmetric built-in types (RSA
, DSA
, ECDsa
, ECDiffieHellman
) support it.
using (RSA rsa = RSA.Create())
{
rsa.ImportPkcs8PrivateKey(blob, out _);
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
Congratulations, your private key transport is strong. Sadly, this requires the maximum amount of code to be written if you want to actually handle it. You don't want to handle it. You really, really, want to
See How is a private key encrypted in a pem certificate?, and then continue to the next section for the primer on the hard way. You have a lot more work than it will talk about, though. You need to read the file, understand the encryption scheme and parameters, decrypt the blob, then use CNG for reading the PKCS#8, or just keep diving down the rabbit hole and enjoy your file parser.
The ImportEncryptedPkcs8PrivateKey
method is declared on AsymmetricAlgorithm
, and all asymmetric built-in types (RSA
, DSA
, ECDsa
, ECDiffieHellman
) support it.
using (RSA rsa = RSA.Create())
{
rsa.ImportEncryptedPkcs8PrivateKey(password, blob, out _);
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
You're at the unfortunate confluence of "relatively simple" and "relatively hard" that is known to math majors as "an exercise left to the reader".
Strongly consider doing the PFX approach from EncryptedPrivateKeyInfo. Alternatively, you can do this in custom code. Custom code? Okay, let's do this. The reference texts that you need at this point are
Okay, let's proceed.
byte[]
for the key object.For step 4, there are some things to be careful about. Specifically, the ASN.1/DER INTEGER components have two rules that RSAParameters does not like.
.NET wants the values as big-endian byte arrays (which is the same byte order as the DER encoding) with the following relationship:
The ImportRSAPrivateKey
method is declared on RSA
, and since it parses data and calls ImportParameters
it works for all RSA
derived types (assuming they already supported parameter import).
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(blob, out _);
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
Determine what RFC defines the ASN.1 structure for your key format, then keep that in mind and evaluate the RSAPrivateKey section.
DSAParameters and ECParameters each have their own spatial expectations.
Some of these include not-always-elegant, but frequently functioning code: