Using RSA with my private key by C# - c#

I'm provided a private key (a string). I have to generate a public key by that private key to encrypt data.
I don't know how to do. Please help me. Thank you.

Simply by having the private key you can not generate a public key.
Private and public keys are generated in pair and should be provided to you for encrypting data.
However you still can sign data using private key alone.

var keypair = "Your keypair in xml format";
using (var rsa = new RSACryptoServiceProvider()) {
rsa.FromXmlString(keypair);
var publicKeyInXmlFormat = rsa.ToXmlString(false);
}

Related

How to encrypt plain text using RSA asymmetric encryption

I am working on an application where I need to encrypt plain text using the RSA algorithm. I encrypt the plain text but it is not working as it gives Error Decoding Text. Basically, I am calling third-party API which gives me the error. When I encrypt my text using this link reference link it works perfectly fine so I think I am doing something wrong. Here is my code
public static string Encryption(string strText)
{
var publicKey = #"<RSAKeyValue><Modulus>MIIDSjCCAjKgAwIBAgIEWrJUKTANBgkqhkiG9w0BAQsFADBmMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmF5ZXJuMQ8wDQYDVQQHDAZNdW5pY2gxDzANBgNVBAoMBkxl
eGNvbTEkMCIGA1UEAwwbQWdyb3BhcnRzX0RNU19CYXNrZXRfVXBsb2FkMCAXDTE4
MDMyMTEyNDYzM1oY################################################
A1UECAwG########################################################
################################################################
WaOa0parvIrMk9/#################################################
NCIeGu+epwg8oUCr6Wd0BNATNjt8Tk64pgQvhdX9/KRDSC8V4QCJBiE3LQPHUVdN
nWRixrcOpucMo6m9PPegjnicn/rBKdFZLfJqLHHm+TrHrNCsEQIDAQABMA0GCSqG
SIb3DQEBCwUAA4IBAQBGwlNnDh2UaZphkEf70MPhySFVnTnLSxUFuwuWaDu8l7YP
zBMeJxcNk3HNiXPeba03GQBj+JqGAwDALJLityGeGEzlESfv/BsgQOONt+lAJUjs
b7+vr2e5REE/dpJZ1kQRQC##########################################
np+GstsdWjIWbL6L6VoqU18qLO5b0k8OoEMsP3akUTcj0w8JwD5V5iLqDhnv1aXK
kntkd/QmVCY6zlzH/dnTh8RNO2CfRtB1GEzNnkJB</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
rsa.FromXmlString(publicKey);
byte[] data = Encoding.UTF8.GetBytes(strText);
byte[] cipherText = rsa.Encrypt(data,true);
var base64Encrypted = Convert.ToBase64String(cipherText);
return base64Encrypted;
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
}
}
Here is my public key. I am using an RSA certificate. I am passing the certificate key to the module tag here is my key. I think I might be using it wrong.
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIEWrJUKTANBgkqhkiG9w0BAQsFADBmMQswCQYDVQQGEwJE
RTEPMA0GA1UECAwGQmF5ZXJuMQ8wDQYDVQQHDAZNdW5pY2gxDzANBgNVBAoMBkxl
eGNvbTEkMCIGA1UEAwwbQWdyb3BhcnRzX0RNU19CYXNrZXRfVXBsb2FkMCAXDTE4
MDMyMTEyNDYzM1oY################################################
A1UECAwG########################################################
################################################################
WaOa0parvIrMk9/#################################################
NCIeGu+epwg8oUCr6Wd0BNATNjt8Tk64pgQvhdX9/KRDSC8V4QCJBiE3LQPHUVdN
nWRixrcOpucMo6m9PPegjnicn/rBKdFZLfJqLHHm+TrHrNCsEQIDAQABMA0GCSqG
SIb3DQEBCwUAA4IBAQBGwlNnDh2UaZphkEf70MPhySFVnTnLSxUFuwuWaDu8l7YP
zBMeJxcNk3HNiXPeba03GQBj+JqGAwDALJLityGeGEzlESfv/BsgQOONt+lAJUjs
b7+vr2e5REE/dpJZ1kQRQC##########################################
np+GstsdWjIWbL6L6VoqU18qLO5b0k8OoEMsP3akUTcj0w8JwD5V5iLqDhnv1aXK
kntkd/QmVCY6zlzH/dnTh8RNO2CfRtB1GEzNnkJB
-----END CERTIFICATE-----
Any help would be highly appreciated. The encryption through this code is not working. But when I used the mentioned link above and pass this key it worked fine.
The answer to my question is here. I solved my problem and I am posting it because maybe someone in the future will have the same issue I am facing and what mistake I did to achieve my requirements.
Findings
I found during my research there is a difference between Public Key and Certificate. I miss understood the terminology I was passing a certificate instead of passing Public Key for encryption. So one of the community members #Topaco basically redirected me to the correct path which helps me to solve my problem. There are steps involved if you have a public key then you can achieve encryption but if you have a certificate then first you need to get the public key by using the method GetRSAPublicKey. When you got your public key in XML form then you pass it to encrypt method to get your result.
Here is the coding
Program.cs
var x509 = new X509Certificate2(File.ReadAllBytes(#"D:\xyz.cer"));
string xml = x509.GetRSAPublicKey().ToXmlString(false);
var result = EncryptUtil.Encryption("start01!", xml);
Utility Class
public static string Encryption(string strText, string publicKey)
{
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
rsa.FromXmlString(publicKey);
byte[] data = Encoding.UTF8.GetBytes(strText);
byte[] cipherText = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);
var base64Encrypted = Convert.ToBase64String(cipherText);
return base64Encrypted;
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
So you can achieve encryption using the above code you need to pass RSAEncryptionPadding.Pkcs1 for encryption.
#happycoding #keephelping

Why do exported ECDSA keys look similar?

I use this snippet to see private and public keys generated by DSA:
byte[] publicKey, hash, signedHash;
string strToSign = "Hello, world!";
SHA512Managed shaComputer = new SHA512Managed();
using (ECDsaCng dsaSigner = new ECDsaCng())
{
publicKey = dsaSigner.Key.Export(CngKeyBlobFormat.GenericPublicBlob);
Console.WriteLine($"DSA public key: {TransformHash(publicKey)}");
Console.WriteLine();
byte[] privateKey = dsaSigner.Key.Export(CngKeyBlobFormat.GenericPrivateBlob);
Console.WriteLine($"DSA private key: {TransformHash(privateKey)}");
Console.WriteLine();
}
But I see theese keys look very similar, because private key starts with public key:
Is that normal?
"because private key starts with public key
I believe this is the case. This is documented for GenericPrivateBlob:
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cngkeyblobformat.genericprivateblob?redirectedfrom=MSDN&view=netframework-4.7.2
A generic private key BLOB can contain a private key of any type and does not necessarily contain the corresponding public key. The type of key that the BLOB contains can be determined only by examining the BLOB.
Emphasis mine, however in this case it does look like the public key is prepended before the private key.

How can verify without private key (NBitcoin)

I am using NBitcoin nuget package. I try to create private and pub key(address). And after that , I try to sign to some message and then verify the this signature with pub key. But NBitcoin , for the verify using the BitcoinSecret object which is the has private key object. So , why for the verify NBitcoin using this object? And How can I verify signature without private key , just using address(pubKey),signature and message ?
Thanks
static void Main(string[] args)
{
Key Key = new Key(); //Create private key
//We can take private key
var privateKey = Key.GetBitcoinSecret(Network.Main);
//Get the public key, and derive the address on the Main network
BitcoinAddress address = privateKey.PubKey.GetAddress(Network.Main);
For the sign to data , create secret object.
BitcoinSecret secret = new BitcoinSecret(Key, Network.Main);
string message = $"I am Nicolas";
Console.WriteLine("Message:" + message + "\n");
sign message with private key.
string signature = secret.PrivateKey.SignMessage(message);
Console.WriteLine("Signature:" + signature + "\n");
/* Now I dont understand this code. For the verify , I know that we need
to signature message , message and pub or adres value.\n But in this code using
again private secret object which has got private key. How we can verify
signature messaga with pub or address and message (dont include private key)*/
if (secret.PubKey.VerifyMessage(message, signature))
{
Console.WriteLine("thats okey");
}
Console.Read();
}
The public key can not exist without the private key, as the public key is derived from the private key by utilizing some kind of one-way-function. If you want to use the public key without the private key, then generate it from the private key, like you did
var pubKey = privateKey.PubKey;
store the public key to some location the verifyer has access to
File.WriteAllBytes("some/public/location/MyPubKey.key", pubKey.ToBytes());
let the verifyer read the public key without ever knowing of the private key
var pubKeyForVerification = File.ReadAllBytes("some/public/location/MyPubKey.key");
This is all there is to it. It is safe to store the public key anywhere you want, because it's practically impossible to learn the private key from it.

EC private key to CngKey in C#

I need to convert a EC private key generated by BouncyCastle to a CngKey in C#. Ultimately, I'm trying to create a PKCS12 that can be imported into the Windows Key Store and am following the information and code example found here.
The EC key pair is generated as follows:
var ecKeyPairGenerator = new ECKeyPairGenerator("ECDSA");
ECKeyGenerationParameters ecKeyGenParams = new ECKeyGenerationParameters(SecObjectIdentifiers.SecP384r1, new SecureRandom());
AsymmetricCipherKeyPair pair = ecKeyPairGenerator.GenerateKeyPair();
To create a CngKey:
PrivateKeyInfo privKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.Private);
CngKey cngPrivKey = CngKey.Import(privKeyStruct.GetDerEncoded(), CngKeyBlobFormat.Pkcs8PrivateBlob);
Searching on the web, the above should work, e.g., see here. Instead, I'm getting an Unknown error exception
(CryptographicException) at
System.Security.Cryptography.NCryptNative.ImportKey(). If I pass
CngKeyBlobFormat.EccPrivateBlob to CngKey.Import(), I get an
invalid data exception.
As a new newbie to both .NET, CNG, and Cryto, I feel I'm overlooking something. Any ideas would be appreciated.
Thanks!

Bouncycastle: what does the subKeyID-Parameter of AddKeyTransRecipient do?

I'm trying to asymetrically encrypt a message of arbitrary length with bouncycastle. (1.4+ with C#)
This is the code I have right now. It is supposed to (but doesn't) generate a CMS message where the data itself is encrypted with AES256 with a random key and the key is encrypted with the public key from keyPair.
keyPair is an RSA-Key (RsaKeyParameters)
public static byte[] Encrypt(byte[] input, AsymmetricCipherKeyPair keyPair)
{
CmsEnvelopedDataGenerator generator = new CmsEnvelopedDataGenerator();
// those two lines are certainly wrong.
// I have no idea what the subKeyID parameter does
byte[] subKeyId = new byte[] {};
generator.AddKeyTransRecipient(keyPair.Public, subKeyId);
CmsProcessableByteArray cmsByteArray = new CmsProcessableByteArray(input);
CmsEnvelopedData envelopeData =
generator.Generate(cmsByteArray, CmsEnvelopedDataGenerator.Aes256Cbc);
return envelopeData.GetEncoded();
}
What is the subKeyId parameter in the Encrypt method for and what value does it need to have?
aaronls is being a little unfair to the author of "Beginning cryptography with Java", who after all wrote all the unit tests himself in the first place...
As other commenters have pointed out, CMS works with certificates, you can't just pass a public key; it must be possible to refer to the key either by "SubjectKeyIdentifier" or by "IssuerAndSerialNumber". The two alternatives of AddKeyTransRecipient allow this. If these terms don't mean anything to you, you probably need to do some background reading on X.509.
Look at the function TryKekAlgorithm in the EnvelopedDataTest.cs file of the BouncyCastle source. Instead of doing AddKeyTransRecipient, they are doing AddKekRecipient.
public static byte[] Encrypt(byte[] input, AsymmetricCipherKeyPair keyPair)
{
CmsEnvelopedDataGenerator generator = new CmsEnvelopedDataGenerator();
DerObjectIdentifier algOid = //initialize
//Still trying to figure out kekId here.
byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
string keyAlgorithm = ParameterUtilities.GetCanonicalAlgorithmName("AES256");
generator.AddKekRecipient(keyAlgorithm, keyPair.Public, kekId);
CmsProcessableByteArray cmsByteArray = new CmsProcessableByteArray(input);
CmsEnvelopedData envelopeData =
generator.Generate(cmsByteArray, CmsEnvelopedDataGenerator.Aes256Cbc);
return envelopeData.GetEncoded();
}
Edit: I think the kekId is just a unique identifier used to reference the key. Just a way to "name" the key. So you can have a book of keys, and each one has an identifier. When you send an encrypted message, the unencrypted key identifier tells you which of the keys was used to encrypt the message.
Here is a pretty good explanation of key identifiers on page 140:
[http://books.google.com/books?id=Pgg-Es2j3UEC&pg=PA140&lpg=PA140&dq=understanding+key+identifiers+encrypt&source=bl&ots=nFg0BzM2ht&sig=Ux5sreXMKyuEEZu0uaxE7cXC1VI&hl=en&ei=JKKJStbHGJivtgffsNznDA&sa=X&oi=book_result&ct=result&resnum=6#v=onepage&q=&f=false][1]
And here is another book that is using BouncyCastleCrypto, but it looks like they did little more than rip off the unit test source code. They have explained it a little:
[http://books.google.com/books?id=WLLAD2FKH3IC&pg=PA343&lpg=PA343&dq=CmsEnvelopedDataGenerator+AddKekRecipient&source=bl&ots=O9HinJm3yB&sig=K5Z99DIVWW4-0abPIFR7x4lzBhU&hl=en&ei=g6aJSrjeDuHktgennNjnDA&sa=X&oi=book_result&ct=result&resnum=6#v=onepage&q=CmsEnvelopedDataGenerator%20AddKekRecipient&f=false][2]
To use AES, it is not enough to use a AsymmetricCipherKeyPair.
You should use a X509 certificate, where the public key is signed by an certificate authority (CA).
the subKeyId is an attribute of the certificate, the subject Key Identifier:
(X509Certificate) cert.getSubjectUniqueID()
To encrypt a message of artrary length, you should use AES only to exchange a symmetric Keypassword and use this key for symmetric encryption.

Categories

Resources