Verify Java Card signature - c#

I am writing a Java Card 3.0.2 application on a NXP J3D081 card. I have it both signing and verifying a signature using ALG_ECDSA_SHA_256. The keys have been written to the card by my test app. If I sign 32 bytes of data and pass the signature back to the card the Verify code successfully verifies the signature. If I sign 32 bytes in Bouncy Castle with the Private key and pass to the Verify on the Card it successfully verifies the signature. The bouncy castle Verify Code successfully verifies signatures created from the bouncy castle signing routine.
BUT if I take the returned signature from the Java Card and pass it to the C# bouncy castle code it FAILS to verify the signature. I have checked all input values and they are correct. My code is here (note I pass Public keys as 64 bytes and prepend them with 0x04)
public bool HashAndVerifyDSA(byte[] pb, byte[] inData, byte[] sig)
{
byte[] pub = new byte[65];
pub[0] = 0x4;
Array.Copy(pb, 0, pub, 1, 64);
ECCurve curve = parameters.Curve;
ECPoint q = curve.DecodePoint(pub);
ICipherParameters Public = new ECPublicKeyParameters(algorithm, q, parameters);
ISigner bSigner = SignerUtilities.GetSigner("SHA-256withECDSA");
bSigner.Init(false, Public);
bSigner.BlockUpdate(inData, 0, inData.Length);
return (bSigner.VerifySignature(sig));
}
I should note that the parameters specify the P-256 curve and are used successfully in the encrypted communication to the card. The Public key is successfully created.
I seem to have less hair now then I did two days ago. Any pointers would be welcome.

Apart from steps you have performed to debug the thing, you can check the following also: -
Verify the signature using some online available tool. Do not forget to use same curve parameters and public key generated from javacard.
Verify the same using bouncy castle java library. I perform the same steps in one of my tools and it was matched successfully.

Related

Is there a Microsoft library for ed25519 signature verification?

I've been going in circles trying to get a simple ed25519 signature verification working. Had success with libsodium third party library but then ran into issues with it and am back to the drawing board. I see system.security.cryptography.ecdsa but it's not clear to me if it's possible to get that to work with a ed25519 signature. I'm kind of surprised there aren't code examples of doing this sig verification in .Net because I thought ed25519 was a reasonably common algorithm?
Is there a Microsoft library for ed25519 signature verification? Or can anyone provide an example of how to successfully do this in .Net?
You can use BouncyCastle for this purpose. Below is the code example of how I am doing it. For using this code make sure the publicKey and signature are hex strings.
public Task<bool> VerifySignature(string publicKey, string dataToVerify, string signature)
{
var publicKeyParam = new Ed25519PublicKeyParameters(Hex.DecodeStrict(publicKey));
var dataToVerifyBytes = Encoding.UTF8.GetBytes(dataToVerify);
var signatureBytes = Convert.FromHexString(signature);
var verifier = new Ed25519Signer();
verifier.Init(false, publicKeyParam);
verifier.BlockUpdate(dataToVerifyBytes, 0, dataToVerifyBytes.Length);
var isVerified = verifier.VerifySignature(signatureBytes);
return Task.FromResult(isVerified);
}

How can I encrypt data using a public key from ECC X509 certificate in .net framework on windows?

