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