How to unwrap a key using RSA in Bouncy castle c#? - c#

How do I unwrap a key using RSA private key in Bouncy castle? I receive the already wrapped key which was wrapped using the RSA public key. I have the RSA key pair. I just cannot find the api in the C# Bouncy Castle that I can use to unwrap it.
This code in the C# source code (https://github.com/bcgit/bc-csharp) is currently commented out. The commented out lines for the RSA is exactly what I need, but when I try to use them it seems that its been removed or never implemented
Key key = cipher.unwrap(wrappedKey, "RSA", IBufferedCipher.PRIVATE_KEY);
The line above is exactly what I need. Why has it been commented out? The full function in WrapTest.cs is given below:
public ITestResult Perform()
{
try
{
// IBufferedCipher cipher = CipherUtilities.GetCipher("DES/ECB/PKCS5Padding");
IWrapper cipher = WrapperUtilities.GetWrapper("DES/ECB/PKCS5Padding");
IAsymmetricCipherKeyPairGenerator fact = GeneratorUtilities.GetKeyPairGenerator("RSA");
fact.Init(
new RsaKeyGenerationParameters(
BigInteger.ValueOf(0x10001),
new SecureRandom(),
512,
25));
AsymmetricCipherKeyPair keyPair = fact.GenerateKeyPair();
AsymmetricKeyParameter priKey = keyPair.Private;
AsymmetricKeyParameter pubKey = keyPair.Public;
byte[] priKeyBytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(priKey).GetDerEncoded();
CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator("DES");
// Key wrapKey = keyGen.generateKey();
byte[] wrapKeyBytes = keyGen.GenerateKey();
KeyParameter wrapKey = new DesParameters(wrapKeyBytes);
// cipher.Init(IBufferedCipher.WRAP_MODE, wrapKey);
cipher.Init(true, wrapKey);
// byte[] wrappedKey = cipher.Wrap(priKey);
byte[] wrappedKey = cipher.Wrap(priKeyBytes, 0, priKeyBytes.Length);
// cipher.Init(IBufferedCipher.UNWRAP_MODE, wrapKey);
cipher.Init(false, wrapKey);
// Key key = cipher.unwrap(wrappedKey, "RSA", IBufferedCipher.PRIVATE_KEY);
byte[] unwrapped = cipher.Unwrap(wrappedKey, 0, wrappedKey.Length);
//if (!Arrays.AreEqual(priKey.getEncoded(), key.getEncoded()))
if (!Arrays.AreEqual(priKeyBytes, unwrapped))
{
return new SimpleTestResult(false, "Unwrapped key does not match");
}
return new SimpleTestResult(true, Name + ": Okay");
}
catch (Exception e)
{
return new SimpleTestResult(false, Name + ": exception - " + e.ToString());
}
}

I'm not entirely clear on what you need, but you can use RSA keys to wrap and unwrap AES keys in Bouncycastle. Here is a Java example that creates an RSA keypair, saves the private key to a file, and then saves an AES key that has been wrapped in the public key.
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
public class Main {
private static final SecureRandom rand = new SecureRandom();
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024, rand);
KeyPair kp = kpg.generateKeyPair();
// Write out private key to file, PKCS8-encoded DER
Files.write(Paths.get("privkey.der"), kp.getPrivate().getEncoded());
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256, rand);
SecretKey aesKey = kg.generateKey();
Cipher c = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
c.init(Cipher.WRAP_MODE, kp.getPublic(), rand);
byte[] wrappedKey = c.wrap(aesKey);
// Write out wrapped key
Files.write(Paths.get("wrappedkey"), wrappedKey);
}
}
And here is a C# example that consumes the output from the Java example and unwraps the AES key.
using System.IO;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace RSADecryptWithBouncy
{
class MainClass
{
private static KeyParameter Unwrap(byte [] key, AsymmetricKeyParameter privKeyParam) {
var wrapper = WrapperUtilities.GetWrapper("RSA/NONE/PKCS1PADDING");
wrapper.Init(false, privKeyParam);
var aesKeyBytes = wrapper.Unwrap(key, 0, key.Length);
return new KeyParameter(aesKeyBytes);
}
public static void Main(string[] args)
{
var privKeyBytes = File.ReadAllBytes("../../privkey.der");
var seq = Asn1Sequence.GetInstance(privKeyBytes);
var rsaKeyParams = PrivateKeyFactory.CreateKey(PrivateKeyInfo.GetInstance(seq));
var wrappedKey = File.ReadAllBytes("../../wrappedKey");
var aesKey2 = Unwrap(wrappedKey, rsaKeyParams);
}
}
}
You will have to adapt this to your needs.

