From b6877f107bd712e39a2d2c754b09dbcaa008cf20 Mon Sep 17 00:00:00 2001 From: CoolandonRS <49355953+CoolandonRS@users.noreply.github.com> Date: Thu, 27 Jul 2023 20:40:53 -0600 Subject: [PATCH] AES support and refactoring --- keyring/AESUtil.cs | 61 +++++++++++++++++++++++++++++++++++++++ keyring/EncryptionUtil.cs | 35 ++++++++++++++++++++++ keyring/RSAUtil.cs | 47 +++++------------------------- 3 files changed, 104 insertions(+), 39 deletions(-) create mode 100644 keyring/AESUtil.cs create mode 100644 keyring/EncryptionUtil.cs diff --git a/keyring/AESUtil.cs b/keyring/AESUtil.cs new file mode 100644 index 0000000..46fd3e7 --- /dev/null +++ b/keyring/AESUtil.cs @@ -0,0 +1,61 @@ +using System.Diagnostics.CodeAnalysis; +using System.Security.Cryptography; +using System.Text; + +namespace CoolandonRS.keyring; + +public class AESUtil : EncryptionUtil { + private Aes aes; + private byte[] ivKey; + private int interactionCount; + private object @lock; + + public override byte[] Encrypt(byte[] b) { + lock (@lock) { + DeriveIV(); + return aes.EncryptCbc(b, aes.IV); + } + } + + public override byte[] Decrypt(byte[] b) { + lock (@lock) { + DeriveIV(); + return aes.DecryptCbc(b, aes.IV); + } + } + + public (byte[] key, byte[] ivKey) GetSecrets() { + lock (@lock) { + if (interactionCount != -1) throw new InvalidOperationException("This AESUtil has already been used. Secrets are not retrievable."); + return (aes.Key, ivKey); + } + } + + private static Aes MakeAes(byte[] key) { + var aes = Aes.Create(); + aes.KeySize = key.Length; + aes.Key = key; + return aes; + } + + private void DeriveIV() { + interactionCount++; + aes.IV = Rfc2898DeriveBytes.Pbkdf2(ivKey, BitConverter.GetBytes(interactionCount), 15000, HashAlgorithmName.SHA256, 16); + } + + private AESUtil(KeyType keyType, byte[] ivKey, Aes aes, Encoding? encoding = null) : base(keyType, encoding) { + if (keyType != KeyType.Symmetric) throw new InvalidOperationException("AESUtil only supports symmetric keys"); + this.aes = aes; + this.ivKey = ivKey; + this.interactionCount = -1; + } + + /// + /// Generates a new AES key to use for the AESUtil + /// + public AESUtil(Encoding? encoding = null) : this(KeyType.Symmetric, RandomNumberGenerator.GetBytes(64), Aes.Create(), encoding) { + } + + public AESUtil(KeyType keyType, byte[] key, byte[] ivKey, Encoding? encoding = null) : this(keyType, ivKey, MakeAes(key), encoding) { + } +} \ No newline at end of file diff --git a/keyring/EncryptionUtil.cs b/keyring/EncryptionUtil.cs new file mode 100644 index 0000000..3cd9404 --- /dev/null +++ b/keyring/EncryptionUtil.cs @@ -0,0 +1,35 @@ +using System.Security.Cryptography; +using System.Text; + +namespace CoolandonRS.keyring; + +public abstract class EncryptionUtil { + protected readonly KeyType keyType; + protected readonly Encoding encoding; + + /// + /// Encrypts data using the stored key(s) + /// + /// Data to encrypt + /// Encrypted data + public abstract byte[] Encrypt(byte[] b); + + public virtual byte[] EncryptStr(string s) => Encrypt(encoding.GetBytes(s)); + + /// + /// Decrypts data using the stored key(s) + /// + /// Data to decrypt + /// Decrypted Data + /// Unable to decrypt + public abstract byte[] Decrypt(byte[] b); + + public virtual string DecryptStr(byte[] b) => encoding.GetString(Decrypt(b)); + + public KeyType GetKeyType() => keyType; + + protected EncryptionUtil(KeyType type, Encoding? encoding) { + this.keyType = type; + this.encoding = encoding ?? Encoding.UTF8; + } +} \ No newline at end of file diff --git a/keyring/RSAUtil.cs b/keyring/RSAUtil.cs index 72c4f29..f371448 100644 --- a/keyring/RSAUtil.cs +++ b/keyring/RSAUtil.cs @@ -1,4 +1,5 @@ -using System.Security.Cryptography; +using System.CodeDom.Compiler; +using System.Security.Cryptography; using System.Text; namespace CoolandonRS.keyring; @@ -6,49 +7,19 @@ namespace CoolandonRS.keyring; /// /// Tool for using RSA Encryption/Decryption /// -public class RSAUtil { +public class RSAUtil : EncryptionUtil { private RSACryptoServiceProvider provider; - private readonly KeyType keyType; private Encoding encoding; - - /// - /// Encrypts data using the stored key(s) - /// - /// Data to encrypt - /// Encrypted data - public byte[] Encrypt(byte[] dat) { + + public override byte[] Encrypt(byte[] dat) { return provider.Encrypt(dat, false); } - - /// - /// Encodes and encrypts a string using the chosen encoding and stored key(s) - /// - /// String to encode and encrypt - /// Encrypted data - public byte[] EncryptStr(string str) { - return Encrypt(encoding.GetBytes(str)); - } - - /// - /// Decrypts data using the stored key(s) - /// - /// Data to decrypt - /// Decrypted Data - /// - public byte[] Decrypt(byte[] dat) { + + public override byte[] Decrypt(byte[] dat) { if (keyType != KeyType.Private) throw new InvalidOperationException("Cannot decrypt if keyType is not private"); return provider.Decrypt(dat, false); } - /// - /// Decrypts data and encodes it into a string using the chosen encoding and stored key(s) - /// - /// Encrypted data - /// Decrypted string - public string DecryptStr(byte[] dat) { - return encoding.GetString(Decrypt(dat)); - } - /// /// Creates an instance of RSAUtil /// @@ -56,14 +27,12 @@ public class RSAUtil { /// The contents of the PEM file /// The text encoding to use for strings /// If you provide a symmetric key - public RSAUtil(KeyType keyType, string pemContents, Encoding? encoding = null) { + public RSAUtil(KeyType keyType, string pemContents, Encoding? encoding = null) : base(keyType, encoding) { if (keyType == KeyType.Symmetric) throw new InvalidOperationException("RSAUtil does not support symmetric keys"); // ReSharper disable once LocalVariableHidesMember // Intentional var provider = new RSACryptoServiceProvider(); provider.ImportFromPem(pemContents); if (keyType == KeyType.Private && provider.PublicOnly) throw new ArgumentException("keyType reported as private; no private key found."); - this.keyType = keyType; this.provider = provider; - this.encoding = encoding ?? Encoding.UTF8; } } \ No newline at end of file