how to find paired ECDSA private key PKCS11 having public key - c#

I have an application that works with smartcards that have RSA certificates on them
For some reason manufacturer does not fill CKA_LABEL on them, so i fidn private key object for RSA like this:
RsaKeyParameters rsaPubKeyParams = (RsaKeyParameters)pubKeyParams;
privKeySearchTemplate.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
privKeySearchTemplate.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODULUS, rsaPubKeyParams.Modulus.ToByteArrayUnsigned()));
privKeySearchTemplate.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PUBLIC_EXPONENT, rsaPubKeyParams.Exponent.ToByteArrayUnsigned()));
now i have to support smartcards that have ECDSA certificates, no CKA_LABEL also
SO the question is how can i find according private key like with RSA ?
Note: all smart cards have 2 certificates (auth,sign) in random order, so i cant just take first or last object found:
ECPublicKeyParameters ecdsaPubKeyParams = (ECPublicKeyParameters)pubKeyParams;
privKeySearchTemplate.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_ECDSA));
-----some more params needed to identify the needed the private key

If it is the same curve, you can't.
A workaround would be to test a signature/verification, then if match, assign CLA_LABEL to optimize for next time.

If you set a unique LABLE or ID for key, you can recover key-pair easily. Then, public key is the one which has CKA.CKA_VERIFY attribute as True and private key is the one which has CKA.CKA_SIGN attribute set to True.
Another tip: for RSA you have its modules and exponent, for elliptic key you have its ec-point CKA.CKA_EC_POINT which is unique for any elliptic-public-key.

Related

Key is not a valid public or private key

I am trying to import key pair created by RSACryptoServiceProvider into ECDiffieHellmanOpenSsl:
RSACryptoServiceProvider keyPair = EncryptionTools.GenerateRSAKeyPair(4096);
ECDiffieHellmanOpenSsl alice = new ECDiffieHellmanOpenSsl();
int publicBytesReadAlice = 0;
alice.ImportSubjectPublicKeyInfo(new ReadOnlySpan<byte>(keyPair.ExportSubjectPublicKeyInfo()), out publicBytesReadAlice);formát
int privateBytesRead = 0;
alice.ImportPkcs8PrivateKey(new ReadOnlySpan<byte>(keyPair.ExportPkcs8PrivateKey()), out privateBytesRead);
It is throwing this error on fifth line:
System.Security.Cryptography.CryptographicException: Key is not a valid public or private key.
I don't know where the issue is because docs say:
ECDiffieHellman.ImportSubjectPublicKeyInfo: Imports the public key from an X.509 SubjectPublicKeyInfo structure after decryption, replacing the keys for this object. Source is: The bytes of an X.509 SubjectPublicKeyInfo structure in the ASN.1-DER encoding.
AsymmetricAlgorithm.ExportSubjectPublicKeyInfo: Exports the public-key portion of the current key in the X.509 SubjectPublicKeyInfo format.
The same thing happens when trying to import RSA private key, which is supposed to be in Pkcs8 format.
Any idea how to correctly export/serialize keys and pass it to ECDiffieHellmanOpenSsl? And any idea how to serialize it to string?
RSA keys and ECDH-compatible keys are extremely different beasts. It's not even quite "square peg, round hole", but more like "color green, round hole". They're both asymmetric keys, which means they're both compatible with the SPKI and PKCS8 formats, though. (Both of those formats are basically "here's the kind of key I am" and "here's some data of the format appropriate to that key")
ECDH can load in any key created by an ECDsa or ECDH instance.
ECDsa can load in any key created by an ECDsa instance, and most keys created by an ECDH instance.
RSA can only load keys created by an RSA instance.
DSA can only load keys created by a DSA instance.
(for all of those statements the keys can also be created by a compatible notion on some other platform or some other library set).
So, if you want to serialize an ECDH, just start by creating an ECDH (e.g. ECDiffieHellman.Create(ECCurve.NamedCurves.nistP521)).
For text versions, .NET 7 is adding straight-to-PEM versions (e.g. key.ExportSubjectPublicKeyInfoPem()). For earlier versions you can use PemEncoding, e.g. PemEncoding.Write("PUBLIC KEY", key.ExportSubjectPublicKeyInfo()).

NSec.Cryptography encrypt and decrypt using ChaCha20Poly1305 and SharedSecret

