(En|De)crypt data with static private/public key with RSA - c#

I've seen many examples of how to use RSA in C# with random generated keys, but none with static keys. I need this is because my program client stores the public key (n, e) statically, and the server stores the private (d, n) and public keys statically too.
If I create a RSAParameters and store the Modulus=n and Exponent=e values and call ImportParameters, I can successfully encrypt data, but if I create a new RSAParameters and store the Modulus=n and D=d values, when I call the ImportParameters method, a System.Security.Cryptography.CryptographicException is thrown.
Is there a way to decrypt the data with only the D and N values?

Try to encode the values in a PKCS#1/PKCS#8 format. That way you can retrieve the keys back from any framework as well. The best way to do this is to use the Bouncy Castle framework. I've included some pointers to questions about importing/exporting keys to/from a C# application.
How to convert pkcs8 key file to DER format in #C?
Creating PKCS1 public key in Net Framework

Related

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

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?

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

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.

C# Verify Json string via signature and RSA public key

I'm creating an IAP plugin for the local Android market that I think has similar API as google play.
I build an Android side and it will return all response from the market to the unity c# side.
All part working fine but I can't figure out how to verify the signature of the response.
I'm new in cryptography and searching day to day about this.
Please correct me if I'm wrong.
They use a hash algorithm to sign data and encrypt that hash with private key.
I must decrypt signature with public key and compare hashes.
This is my public key (Base64):
MIHNMA0GCSqGSIb3DQEBAQUAA4G7ADCBtwKBrwDltnT/AaF3oMt+F3lza5JEvce0GLS1L9v9Z53lQ3LNluGk0eI2ukgWm7tAiIOLQgn11Sb9mW2VWkYTWGnZ1AZtY0GwdUQJUr7u3CWNznE6XH4UCVOVhGDCLnFrG8BcfDelhcfReGZQ3izOefhc4Oq6vZf5PfLwximK+FH27fR6XL8vg3yyK4LSwT764Dfd6H3IGes6EdTx/C3C690jdyMvhi2Q3qBiqfepHzW/jV8CAwEAAQ==
This key is in ASN.1 DER format.
I break it out and find this data:
SEQUENCE
SEQUENCE
OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption(PKCS #1)
NULL
BIT STRING
SEQUENCE
INTEGER 969837669069837851043825067021609343597253227631794160042862620526559…
INTEGER 65537
As I read on net first INTEGER is Modules and second INTEGER is Exponent
So in c# write a code like this =>
var parameter = new RSAParameters
{
Modulus = HexToByteArray(/* "first_INTEGET" */),
Exponent = BitConverter.GetBytes(/* "second_INTEGER" */)
};
Market send me a Json like this:
{"orderId": "0j8oJgE0Bett-neB", "purchaseToken": "0j8oJgE0Bett-neB", "developerPayload": "payload", "packageName": "com.some.market", "purchaseState": 0, "purchaseTime": 1520676644872, "productId": "card-1"}
The signature is like this:
hTFeQd25PZJ2DhGmXd0eO+C+oBeWsg983I4e5ztXtKAUrOIaNBaqAxHU3vW8acBs1I9fE5cxx/DI/sQGY4QSvpDnSm9aYz3do3joHPOXIVvXjSJfejxwzp9DKMUPd6LrgtxkaGevG+94NuKHFxpCdZlovEPXRJZyEznbASuYLqeW0KjP3jnvvw2O5iNlQRdh98h4Q18bSsaxq9zaRKExFLHkhNf/yO5m84kRB1G8
I'm searched for a method to do this but I don't know which method is true for me.
My verify code is this:
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(parameter);
var hash = new SHA1Managed();
bool dataOK =
rsa.VerifyData(hash.ComputeHash(Encoding.UTF8.GetBytes(json)), CryptoConfig.MapNameToOID("SHA1"), Encoding.UTF8.GetBytes(signature));
}
How truly convert signature to byte[] to verify? (with encoding or what???)
I'm searching a lot but more search more confuse.
Am I going the wrong way or using wrong method or ...?
Why should workflow be complicated?
Can anyone help me, please?
Thanks.
OK, I'll answer in order:
They use a hash algorithm to sign data and encrypt that hash with private key. I must decrypt signature with public key and compare hashes.
No, that's not correct. You should use a signature verification method, as you're currently doing. Seeing signature as encryption of a hash is incorrect; even the latest RSA standards go out of their way to explain this. For RSA the internal padding method is different. For ECDSA there is no direct encryption/decryption possible using the same scheme.
As I read on net first INTEGER is Modules and second INTEGER is Exponent
Yes, although it is spelled modulus, not modules. It is the public exponent, there is also a private exponent for the private key. Also without the caps.
How truly convert signature to byte[] to verify? (with encoding or what???)
Standard Base 64 is already mentioned in the comment section. Note that the key and signature size are not common (but that's OK in itself).
Why should workflow be complicated?
Well, somebody has to code it in the end and crypto is hard. But to make it easier for you: the entire ASN.1 structure is called a SubjectPublicKeyInfo structure; if you look on the internet you will find pre-made code to import from such a structure.
To finally verify the structure: make sure that you use the correct signature format (RSA-PKCS#1 v1.5 or RSA-PSS) and that you know exactly which binary data is fed to the signature generation function. For instance, the signature over the JSON could be in ASCII or UTF-8 or it could be in UTF-16 LE or BE.
Better ask the creator of the signature.

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