Skip to content

Instantly share code, notes, and snippets.

@yetanotherchris
Last active January 12, 2023 09:25

Revisions

  1. yetanotherchris revised this gist Nov 13, 2020. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions PublicKeyCryptographyExample.cs
    Original file line number Diff line number Diff line change
    @@ -89,6 +89,7 @@ private static bool VerifySignature(string plainText, string 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);
  2. yetanotherchris created this gist Nov 9, 2020.
    115 changes: 115 additions & 0 deletions PublicKeyCryptographyExample.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,115 @@
    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);
    }

    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;
    }
    }
    }