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