Related

Trying to decrypt a string with public key(not private) using bouncycastle in .net

As a sample app, I encrypted a string using an rsa public key(supplied by a 3rd party api) using BouncyCastle library in .NET. When I send this encrypted string to the said 3rd party api endpoint, it is able to decrypt it(using its private key). I don't have their private key, but, is it possible to decrypt the string on my end using just the public key that I have?
From my understanding of RSA public/private key pair, when decrypting, you use the private key stored with you to decrypt a string and use the public key to confirm that you are receiving data from a said source.
public string RsaEncryptWithPublic(string clearText
, string publicKey)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);
var encryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(publicKey))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
encryptEngine.Init(true, keyParameter);
}
var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
return encrypted;
}
public string RsaDecrypt(string base64Input
, string privateKey)
{
var bytesToDecrypt = Convert.FromBase64String(base64Input);
//get a stream from the string
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
//decryptEngine.Init(false, keyPair.Private);
decryptEngine.Init(false, keyPair.Public);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}
static void Main(string[] args)
{
string _creditCardNumber = "5454545454545454";
string publicKey = System.IO.File.ReadAllText(#"C:\ThirdPartyKeys\RSAPublicKey_01.txt");
var enc = new EncryptionClass();
var encryptedWithPublic = enc.RsaEncryptWithPublic(_creditCardNumber, publicKey);
Console.WriteLine("String: " + _creditCardNumber);
Console.WriteLine("Encrypted String: " + encryptedWithPublic);
// Decrypt
var outputWithPublic = enc.RsaDecrypt(encryptedWithPublic, publicKey);
//var outputWithPrivate = enc.RsaDecrypt(encryptedWithPrivate, _privateKey);
Console.WriteLine("Decrypted String: " + outputWithPublic);
}
The encryption works, but when I try to decrypt with the same public key, it complains of
Invalid Cast Exception:
Unable to cast object of type 'Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters' to type 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair'.
at line in RsaDecrypt function:
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
No. It's Asymmetric Encryption which means you can't decrypt it with the public key. If you could, it would defeat the purpose and anyone with the public key would be able to decrypt your secret message

Using Azure Key Vault RSA Key to encrypt and decrypt strings

I have setup Azure Key Vault to retrieve RSA Keys for encryption. Azure send me an object of type KeyBundle. This object contains a JsonWebKey of type RSA of size 2048. Looking at my RSA Key, it has 2 methods called Encrypt(byte[] data, RSAEncryptionPadding padding) and Decrypt(byte[] data, RSAEncryptionPadding padding). Now I am trying to encrypt and decrypt a simple string like this:
public EncryptionManager(KeyBundle encryptionKey)
{
string test = "Hello World!";
var key = encryptionKey.Key.ToRSA();
var encryptedString = key.Encrypt(Encoding.UTF8.GetBytes(test), RSAEncryptionPadding.OaepSHA256);
var decryptedString = key.Decrypt(encryptedString, RSAEncryptionPadding.OaepSHA256);
}
Encryption works, but decryption throws an exception with message:
Key does not exist.
Here is the StackTrace
at System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle
key, ReadOnlySpan`1 input, AsymmetricPaddingMode paddingMode, Void*
paddingInfo, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(Byte[]
data, RSAEncryptionPadding padding, Boolean encrypt) at
System.Security.Cryptography.RSAImplementation.RSACng.Decrypt(Byte[]
data, RSAEncryptionPadding padding) at
NxtUtils.Security.EncryptionManager..ctor(KeyBundle encryptionKey) in
C:\Repos\Enigma\EnigmaPrototype\SharedLibaries\NxtUtils\Security\EncryptionManager.cs:line
26
I am really not familiar with cryptographic algorithms. My question is: How can I encrypt and decrypt a simple strig using this RSA Key provided by Azure?
Thanks!
I got the same issue, what I did is here although I searched from internet and got this from the Microsoft docs
so this is my working code below
public static class KeyVaultEncryptorDecryptor
{
public static string KeyDecryptText(this string textToDecrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).Result;
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var encryptedTextNew = Convert.FromBase64String(textToDecrypt);
var decryptedData = kv.DecryptAsync(key.KeyIdentifier.Identifier.ToString(), JsonWebKeyEncryptionAlgorithm.RSAOAEP, encryptedTextNew).GetAwaiter().GetResult();
var decryptedText = Encoding.Unicode.GetString(decryptedData.Result);
return decryptedText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
public static string KeyEncryptText(this string textToEncrypt , KeyVaultClient keyVaultClient, string keyidentifier)
{
var kv = keyVaultClient;
try
{
var key = kv.GetKeyAsync(keyidentifier).GetAwaiter().GetResult();
var publicKey = Convert.ToBase64String(key.Key.N);
using var rsa = new RSACryptoServiceProvider();
var p = new RSAParameters() {
Modulus = key.Key.N, Exponent = key.Key.E
};
rsa.ImportParameters(p);
var byteData = Encoding.Unicode.GetBytes(textToEncrypt);
var encryptedText = rsa.Encrypt(byteData, true);
string encText = Convert.ToBase64String(encryptedText);
return encText;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return default;
}
}
}
ToRSA has a default boolean parameter indicating if the private key should be available, or not.
Since you didn't explicitly say true it is implicitly false, therefore your key object is public-only. With a public RSA key you can encrypt data or verify a signature, but you cannot sign or decrypt.

C# RSA Decrypt Using Private Key

I've been searching but I can't seem to find a simple way of decrypting using RSA.
I have generated a public and private key, they are stored in two separate files and are in the XML format. I have no problem associating the public key to the RSACryptoServiceProvider object using FromXmlString, and then encrypting a string. My confusion comes when trying to decrypt an encrypted string. I'm not sure how I associate the private key data with the RSACryptoServiceProvider so that I can use the Decrypt function.
Any help would be appreciated.
EDIT:
The format of the public and private key is XML generated by the RSACryptoServiceProvider object, which I just put into a file:
<RSAKeyValue><Modulus>vS7Y5up+6kHMx7hQjKA6sKlIVASaw ... etc ...
I load the public key using this code:
StreamReader sr = new StreamReader(HttpContext.Current.Server.MapPath("public.key"));
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(sr.ReadToEnd().ToString());
I currently haven't tried anything with the private key yet, since I'm not sure where to start.
I don't know your situation but I would suggest that you store you key information in a KeyContainer. If you do this you can access the keyContainer by name and can do something like this.
// retrieves the maximum number of characters that can be decrypted at once
private int getMaxBlockSize(int keySize){
int max = ((int)(keysize/8/3) )* 4
if (keySize / 8 mod 3 != 0){
max += 4
}
return max;
}
public string decrypt(string msg, string containerName){
CspParameters params = new CspParameters();
params.KeyContainerName = containerName;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(params);
StringBuilder decryptedMsg = new StringBuilder();
int maxDecryptSize = getMaxBlockSize(rsa.KeySize);
int iterationCount = Math.Floor(msg.length / maxDecryptSize)
for(int i=0; i<iterationCount; i++){
int start = i * maxDecryptSize;
int blkSize = Math.min(start + maxDecryptSize, msg.Length);
Byte[] msgBytes = System.Convert.FromBase64String(msg.Substring(start, blkSize));
decryptedMsg.Append(System.Text.Encoding.Unicode.GetString(RSAProvider.Decrypt(msgBytes, false));
}
return decryptedMsg.ToString();
}
I haven't tested this out so there might be a bug in here but the you get the idea.
if you have private key in text format
like given below
-----BEGIN RSA PRIVATE KEY-----
text....
-----END RSA PRIVATE KEY-----
public string RsaDecryptWithPrivate(string base64Input, string privateKey)
{
var bytesToDecrypt = Convert.FromBase64String(base64Input);
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();//fetch key pair from text file
decryptEngine.Init(false, keyPair.Private);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}

Encode a RSA public key to DER format

I need a RSA public key encoded into DER format.
The key-pair is generated using RSACryptoServiceProvider.
What I'm looking for is the c# equivalent to the java:
PublicKey pubKey = myPair.getPublic();
byte[] keyBytes = pubKey.getEncoded();
I have tried looking into BouncyCastle but got lost so if the solution is there any pointers are welcome.
Using Bouncy Castle:
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
...
var generator = new RsaKeyPairGenerator ();
generator.Init (new KeyGenerationParameters (new SecureRandom (), 1024));
var keyPair = generator.GenerateKeyPair ();
RsaKeyParameters keyParam = (RsaKeyParameters)keyPair.Public;
var info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo (keyParam);
RsaBytes = info.GetEncoded ();
The last three lines are the ones who take the RSA public key and export it.
I tried to use aforementioned info.GetEncoded() but as a result, I couldn't use it to verify the signature created with the corresponding private key.
What works for me is converting it to a X509Certificate2.
private bool VerifySignature(string stringContent, string stringSignature, X509Certificate2 x509PublicKey)
{
Int16 cbSignature = 0, cbCert = 0;
int cbData = 0;
CertBasicStruct sCert = new CertBasicStruct();
var pbCert = PublicKey.RawData;
cbCert = (Int16)pbCert.Length;
byte[] pbData = Encoding.UTF8.GetBytes(stringContent);
cbData = (Int16)pbData.Length;
byte[] pbSignature = Convert.FromBase64String(Signature);
cbSignature = (Int16)pbSignature.Length;
var rtn = DllImportService.DecodeCertificate(pbCert, cbCert, ref sCert);
var rtn_1 = DllImportService.VerifySignatureByCert(ref sCert, DllImportService.CKM_SHA256_RSA_PKCS, pbData, cbData, pbSignature, cbSignature);
if (rtn_1 == 0)
{
LogWndAppendLine("Signature is valid.");
return true;
}
else
{
LogWndAppendLine("Signature is invalid");
return false;
}
}
X509Certificate2.RawData would be what you are looking for.

RSA signing and verification with C#,BouncyCastle and imported RSA key - Working Python example and non-working C# code sample inside

I have been tearing what is left of my hair out trying to get a trivial example of RSA data signing and verification with C# and BouncyCastle working.
RSACryptoServiceProvider.VerifyHash() always returns false on an example that works for me with Python and M2Crypto.
I have verified that the hash signatures are identical between the working example and the C# example and it is there I am stuck. I feel I am missing some vital detail.
The working Python code and non working C# code follow.
The key was generated with
openssl genrsa -out testkey.pem 1024
openssl rsa -in testkey.pem -pubout > testkey.pub
Python code (working):
private = """-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCxSHbp1ID/XHEdzVzgqYR1F/79PeMbqzuKNZChvt1gFObBhKyB
pgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyVoznXMoJYBv0uLDApvSQbJNOd
f7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bczPQPGOASrQ2Ly9afOZQIDAQAB
AoGBAIEzQIZ1OnXgVwfTLMcGg+QaUtkYizUU+9Vj6D4YrZliYjHSkS4DY2p0rOpb
7Ki5yMpCoZJ/OpWo03+tilj6zNUU6X3aHrPPSv8jcsE0sDi9zYJr/Ztk3EG23sad
bM28Bb4fV/Z0/E6FZJrmuvI2dZP/57oQSHGOhtkHFO21cW5BAkEA3l/i5Rc34YXc
WHYEsOYe0kAxS4dCmhbLWaWvsghW/TomjdxzePsO70GZZqRMdzkfA1iS1OrK+pP4
4suL2rSLrQJBAMwXFnBp4Jmek0CTSxoYf6q91eFm/IRkGLnzE1fEZ76vQOBTas8T
/mpjNQHSEywo/QB62h9A8hy7XNrfZJAMJJkCQA5TYwybKFBxDTbts3Op/4ZP+F0D
Q7klisglsmHnw6Lgoic1coLyuY2UTkucfgiYN3VBuYPZ9GWcLsZ9km7ufqkCQQCz
NVa70Qyqd+cfXfcla/u2pskHCtKTQf3AUmRavhjHBMa39CemvAy7yG9EMP4q2bcH
U9jydqnidtdbTavVHQSJAkA0zJtLzHGPtQqQaI7K6kBDXYPqloGnQxHxad0HPx2e
Vj2qv1tEsqeG6HC7aL/afXOtxcfjq4oMHbGUjDv+dGfP
-----END RSA PRIVATE KEY-----"""
public = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxSHbp1ID/XHEdzVzgqYR1F/79
PeMbqzuKNZChvt1gFObBhKyBpgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyV
oznXMoJYBv0uLDApvSQbJNOdf7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bcz
PQPGOASrQ2Ly9afOZQIDAQAB
-----END PUBLIC KEY-----"""
message = "test input string"
import base64
# Use EVP api to sign message
from M2Crypto import EVP
key = EVP.load_key_string(private)
key.reset_context(md='sha1')
key.sign_init()
key.sign_update(message)
signature = key.sign_final()
encoded = base64.b64encode(signature)
print encoded
with open("python_sig2.txt","w") as f:
f.write(encoded)
# Use EVP api to verify signature
from M2Crypto import BIO, RSA, EVP
bio = BIO.MemoryBuffer(public)
rsa = RSA.load_pub_key_bio(bio)
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
pubkey.reset_context(md="sha1")
pubkey.verify_init()
pubkey.verify_update(message)
decoded = base64.b64decode(encoded)
print pubkey.verify_final(decoded) == 1
C# code (verifyhash() returns false):
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
namespace RsaSignTest
{
class Program
{
private const string privateKey =
#"-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCxSHbp1ID/XHEdzVzgqYR1F/79PeMbqzuKNZChvt1gFObBhKyB
pgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyVoznXMoJYBv0uLDApvSQbJNOd
f7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bczPQPGOASrQ2Ly9afOZQIDAQAB
AoGBAIEzQIZ1OnXgVwfTLMcGg+QaUtkYizUU+9Vj6D4YrZliYjHSkS4DY2p0rOpb
7Ki5yMpCoZJ/OpWo03+tilj6zNUU6X3aHrPPSv8jcsE0sDi9zYJr/Ztk3EG23sad
bM28Bb4fV/Z0/E6FZJrmuvI2dZP/57oQSHGOhtkHFO21cW5BAkEA3l/i5Rc34YXc
WHYEsOYe0kAxS4dCmhbLWaWvsghW/TomjdxzePsO70GZZqRMdzkfA1iS1OrK+pP4
4suL2rSLrQJBAMwXFnBp4Jmek0CTSxoYf6q91eFm/IRkGLnzE1fEZ76vQOBTas8T
/mpjNQHSEywo/QB62h9A8hy7XNrfZJAMJJkCQA5TYwybKFBxDTbts3Op/4ZP+F0D
Q7klisglsmHnw6Lgoic1coLyuY2UTkucfgiYN3VBuYPZ9GWcLsZ9km7ufqkCQQCz
NVa70Qyqd+cfXfcla/u2pskHCtKTQf3AUmRavhjHBMa39CemvAy7yG9EMP4q2bcH
U9jydqnidtdbTavVHQSJAkA0zJtLzHGPtQqQaI7K6kBDXYPqloGnQxHxad0HPx2e
Vj2qv1tEsqeG6HC7aL/afXOtxcfjq4oMHbGUjDv+dGfP
-----END RSA PRIVATE KEY-----";
private const string publicKey =
#"-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxSHbp1ID/XHEdzVzgqYR1F/79
PeMbqzuKNZChvt1gFObBhKyBpgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyV
oznXMoJYBv0uLDApvSQbJNOdf7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bcz
PQPGOASrQ2Ly9afOZQIDAQAB
-----END PUBLIC KEY-----";
static void Main(string[] args)
{
var data = "test input string";
var sig = SignWithPrivateKey(data);
var valid = VerifyWithPublicKey(data,sig);
}
private static byte[] SignWithPrivateKey(string data)
{
RSACryptoServiceProvider rsa;
using (var keyreader = new StringReader(privateKey))
{
var pemreader = new PemReader(keyreader);
var y = (AsymmetricCipherKeyPair) pemreader.ReadObject();
var rsaPrivKey = (RsaPrivateCrtKeyParameters)y.Private;
rsa = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
var rsaParameters = DotNetUtilities.ToRSAParameters(rsaPrivKey);
rsa.ImportParameters(rsaParameters);
}
// compute sha1 hash of the data
var sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));
// actually compute the signature of the SHA1 hash of the data
var sig = rsa.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
// base64 encode the signature and write to compare to the python version
String b64signature = Convert.ToBase64String(sig);
using (var sigwriter = new StreamWriter(#"C:\scratch\csharp_sig2.txt"))
{
sigwriter.Write(b64signature);
}
return sig;
}
private static bool VerifyWithPublicKey(string data,byte[] sig)
{
RSACryptoServiceProvider rsa;
using (var keyreader = new StringReader(publicKey))
{
var pemReader = new PemReader(keyreader);
var y = (RsaKeyParameters) pemReader.ReadObject();
rsa = (RSACryptoServiceProvider) RSACryptoServiceProvider.Create();
var rsaParameters = new RSAParameters();
rsaParameters.Modulus = y.Modulus.ToByteArray();
rsaParameters.Exponent = y.Exponent.ToByteArray();
rsa.ImportParameters(rsaParameters);
}
// compute sha1 hash of the data
var sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));
// This always returns false
return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"),sig);
}
}
}
At this point I don't know how to proceed and any help would be greatly appreciated.
Something is wrong with how you're re-constructing the private/public key. Obviously in python you're note required to do that.
I created new keys that verify (in a different format) using this code:
private static void GenerateKeys(out string forPubKey, out string forPrivKey)
{
GenerateKeys(out forPubKey, out forPrivKey, 2048, 65537, 80);
}
/// <summary>
///
/// </summary>
/// <param name="forPubKey"></param>
/// <param name="forPrivKey"></param>
/// <param name="keyStrength">1024, 2048,4096</param>
/// <param name="exponent">Typically a fermat number 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,</param>
/// <param name="certaninty">Should be 80 or higher depending on Key strength number (exponent)</param>
private static void GenerateKeys(out string forPubKey, out string forPrivKey, int keyStrength, int exponent, int certaninty)
{
// Create key
RsaKeyPairGenerator generator = new RsaKeyPairGenerator();
/*
* This value should be a Fermat number. 0x10001 (F4) is current recommended value. 3 (F1) is known to be safe also.
* 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,
*
* Practically speaking, Windows does not tolerate public exponents which do not fit in a 32-bit unsigned integer. Using e=3 or e=65537 works "everywhere".
*/
BigInteger exponentBigInt = new BigInteger(exponent.ToString());
var param = new RsaKeyGenerationParameters(
exponentBigInt, // new BigInteger("10001", 16) publicExponent
new SecureRandom(), // SecureRandom.getInstance("SHA1PRNG"),//prng
keyStrength, //strength
certaninty);//certainty
generator.Init(param);
AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();
// Save to export format
SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
byte[] ret = info.GetEncoded();
forPubKey = Convert.ToBase64String(ret);
// EncryptedPrivateKeyInfo asdf = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
// DerObjectIdentifier.Ber,,,keyPair.Private);
//// demonstration: how to serialise option 1
//TextWriter textWriter = new StringWriter();
//PemWriter pemWriter = new PemWriter(textWriter);
//pemWriter.WriteObject(keyPair);
//pemWriter.Writer.Flush();
//string ret2 = textWriter.ToString();
//// demonstration: how to serialise option 1
//TextReader tr = new StringReader(ret2);
//PemReader read = new PemReader(tr);
//AsymmetricCipherKeyPair something = (AsymmetricCipherKeyPair)read.ReadObject();
//// demonstration: how to serialise option 2 (don't know how to deserailize)
//PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
//byte[] privRet = pKinfo.GetEncoded();
//string forPrivKey2Test = Convert.ToBase64String(privRet);
PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
byte[] privRet = pKinfo.GetEncoded();
string forPrivKey2Test = Convert.ToBase64String(privRet);
forPrivKey = forPrivKey2Test;
}
and then turned them back into RSA objects like this:
// Private key
RsaPrivateCrtKeyParameters kparam = ConvertToRSAPrivateKey(privateKey);
RSAParameters p1 = DotNetUtilities.ToRSAParameters(kparam);
rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(p1);
// Public key
RsaKeyParameters kparam = ConvertToRSAPublicKey(publicKey);
RSAParameters p1 = DotNetUtilities.ToRSAParameters(kparam);
rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(p1);

Categories

Resources