1

Besides the limited nonce size of 96 bits, are there any other weaknesses to the GCM mode of AES?

I am creating a password vault and am trying to narrow down my options of encryption schemes.

Also, is this a safe and secure implementation of AES-GCM?

public static async Task<byte[]> EncryptAsyncV2(byte[] plainText, byte[] password, byte[] nonce, byte[] salt)
    {
        try
        {
            if (plainText == null)
                throw new ArgumentException(@"Value was empty or null.", nameof(plainText));
            if (password == null)
                throw new ArgumentException(@"Value was empty or null.", nameof(password));
            if (salt == null)
                throw new ArgumentException(@"Value was empty or null.", nameof(salt));
            if (nonce == null)
                throw new ArgumentException(@"Value was empty or null.", nameof(nonce));
        var cipherText = new byte[plainText.Length];
        var tag = new byte[TagLen];

        using (var argon2 = new Argon2id(password))
        {
            argon2.Salt = salt;
            argon2.DegreeOfParallelism = Environment.ProcessorCount * 2;
            argon2.Iterations = Iterations;
            argon2.MemorySize = (int)MemorySize;

            var key = await argon2.GetBytesAsync(KeySize);

            using var aesGcm = new AesGcm(key, TagLen);
            aesGcm.Encrypt(nonce, plainText, cipherText, tag);
            Array.Clear(key, 0, key.Length);
        }

        cipherText = tag.Concat(nonce.Concat(cipherText)).ToArray();
        return cipherText;
    }
    catch (CryptographicException ex)
    {
        Array.Clear(password, 0, password.Length);
        ErrorLogging.ErrorLog(ex);
        return Array.Empty&lt;byte&gt;();
    }
    catch (ArgumentNullException ex)
    {
        Array.Clear(password, 0, password.Length);
        ErrorLogging.ErrorLog(ex);
        return Array.Empty&lt;byte&gt;();
    }
    catch (Exception ex)
    {
        Array.Clear(password!, 0, password!.Length);
        ErrorLogging.ErrorLog(ex);
        return Array.Empty&lt;byte&gt;();
    }
}

public static async Task&lt;byte[]&gt; DecryptAsyncV2(byte[] cipherText, byte[] password, byte[] salt)
{
    try
    {
        if (cipherText == null)
            throw new ArgumentException(@&quot;Value was empty or null.&quot;, nameof(cipherText));
        if (password == null)
            throw new ArgumentException(@&quot;Value was empty or null.&quot;, nameof(password));
        if (salt == null)
            throw new ArgumentException(@&quot;Value was empty or null.&quot;, nameof(salt));

        using var argon2 = new Argon2id(password);
        argon2.Salt = salt;
        argon2.DegreeOfParallelism = Environment.ProcessorCount * 2;
        argon2.Iterations = Iterations;
        argon2.MemorySize = (int)MemorySize;

        var key = await argon2.GetBytesAsync(KeySize);

        using var aesGcm = new AesGcm(key, TagLen);
        var tag = new byte[TagLen];
        var nonce = new byte[NonceSize];
        var cipherResult = new byte[cipherText.Length - nonce.Length - tag.Length];

        Buffer.BlockCopy(cipherText, 0, tag, 0, tag.Length);
        Buffer.BlockCopy(cipherText, tag.Length, nonce, 0, nonce.Length);
        Buffer.BlockCopy(cipherText, tag.Length + nonce.Length, cipherResult, 0, cipherResult.Length);

        var plainText = new byte[cipherResult.Length];

        aesGcm.Decrypt(nonce, cipherResult, tag, plainText);

        Array.Clear(key, 0, key.Length);

        return plainText;
    }
    catch (CryptographicException ex)
    {
        Array.Clear(password, 0, password.Length);
        ErrorLogging.ErrorLog(ex);
        return Array.Empty&lt;byte&gt;();
    }
    catch (ArgumentNullException ex)
    {
        Array.Clear(password, 0, password.Length);
        ErrorLogging.ErrorLog(ex);
        return Array.Empty&lt;byte&gt;();
    }
    catch (Exception ex)
    {
        Array.Clear(password!, 0, password!.Length);
        ErrorLogging.ErrorLog(ex);
        return Array.Empty&lt;byte&gt;();
    }

#pragma warning restore }

The nonce is generated with the RandomNumberGenerator class using this method

public static byte[] RndByteSized(int size)
    {
        var buffer = new byte[size];
        RndNum.GetBytes(buffer);
        return buffer;
    }

0 Answers0