Tutorials

Tutorials

Encryption, Hashing, and Signing with GPAL Cryptography

GPAL's Cryptography class wraps common .NET crypto operations - AES encryption in multiple modes, hashing, RSA signing and verification, and PBKDF2 key derivation - behind one fluent, chainable object. This tutorial walks through generating keys, encrypting and decrypting data, chaining encryption into hashing, and signing/verifying with RSA.

Complete Program

This is a trimmed version of the actual test program. It generates an RSA key pair and an AES key/IV, encrypts and decrypts a message, chains encryption straight into hashing, and signs/verifies the original data with RSA.

using System;

using System.Text;

using GenerallyPositive;

using static GenerallyPositive.Enums;

byte[] data = Encoding.UTF8.GetBytes("Hello, GPAL Cryptography!");

var (rsaPrivateKey, rsaPublicKey) = Cryptography.GenerateRsaKeyPair();

var crypto = new Cryptography();

GPAL.WithPublishToConsole();

// Generate a key and IV, then encrypt with AES/GCM

crypto.WithAlgorithm(CryptoAlgorithm.AES)

.WithMode(CryptoMode.GCM)

.GenerateIV(out byte[] iv)

.GenerateKey(out byte[] key)

.WithInputData(data)

.Encrypt(out byte[] encrypted);

// Decrypt using the same key and IV, switching to CBC/PKCS7

crypto.WithAlgorithm(CryptoAlgorithm.AES)

.WithMode(CryptoMode.CBC)

.WithPadding(CryptoPadding.PKCS7)

.WithKey(key)

.WithIV(iv)

.WithInputData(encrypted)

.Decrypt(out string decrypted);

Console.WriteLine($"Decrypted value: [{decrypted}]");

// Encrypt, then immediately hash the same input data

crypto.WithAlgorithm(CryptoAlgorithm.AES)

.WithKey(key)

.WithIV(iv)

.WithInputData(data)

.Encrypt(out encrypted)

.WithAlgorithm(CryptoAlgorithm.SHA256)

.Hash(out byte[] hash);

// Sign with the RSA private key, verify with the public key

crypto.WithAlgorithm(CryptoAlgorithm.SHA256withRSA)

.WithKey(rsaPrivateKey)

.WithInputData(data)

.Sign(out byte[] signature)

.WithKey(rsaPublicKey)

.WithSignature(signature)

.Verify(out bool isValid);

Console.WriteLine($"Verification result: [{isValid}]");

Generate Keys Up Front

Cryptography.GenerateRsaKeyPair() is a static helper that returns a private and public key in one call. For symmetric work, GenerateIV and GenerateKey are instance methods on a Cryptography object - calling them stores the generated values internally (_iv and _key) so later calls like Encrypt can reuse them without you passing anything explicitly.

var (rsaPrivateKey, rsaPublicKey) = Cryptography.GenerateRsaKeyPair();

var crypto = new Cryptography();

crypto.WithAlgorithm(CryptoAlgorithm.AES)

.WithMode(CryptoMode.GCM)

.GenerateIV(out byte[] iv)

.GenerateKey(out byte[] key)

.WithInputData(data)

.Encrypt(out byte[] encrypted);

TIP

GenerateIV and GenerateKey both hand the value back to you via out parameters AND store it internally for the next call in the chain. That's why Encrypt doesn't need a separate WithKey/WithIV call here - it reuses what was just generated.

Switch Algorithm and Mode for Decryption

WithAlgorithm and WithMode (and WithPadding for block modes that need it) configure how the next operation runs. Here decryption explicitly sets WithKey and WithIV to the values generated during encryption, switches to CBC with PKCS7 padding, and calls Decrypt with an out string to get the plaintext back directly.

crypto.WithAlgorithm(CryptoAlgorithm.AES)

.WithMode(CryptoMode.CBC)

.WithPadding(CryptoPadding.PKCS7)

.WithKey(key)

.WithIV(iv)

.WithInputData(encrypted)

.Decrypt(out string decrypted);

Chain Encrypt Straight Into Hash

Because Encrypt returns the same crypto object, you can immediately switch algorithm to SHA256 and call Hash - it reuses _inputData (the original plaintext, not the just-produced ciphertext) for the hash. This is a convenient way to produce both an encrypted payload and an integrity hash of the source data in one chain.

crypto.WithAlgorithm(CryptoAlgorithm.AES)

.WithKey(key)

.WithIV(iv)

.WithInputData(data)

.Encrypt(out encrypted)

.WithAlgorithm(CryptoAlgorithm.SHA256)

.Hash(out byte[] hash);

WARNING

Switching WithAlgorithm to SHA256 after Encrypt does not hash the ciphertext - it hashes whatever _inputData currently holds, which here is still the original plaintext set by the earlier WithInputData(data) call.

Sign with a Private Key, Verify with the Public Key

SHA256withRSA covers both signing and verification. Sign takes the RSA private key and the data, producing a signature. Verify then takes the public key plus that signature and reports whether it matches - the standard pattern for proving data hasn't been tampered with.

crypto.WithAlgorithm(CryptoAlgorithm.SHA256withRSA)

.WithKey(rsaPrivateKey)

.WithInputData(data)

.Sign(out byte[] signature)

.WithKey(rsaPublicKey)

.WithSignature(signature)

.Verify(out bool isValid);