How to generate RSA-PSS key in .NET Framework 4.8? - c#

I get just signature padding with pss. But i need RSA-PSS key algorithm. How can i get it?
i use new KeyGenerationParameters(SecureRandom.GetInstance("SHA256PRNG"), sizeInBits) for generation.
UPD: I sign certificate by this key, and i have just rsa encryption in public data. How i can get rsapss in this field?

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()).

how to find paired ECDSA private key PKCS11 having public key

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.

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.

Bad Key Exception using RSACryptoServiceProvider

The key exchange method is: RSA-PKCS1-KeyEx
So I don't think the answers in other similar questions apply and I have no control over the certificate - it's valid and is supposed to work.
.NET Framework 3.5
The code:
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] bytestodecrypt = Convert.FromBase64String(SignatureValue);
byte[] plainbytes = rsa.Decrypt(bytestodecrypt, false);
Screenshot of the attributes of the rsa object:
While RSA can do both signatures and encryption, they can't be used interchangeably (except for at the raw/"no padding" version of the algorithm, which .NET does not support; and even then the keys are "backwards").
The signature blob is computed by "encrypting" with the private key. It gets "decrypted" by the public key, and then the underlying system compares it with the provided hash and hash algorithm. If they both match, it returns true; otherwise it returns false (or might throw an exception if it gets really confused).
So rather than rsa.Decrypt(signature, false) you want rsa.VerifyHash(hash, signature, hashAlgorithm, RSASignaturePadding.Pkcs1), which returns a bool.
The "bad key" exception is because you only have a public key (which is sufficient for verify) but called decrypt (which requires the private key).

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.

Categories