HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

An AES Cryptography Wrapper

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
wrappercryptographyaes

Problem

I built this wrapper over the System.Security.Cryptography.Aes encryption/decryption so that one need only instance the class and call the appropriate methods. This makes it much simpler to work with AES encryption so that developers don't need to reuse the same AES code everywhere they need encryption.

Any and all comments are much appreciated.

```
///
/// Provides Cryptography methods based on AES cryptography implementation.
///
public class AesCrypto
{
///
/// Gets or sets the salt to use with AES encryption.
///
public byte[] Salt { get; set; }

///
/// Gets or sets the passphrase for use with AES encryption.
///
public string Passphrase { get; set; }

///
/// Constructs a new instance of from the specified values.
///
/// The used in encryption.
/// The used in encryption.
public AesCrypto(byte[] salt, string passphrase)
{
if (string.IsNullOrWhiteSpace(passphrase))
{
throw new ArgumentException($"The parameter {nameof(passphrase)} is required.");
}

if (salt == null || salt.Length == 0)
{
throw new ArgumentException($"The parameter {nameof(salt)} is required.");
}

Salt = salt;
Passphrase = passphrase;
}

///
/// Uses AES encryption to encrypt a string of data.
///
/// The data to encrypt. Data is expected to be Unicode.
/// An encrypted Base64 string.
public string AesEncrypt(string clearText)
{
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);

using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(Passphrase, Salt);
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);

using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))

Solution

public string AesEncrypt(string clearText)
{
    byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);

    using (Aes encryptor = Aes.Create())
    {
        Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(Passphrase, Salt);
        encryptor.Key = pdb.GetBytes(32);
        encryptor.IV = pdb.GetBytes(16);

        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearBytes, 0, clearBytes.Length);
                cs.Close();
            }

            clearText = StringExtensions.ToBase64String(ms.ToArray());
        }
    }

    return clearText;
}


-
the call of the Close() method isn't needed, because the disposing of the CryptoStream will close the stream (See the source).

-
Instead of calling ms.ToArray() you should use the MemoryStream.GetBuffer() method to avoid having a copy of the byte array.

The same is true for the AesDecryptInternal() method.

  • because Rfc2898DeriveBytes is inheriting DerivedBytes which is implementing IDisposable you should enclose it in an using block too.



The conditions when you throw an ArgumentExceptionin the constructor aren't sufficient. The call to the Rfc2898DeriveBytes constructor will throw if the Salt isn't at least 8 bytes long. So checking against salt.Length < 8 should be done.

In addition to whats being said about the length of the Salt, you should consider to have a backing field for the Salt property so you can change the property to have the same validation there. This will be true for the Passphrase property too.

Code Snippets

public string AesEncrypt(string clearText)
{
    byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);

    using (Aes encryptor = Aes.Create())
    {
        Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(Passphrase, Salt);
        encryptor.Key = pdb.GetBytes(32);
        encryptor.IV = pdb.GetBytes(16);

        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearBytes, 0, clearBytes.Length);
                cs.Close();
            }

            clearText = StringExtensions.ToBase64String(ms.ToArray());
        }
    }

    return clearText;
}

Context

StackExchange Code Review Q#110754, answer score: 6

Revisions (0)

No revisions yet.