patterncsharpModerate
C# AES + RSA Encryption Implementation
Viewed 0 times
encryptionimplementationrsaaes
Problem
I've put together an AES encryption implementation to solve a set of requirements. I believe that I've met the requirements, but I'd like to see if anyone is willing to review the implementation to ensure that my crypto approach is sound.
Requirements
Encryption libraries used:
Usage prerequisites
Encryption Flow
Notes
I've omitted certain business requirements that are driving the requirements here for brevity. I do recognize that the additional server certificate security layer seems unnecessary without those details. The basic idea is that even if you know the base passphrase, you still need to have the certificate installed in order to encrypt/decrypt.
Code (semi-redacted)
AES
```
public static class AES
{
private static readonly byte[] _Salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };
private const int KEY_SIZE = 256;
private const int BLOCK_SIZE = 128;
private const PaddingMode PADDING_MODE = PaddingMode.PKCS7;
private static readonly byte[] _AESKey = GetEncryptionKey(KEY_SIZE);
public static string Encrypt(string dataToEncrypt)
{
if (dataToEncrypt == null || dataToEncrypt.Length
Requirements
- Static symmetric encryption API composed of Encrypt(string) and Decrypt(string) methods.
- Multi-server use. Cannot use server scoped encryption. Previous Triple DES implementation did this.
- Passphrase used to derive encryption key is stored as plaintext on disc (see "Notes" section below).
Encryption libraries used:
- AES - System.Security.Cryptography.RijndaelManaged
- RSA - System.Security.Cryptography.RSACryptoServiceProvider
Usage prerequisites
- Server using encryption library must have certificate installed in certificate store.
- Server using encryption library must have plain text passphrase present on disc.
Encryption Flow
- Application requests encryption from AES library.
- AES retrieves passphrase from disc.
- 256 bit AES encryption key is derived from passphrase using certificate.
- AES encryption is performed using key that is derived from RSA encryption.
Notes
I've omitted certain business requirements that are driving the requirements here for brevity. I do recognize that the additional server certificate security layer seems unnecessary without those details. The basic idea is that even if you know the base passphrase, you still need to have the certificate installed in order to encrypt/decrypt.
Code (semi-redacted)
AES
```
public static class AES
{
private static readonly byte[] _Salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };
private const int KEY_SIZE = 256;
private const int BLOCK_SIZE = 128;
private const PaddingMode PADDING_MODE = PaddingMode.PKCS7;
private static readonly byte[] _AESKey = GetEncryptionKey(KEY_SIZE);
public static string Encrypt(string dataToEncrypt)
{
if (dataToEncrypt == null || dataToEncrypt.Length
Solution
As far as I can tell, this
Can be replaced with this
Similarly, this
Can be written
All code like this can be replaced with
Can be written
Similar rewrites are possible in
There's an unused variable
byte[] encryptedData;
// ...
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
using (var binaryWriter = new BinaryWriter(cryptoStream))
{
binaryWriter.Write(rij.IV);
binaryWriter.Write(dataToEncrypt);
cryptoStream.Flush();
cryptoStream.FlushFinalBlock();
memoryStream.Position = 0;
encryptedData = memoryStream.ToArray();
}
memoryStream.Close();
cryptoStream.Close();
}
}
return encryptedData;Can be replaced with this
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(rij.IV, 0, rij.IV.Length);
cryptoStream.Write(dataToEncrypt, 0, dataToEncrypt.Length);
}
return memoryStream.ToArray();
}CryptoStream.Flushis a no-op
- Disposing of the
CryptoStreamwill callFlushFinalBlock.
ToArraycan still be called on theMemoryStreamafter it has been closed by disposing of theCryptoStream.
ToArray"writes the stream contents to a byte array, regardless of thePositionproperty."
Similarly, this
byte[] decrypted;
// ...
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
using (var binaryWriter = new BinaryWriter(cryptoStream))
{
binaryWriter.Write(dataToDecrypt, iv.Length, dataToDecrypt.Length - iv.Length);
cryptoStream.Flush();
cryptoStream.FlushFinalBlock();
memoryStream.Position = 0;
}
decrypted = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
}
}
return decrypted;Can be written
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(dataToDecrypt, iv.Length, dataToDecrypt.Length - iv.Length);
}
return memoryStream.ToArray();
}dataToEncrypt == null || dataToEncrypt.Length < 1All code like this can be replaced with
string.IsNullOrEmpty(dataToEncrypt)byte[] iv;
using (var aes = new AesCryptoServiceProvider())
{
aes.GenerateIV();
iv = aes.IV;
}
return iv;Can be written
using (var aes = new AesCryptoServiceProvider())
{
aes.GenerateIV();
return aes.IV;
}Similar rewrites are possible in
RSA.Encrypt(byte[]) and RSA.Decrypt(byte[]).There's an unused variable
key in AES.GetEncryptionKey.Code Snippets
byte[] encryptedData;
// ...
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
using (var binaryWriter = new BinaryWriter(cryptoStream))
{
binaryWriter.Write(rij.IV);
binaryWriter.Write(dataToEncrypt);
cryptoStream.Flush();
cryptoStream.FlushFinalBlock();
memoryStream.Position = 0;
encryptedData = memoryStream.ToArray();
}
memoryStream.Close();
cryptoStream.Close();
}
}
return encryptedData;using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(rij.IV, 0, rij.IV.Length);
cryptoStream.Write(dataToEncrypt, 0, dataToEncrypt.Length);
}
return memoryStream.ToArray();
}byte[] decrypted;
// ...
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
using (var binaryWriter = new BinaryWriter(cryptoStream))
{
binaryWriter.Write(dataToDecrypt, iv.Length, dataToDecrypt.Length - iv.Length);
cryptoStream.Flush();
cryptoStream.FlushFinalBlock();
memoryStream.Position = 0;
}
decrypted = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
}
}
return decrypted;using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(dataToDecrypt, iv.Length, dataToDecrypt.Length - iv.Length);
}
return memoryStream.ToArray();
}dataToEncrypt == null || dataToEncrypt.Length < 1Context
StackExchange Code Review Q#84922, answer score: 10
Revisions (0)
No revisions yet.