I am using:
Windows 10 (Version 1709, OS Build 17025.1000)
.net framework 4.7
VS 2017 (version: 15.3.5)
Here is what I did:
Got a self signed ECC certificate using OpenSSL and steps outlined in the script at https://gist.github.com/sidshetye/4759690 with modifications:
a) Used NIST/P-256 curve over a 256 bit prime field
b) Used SHA-256
Load the certificate from file (generated in previous step) into X509Certificate2 object
Imported the PFX file into windows trust store (for testing). This is successful.
Inspection of the imported certificate shows Public Key field as 'ECC (256 Bits)' and Public key parameters as 'ECDSA_P256'.
Next tried to figure out how to encrypt with this certificate.
I am stuck at the last step because all the examples that use X509Certificate2 object predominantly use only RSA and I am using ECC certificate. For RSA certificate, there is a GetRSAPublicKey extention method on X509Certificate2 and RSA class has Encrypt method. However there is no such method for ECC certificates.
Next, I stumbled on this post (Load a Certificate Using X509Certificate2 with ECC Public Key) and tried following (even though it appeared bizarre as to why ECC cert public key is being coerced into RSA type):
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key
I got following exception: The certificate key algorithm is not supported.
Next I stumbled on this post (Importing ECC-based certificate from the Windows Certificate Store into CngKey) which basically tried to create CNGKey type and instantiate ECDsaCng with it. However even if I can do it with ECDiffieHellmanCng, there is no Encrypt method on it.
So I am not really sure how can I proceed further to use ECC X509 certificate's public key to encrypt data.
###Background
Asymmetric algorithms have three different purposes (that I know of)
Encryption
RSA is the only "standard" algorithm that can do this directly.
Signature
RSA
DSA
ECDSA
ElGamal Signature
Key Agreement
Diffie-Hellman (DH)
ECDH
ElGamal encryption (the asymmetric startup phase)
MQV
ECMQV
Because RSA encryption is space limited, and was hard for computers in the '90s, RSA encryption's primary use was in "Key Transfer", which is to say that the "encrypted message" was just the symmetric encryption key for DES/3DES (AES not yet having been invented) - https://www.rfc-editor.org/rfc/rfc2313#section-8.
Key agreement (or transfer) schemes always have to be combined with a protocol/scheme to result in an encryption operation. Such schemes include
TLS (nee SSL)
CMS or S/MIME encrypted-data
IES (Integrated Encryption Scheme)
ECIES (Elliptic Curve Integrated Encryption Scheme)
ElGamal encryption (holistically)
PGP encryption
So what you probably want is ECIES.
ECIES.Net
Currently (.NET Framework 4.7.1, .NET Core 2.0) there's no support to get an ECDiffieHellman object from a certificate in .NET.
Game over, right? Well, probably not. Unless a certificate carrying an ECDH key explicitly uses the id-ecDH algorithm identifier (vs the more standard id-ecc one) it can be opened as ECDSA. Then, you can coerce that object into being ECDH:
using (ECDsa ecdsa = cert.GetECDsaPublicKey())
{
return ECDiffieHellman.Create(ecdsa.ExportParameters(false));
}
(a similar thing can be done for a private key, if the key is exportable, otherwise complex things are required, but you shouldn't need it)
Let's go ahead and carve off the recipient public object:
ECDiffieHellmanPublicKey recipientPublic = GetECDHFromCertificate(cert).PublicKey;
ECCurve curve = recipientPublic.ExportParameters().Curve;
So now we turn to http://www.secg.org/sec1-v2.pdf section 5.1 (Elliptic Curve Integrated Encryption Scheme)
###Setup
Choose ANSI-X9.63-KDF with SHA-2-256 as the hash function.
Choose HMAC–SHA-256–256.
Choose AES–256 in CBC mode.
Choose Elliptic Curve Diffie-Hellman Primitive.
You already chose secp256r1.
Hard-coded. Done.
Point compression's annoying, choose not to use it.
I'm omitting SharedInfo. That probably makes me a bad person.
Not using XOR, N/A.
###Encrypt
Make an ephemeral key on the right curve.
ECDiffieHellman ephem = ECDiffieHellman.Create(curve);
We decided no.
ECParameters ephemPublicParams = ephem.ExportParameters(false);
int pointLen = ephemPublicParams.Q.X.Length;
byte[] rBar = new byte[pointLen * 2 + 1];
rBar[0] = 0x04;
Buffer.BlockCopy(ephemPublicParams.Q.X, 0, rBar, 1, pointLen);
Buffer.BlockCopy(ephemPublicParams.Q.Y, 0, rBar, 1 + pointLen, pointLen);
Can't directly do this, moving on.
Can't directly do this, moving on.
Since we're in control here, we'll just do 3, 4, 5, and 6 as one thing.
KDF time.
// This is why we picked AES 256, HMAC-SHA-2-256(-256) and SHA-2-256,
// the KDF is dead simple.
byte[] ek = ephem.DeriveKeyFromHash(
recipientPublic,
HashAlgorithmName.SHA256,
null,
new byte[] { 0, 0, 0, 1 });
byte[] mk = ephem.DeriveKeyFromHash(
recipientPublic,
HashAlgorithmName.SHA256,
null,
new byte[] { 0, 0, 0, 2 });
Encrypt stuff.
byte[] em;
// ECIES uses AES with the all zero IV. Since the key is never reused,
// there's not risk in that.
using (Aes aes = Aes.Create())
using (ICryptoTransform encryptor = aes.CreateEncryptor(ek, new byte[16]))
{
if (!encryptor.CanTransformMultipleBlocks)
{
throw new InvalidOperationException();
}
em = encryptor.TransformFinalBlock(message, 0, message.Length);
}
MAC it
byte[] d;
using (HMAC hmac = new HMACSHA256(mk))
{
d = hmac.ComputeHash(em);
}
Finish
// Either
return Tuple.Create(rBar, em, d);
// Or
return rBar.Concat(em).Concat(d).ToArray();
###Decrypt
Left as an exercise to the reader.
For getting ECDiffieHellman private key from certificate, use the following method:
Install NuGet package Security.Cryptography (CLR Security). (The package is under MIT license.)
Use the following extension method to get the CngKey instance:
CngKey cngKey = certificate.GetCngPrivateKey();
(Note: The extension method certificate.GetECDsaPrivateKey(), natively supported in .NET, returns an ECDsaCng instance; there is no extension method to return ECDiffieHellmanCng.)
The cngKey instance can be used to create either an ECDsaCng or an ECDiffieHellmanCng instance:
var sa = new ECDsaCng(cngKey);
var sa = new ECDiffieHellmanCng(cngKey);

How to sign public PGP key with Bouncy Castle in C#

I want to create web of trust support in my application, allowing my users to use their private keys, to sign other user's public keys - Using C# and Bouncy Castle.
I've got most things figured out, such as creating PGP keys, submitting them to key servers using HTTP REST, encrypting MIME messages and cryptographically signing them (using MimeKit) - But the one remaining hurdle, is to figure out some piece of code that can use my private key, to sign for another person's public key, using Bouncy Castle.
Since the documentation for BC is horrendous, figuring out these parts, have previously proven close to impossible ...
For the record, I'm using GnuPG as my storage for keys.
If anybody wants to look at my code so far for what I have done, feel free to check it out here.
I am probably not supposed to ask this here, but I'd also love it if some BC gurus out there could have a general look at my code so far, and check if I've made a fool of myself with the stuff I've done so far ...
Found the answer after a lot of trial and error, here it is ...
private static byte[] SignPublicKey(
PgpSecretKey secretKey,
string password,
PgpPublicKey keyToBeSigned,
bool isCertain)
{
// Extracting private key, and getting ready to create a signature.
PgpPrivateKey pgpPrivKey = secretKey.ExtractPrivateKey (password.ToCharArray());
PgpSignatureGenerator sGen = new PgpSignatureGenerator (secretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
sGen.InitSign (isCertain ? PgpSignature.PositiveCertification : PgpSignature.CasualCertification, pgpPrivKey);
// Creating a stream to wrap the results of operation.
Stream os = new MemoryStream();
BcpgOutputStream bOut = new BcpgOutputStream (os);
sGen.GenerateOnePassVersion (false).Encode (bOut);
// Creating a generator.
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
PgpSignatureSubpacketVector packetVector = spGen.Generate();
sGen.SetHashedSubpackets (packetVector);
bOut.Flush();
// Returning the signed public key.
return PgpPublicKey.AddCertification (keyToBeSigned, sGen.Generate()).GetEncoded();
}

The requested operation is not supported in CngKey.Create

I'm trying to generate a self-signed certificate on the fly (programmatically) in a C# assembly (targeting .NET 4.0), to serve as a root CA to generate other certificates. The certificate doesn't need to be persisted in the Windows certificate store, I'll export it as a file.
Reading through this question (and in particular, #dthorpe's answer), I decided to give a try to CLR Security.
The CLR Security library put an extension method on CngKey class to generate a self-signed certificate, but I couldn't succeed in creating an instance of CngKey with:
var key = CngKey.Create(CngAlgorithm.Sha1); //same with Sha256, Sha512 and MD5
//or
var key = CngKey.Create(CngAlgorithm.Sha1, null, new CngKeyCreationParameters()
{
ExportPolicy = CngExportPolicies.AllowExport,
KeyUsage = CngKeyUsages.AllUsages,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
});
Any of these lines raises the exception:
System.Security.Cryptography.CryptographicException was unhandled
HResult=-2146893783
Message=The requested operation is not supported.
Source=System.Core
StackTrace:
at System.Security.Cryptography.NCryptNative.CreatePersistedKey(SafeNCryptProviderHandle provider, String algorithm, String name, CngKeyCreationOptions options)
at System.Security.Cryptography.CngKey.Create(CngAlgorithm algorithm, String keyName, CngKeyCreationParameters creationParameters)
at System.Security.Cryptography.CngKey.Create(CngAlgorithm algorithm)
at Tests.Program.Main(String[] args) at Program.cs:line 51
Searching through SO and the internet, I've checked the following:
I'm running a Windows 7 box (so it supports RPC as per MSDN)
Tried on a Windows Server 2012 box, same error
The process is running as admin (so it have access to all cert storages, anyway)
The services CNG Key Isolation and Remote Procedure Call (RPC) are running
Any help would be appreciated.
Small off-topic: during google search for this question found a site with HRESULT descriptions and handy search tool on SO and MSDN (I simply googled for your HRESULT code -2146893783)
I found a topic on MSDN which contains code failing with similar HRESULT, and the author provides a link to MSDN article about CNG:
NCRYPT_ALGORITHM_GROUP_PROPERTY
L"Algorithm Group"
A null-terminated Unicode string that contains the name of the object's algorithm group. This property only applies to keys. The following identifiers are returned by the Microsoft key storage provider:
NCRYPT_RSA_ALGORITHM_GROUP
"RSA", The RSA algorithm group.
NCRYPT_DH_ALGORITHM_GROUP
"DH", The Diffie-Hellman algorithm group.
NCRYPT_DSA_ALGORITHM_GROUP
"DSA", The DSA algorithm group.
NCRYPT_ECDSA_ALGORITHM_GROUP
"ECDSA", The elliptic curve DSA algorithm group.
NCRYPT_ECDH_ALGORITHM_GROUP
"ECDH", The elliptic curve Diffie-Hellman algorithm group.
Also I found an article on MSDN about CNG Key Storage Providers, which contains similar list of the algorithms:
Diffie-Hellman (DH)
Secret agreement and key exchange, 512 to 4096 in 64-bit increments
Digital Signature Algorithm (DSA)
Signatures, 512 to 1024 in 64-bit increments
Elliptic Curve Diffie-Hellman (ECDH)
Secret agreement and key exchange, P256, P384, P521
Elliptic Curve Digital Signature Algorithm (ECDSA)
Signatures, P256, P384, P521
RSA
Asymmetric encryption and signing, 512 to 16384 in 64-bit increments
So, as you've said that you've tried only Sha1, Sha256, Sha512 and MD5, maybe you simply use another algorithm from list available? You can find there ones mentioned above:
RSA
ECDsa
P256
P384
P521
ECDiffieHellman
P256
P384
P521
Here other developers successfully created one of them and was able to export it:
var cngKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256, null,
new CngKeyCreationParameters { ExportPolicy = CngExportPolicies.AllowPlaintextExport });

Crypto API functions equivalent in C#

Earlier our Application-A was in C++ and a message was signed before sending it to Application-B using crypto API functions in C++ , exactly similar to the example described in http://msdn.microsoft.com/en-us/library/windows/desktop/aa382372%28v=vs.85%29.aspx.
This message was again verified by Application-B using Crypto API functions in C++ (the above example again talks about how to verify an already signed message).
Now we are in the process of converting/migrating the old C++ Application-A to C#.
I already found a way to sign the message using P-Invoke in C# and when the signed message was verified by Application-B (using C++ CryptVerifySignatureMessage) everything is working fine.
Example is available in - http://blogs.msdn.com/b/alejacma/archive/2008/02/21/how-to-sign-a-message-and-verify-a-message-signature-c.aspx .
As #CodeInChaos has mentioned in his comments i want the leave the interop work to the framework (without using P-Invoke or other 3rd party implementation like BountyCastle)
So would like to know whether .net offers any API to sign a message (as a learning perspective too) , if so how can i achieve it.
NOTE:
I already tried crypto wrapper API RSACryptoServiceProvider offered by .Net.
private byte[] SignData(byte[] data, string certThumbPrint)
{
X509Certificate2 cert = GetCertificate(); // finds the certificate with thumbprint
RSACryptoServiceProvider rsaCryptoServiceProvider = (RSACryptoServiceProvider)cert.PrivateKey;
return rsaCryptoServiceProvider.SignData(data, new SHA1CryptoServiceProvider());
}
But found a major difference with the return value (byte array) of CryptSignMessage from C++ and RSACryptoServiceProvider.SignData() method from C#.
• CryptSignMessage: The CryptSignMessage function creates a hash of the specified content, signs the hash, and then encodes both the original message content and the signed hash.
• RSA.SignData: Computes the hash value of the specified byte array using the specified hash algorithm, and signs the resulting hash value.
Because of this difference , the Application-B when it verifies the message it throws error saying 'invalid signing' .
So i cant use this RSACryptoServiceProvider type offered by .net.
Is there any other way to achieve the same using any .NET API's ? (when using .net API the output byte array should be similar to that of output when using PInvoke example as mentioned above) so that Application-B can work without any issues.
Any help is appreciated.
After some long research i found a way to do it . If someone else is looking for how to sign a message using PKCS7 format using a certificate in C# then here it is,
public byte[] SignMsg(
Byte[] msg,
X509Certificate2 signerCert)
{
// Place message in a ContentInfo object.
// This is required to build a SignedCms object.
ContentInfo contentInfo = new ContentInfo(msg);
// Instantiate SignedCms object with the ContentInfo above.
// Has default SubjectIdentifierType IssuerAndSerialNumber.
// Has default Detached property value false, so message is
// included in the encoded SignedCms.
SignedCms signedCms = new SignedCms(contentInfo);
// Formulate a CmsSigner object, which has all the needed
// characteristics of the signer.
CmsSigner cmsSigner = new CmsSigner(signerCert);
// Sign the PKCS #7 message.
Console.Write("Computing signature with signer subject " +
"name {0} ... ", signerCert.SubjectName.Name);
signedCms.ComputeSignature(cmsSigner);
Console.WriteLine("Done.");
// Encode the PKCS #7 message.
return signedCms.Encode();
}
Found the information from the link http://msdn.microsoft.com/en-us/library/ms180961%28v=vs.85%29.aspx .

Categories

Resources