Skip to content

Instantly share code, notes, and snippets.

@yetanotherchris
Last active January 12, 2023 09:25
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save yetanotherchris/d8330dd6f541f85903a9bdd5dd13bb1f to your computer and use it in GitHub Desktop.
Save yetanotherchris/d8330dd6f541f85903a9bdd5dd13bb1f to your computer and use it in GitHub Desktop.
Public key cryptography by example in .NET Core
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace PublicKeyCryptographyExample
{
//
// https://yetanotherchris.dev/security/public-private-key-in-netcore-by-example/
//
// nuget dependencies:
// - System.Security.Cryptography.Algorithms
// To generate a test key, install openssl and use:
// - openssl req -x509 -sha256 -days 365 -newkey rsa:4096 -keyout public.pem -out private.pem
//
class Program
{
private static readonly string PublicPemFilename = "public.pem";
private static readonly string PrivatePemFilename = "private.pem";
static void Main(string[] args)
{
string plainText = "hello world";
Console.WriteLine($"Encrypting ${plainText}");
string encrypted = Encrypt(plainText);
Console.WriteLine("[Encrypted]");
Console.WriteLine(encrypted);
Console.WriteLine("-------------------");
string decrypted = Decrypt(encrypted);
Console.WriteLine("[Decrypted]");
Console.WriteLine(decrypted);
Console.WriteLine("-------------------");
string signature = SignWithPrivateKey(plainText);
Console.WriteLine("[Signature]");
Console.WriteLine(signature);
Console.WriteLine("-------------------");
Console.WriteLine("[Verify the hash and signature with a public key]");
Console.WriteLine("Verified: "+VerifySignature(plainText, signature));
Console.WriteLine("-------------------");
}
private static string Encrypt(string text)
{
byte[] publicPemBytes = File.ReadAllBytes(PublicPemFilename);
using var publicX509 = new X509Certificate2(publicPemBytes);
var rsa = publicX509.GetRSAPublicKey();
byte[] encrypted = rsa.Encrypt(System.Text.Encoding.Default.GetBytes(text), RSAEncryptionPadding.Pkcs1);
return Convert.ToBase64String(encrypted);
}
private static string Decrypt(string base64Text)
{
using X509Certificate2 certificate = CombinePublicAndPrivateCerts();
var rsa = certificate.GetRSAPrivateKey();
byte[] textBytes = Convert.FromBase64String(base64Text);
byte[] decrypted = rsa.Decrypt(textBytes, RSAEncryptionPadding.Pkcs1);
return System.Text.Encoding.Default.GetString(decrypted);
}
private static string SignWithPrivateKey(string text)
{
var privateKeyText = File.ReadAllText(PrivatePemFilename);
var privateKeyBlocks = privateKeyText.Split("-", StringSplitOptions.RemoveEmptyEntries);
var privateKeyBytes = Convert.FromBase64String(privateKeyBlocks[1]);
using RSA rsa = RSA.Create();
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
byte[] textBytes = System.Text.Encoding.Default.GetBytes(text);
byte[] signature = rsa.SignData(textBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signature);
}
private static bool VerifySignature(string plainText, string base64Signature)
{
byte[] publicPemBytes = File.ReadAllBytes(PublicPemFilename);
using var publicX509 = new X509Certificate2(publicPemBytes);
var rsa = publicX509.GetRSAPublicKey();
byte[] dataBytes = System.Text.Encoding.Default.GetBytes(plainText);
byte[] signatureBytes = Convert.FromBase64String(base64Signature);
return rsa.VerifyData(dataBytes, signatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
// With help from https://github.com/dotnet/runtime/issues/19581#issuecomment-581147166
private static X509Certificate2 CombinePublicAndPrivateCerts()
{
byte[] publicPemBytes = File.ReadAllBytes(PublicPemFilename);
using var publicX509 = new X509Certificate2(publicPemBytes);
var privateKeyText = File.ReadAllText(PrivatePemFilename);
var privateKeyBlocks = privateKeyText.Split("-", StringSplitOptions.RemoveEmptyEntries);
var privateKeyBytes = Convert.FromBase64String(privateKeyBlocks[1]);
using RSA rsa = RSA.Create();
if (privateKeyBlocks[0] == "BEGIN PRIVATE KEY")
{
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
}
else if (privateKeyBlocks[0] == "BEGIN RSA PRIVATE KEY")
{
rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
}
var keyPair = publicX509.CopyWithPrivateKey(rsa);
return publicX509;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment