1

Im trying to make a SHA1withRSA sign/verify function on ASP.NET core using BouncyCastle library, 1st of all I need to make a keypair, I am using this page to generate the key: https://travistidwell.com/jsencrypt/demo/

However from BouncyCastle example code I found (C# Sign Data with RSA using BouncyCastle), from the Public and Private key text generated, I couldn't make the key files, which as I understand, would be a .CER file for public key and .PEM for private key.

So could you please suggest me a way to make the .CER and .PEM file? Also, I haven't found a complete example about signing SHA1withRSA using BouncyCastle library - or just core C#, I'd be so grateful if you could suggest me a complete example, thank you so much.

Liberty
  • 345
  • 1
  • 4
  • 10
  • The linked site generates keys in PKCS#1 (private) and X.509 (public) format. Both should be importable into .NET Core (in contrast to .NET Framework) as DER, unless you are using a too old version. Therefore, which .NET Core version are you using? And do you want to apply BouncyCastle even if it works with .NET Core alone? – Topaco Jun 29 '21 at 14:02
  • 1
    Thanks for your reply, I am using .NET Core 2.2, could u please give me some advice to make the key files? Yes, I only need it to work wit .NET Core. – Liberty Jun 29 '21 at 14:20

1 Answers1

2

The linked website generates private keys in PKCS#1 format and public keys in X.509/SPKI format, each PEM encoded.

.NET Core only supports the import of PKCS#1 and X.509 keys as of version 3.0. For .NET Core 2.2, the easiest way is to apply BouncyCastle. For loading the PEM keys the PemReader of BouncyCastle can be used.

Option 1:

With BouncyCastle's DotNetUtilities class, RSAParameters instances can be derived and thus RSACryptoServiceProvider instances:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
...
public static RSACryptoServiceProvider GetRSACryptoServiceProviderFromPem(string pem, bool isPrivate)
{
    PemReader pemReader = new PemReader(new StringReader(pem));
    object key = pemReader.ReadObject();

    RSAParameters rsaParameters = isPrivate ? 
        DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)(((AsymmetricCipherKeyPair)key).Private)) : 
        DotNetUtilities.ToRSAParameters((RsaKeyParameters)key);

    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
    rsaKey.ImportParameters(rsaParameters);

    return rsaKey;
}

RSACryptoServiceProvider in turn has methods for signing/verifying:

RSACryptoServiceProvider privateCSP = GetRSACryptoServiceProviderFromPem(privateKey, true);
RSACryptoServiceProvider publicCSP = GetRSACryptoServiceProviderFromPem(publicKey, false);

byte[] dataToSign = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog");
byte[] signature = privateCSP.SignData(dataToSign, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
bool verified = publicCSP.VerifyData(dataToSign, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);

Option 2:

Alternatively, the RsaPrivateCrtKeyParameters and the RsaKeyParameters classes of BouncyCastle can be used directly:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
...
public static AsymmetricKeyParameter GetAsymmetricKeyParameterFromPem(string pem, bool isPrivate)
{
    PemReader pemReader = new PemReader(new StringReader(pem));
    object key = pemReader.ReadObject();

    return isPrivate ? ((AsymmetricCipherKeyPair)key).Private : (AsymmetricKeyParameter)key;
}

as well as classes for signing and verifying provided by BouncyCastle's SignerUtilities:

RsaPrivateCrtKeyParameters privateKeyParameters = (RsaPrivateCrtKeyParameters)GetAsymmetricKeyParameterFromPem(privateKey, true);
RsaKeyParameters publicKeyParameters = (RsaKeyParameters)GetAsymmetricKeyParameterFromPem(publicKey, false);

ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(true, privateKeyParameters);
byte[] dataToSign = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog");
signer.BlockUpdate(dataToSign, 0, dataToSign.Length);
byte[] signature = signer.GenerateSignature();

signer.Init(false, publicKeyParameters);
signer.BlockUpdate(dataToSign, 0, dataToSign.Length);
bool verified = signer.VerifySignature(signature);
Console.WriteLine(verified);

Both implementations are executable under .NET Core 2.2.

Topaco
  • 40,594
  • 4
  • 35
  • 62