I'm trying to encrypt (and decrypt) messages send from one device to another by using NSec.Cryptography, but I find the documentation a bit vague. As I understood I need a Key and PublicKey of device A and B, respectively. I can turn these into a SharedSecret:
var sharedSecret = KeyAgreementAlgorithm.X25519.Agree(encryption.Key, deviceKey);
However, this shared secret doesn't seem useful for encryption as the Encrypt(...) method asks for a Key in its parameters:
var cyphertext = AeadAlgorithm.ChaCha20Poly1305.Encrypt(sharedSecret, nonce, new byte[0], message);
^-- will not work
I have multiple questions:
What is the use of SharedSecret if it can not be used to encrypt?
How is the ChaCha20Poly1305.Encrypt method useful if it uses one key which can't be a shared secret?
How do I encrypt a message using the private key of A and public key of B (like box and secret box in libsodium)?
Note: I wanna use X25519 keys.
Read the documentation for SharedSecret:
Represents the output of a key agreement and the input for key derivation
So you first need to generate one or more keys using a specific KDF and NSec seems to implement HKDF (using SHA-256 or-512, I'd prefer the latter because it is more secure and - on 64 bit machines - possibly even faster. The shared secret itself is not fully random to an adversary, so a KDF is required to create the most cryptographically secure keys from it.
This should answer 1 & 2: SharedSecret is used to derive the actual keys, it isn't a key in itself.
How do I encrypt a message using the private key of A and public key of B (like box and secret box in libsodium)?
As for 3: You need an ephemeral key pair on the sender A and the public key of receiver B. Then you perform the key agreement & key derivation (as above) using the sender's ephemeral private key and send the ephemeral public key with the ciphertext. Don't forget to destroy the ephemeral private key of the sender after the key agreement; you don't need it anymore, and leaking it will compromise the ciphertext.
The receiver can now perform the same agreement using their static private key and the received ephemeral public key, and finally decrypt the message.

RSA Crypto: Is it require to store keypair after geneating first time

Once public/private key generated then, is this has to store or persist on storage So, when decryption call then same private key (related to public key) is used ?
Basically, there will be two separate endpoints for RSA encrypt and decryption.
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
var pu = rsa.ToXmlString(false);
var pr = rsa.ToXmlString(true);
}
Yes, in almost all cases you need to store the private key permanently. You could use RSA for one-time key establishment. However, creating a key pair is relatively slow for RSA, so RSA is not commonly used for this.
Note that you may also create a key pair where the private key remains in a key container such as a key store. For instance, most smart cards have been designed in such a way that the private key never leaves the device; it is simply used when required. The key is automatically persisted after creation. So you would not be able to retrieve the values of them and convert them to XML.
Storing keys in the Microsoft proprietary XML format without any protection - as performed in the code within the question - is not a good idea.

Sign a string against an RSA Public Key

I'm using C# and I'm trying to sign a string with a key produced from the PuTTY Key Generator. I'm not quite sure what I'm doing because I can't see how to import a key into the RsaEngine
I looked at the following:
AsymmetricKeyParameter key = new RsaKeyParameters(false, ???, ???);
RsaEngine rsa = new RsaEngine();
rsa.Init(true, key);
but it seems that RsaKeyParameter and AsymmetricKeyParameter take a modulus and a exponent which I don't know how to get from my already generated key? I could be using the wrong class though so if anyone has any pointers on this that would be excellent
I looked at: RSA signing and verification with C#,BouncyCastle and imported RSA key - Working Python example and non-working C# code sample inside but answer has a non existent function:
ConvertToRSAPrivateKey
You can first convert the PuttyGen keys into OpenSSH compatible keys and then convert this well documented format to C#.
The best I can come up with is this class of the SSH.NET library code.
In the mean time, please note that you are better off generating the key in the actual library that you want to use. Key formats, especially private key formats, are not always compatible.

How do I get certificate's key size

I have an X.509 certificate and need to get the size of its key (in bits) - e.g., 1024 2048 etc. I have looked at X509Certificate2 and also the bouncycastle X509Certificate classes but can't see how to get the key size.
You surely have access to the public key. The key length is public key's size: this.PublicKey.Key.KeySize;
To see an implemented solution, check out this article on MSDN

Categories