Skip to content

Commit

Permalink
Aesgcm
Browse files Browse the repository at this point in the history
  • Loading branch information
RojaEnnam committed Mar 3, 2021
1 parent 705da5b commit f2b7a2d
Show file tree
Hide file tree
Showing 16 changed files with 854 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ private static string EncryptTokenPrivate(string innerJwt, EncryptingCredentials
throw LogHelper.LogExceptionMessage(new ArgumentException(TokenLogMessages.IDX10620));

byte[] wrappedKey = null;
SecurityKey securityKey = JwtTokenUtilities.GetSecurityKey(encryptingCredentials,cryptoProviderFactory, out wrappedKey);
SecurityKey securityKey = JwtTokenUtilities.GetSecurityKey(encryptingCredentials, cryptoProviderFactory, out wrappedKey);

using (var encryptionProvider = cryptoProviderFactory.CreateAuthenticatedEncryptionProvider(securityKey, encryptingCredentials.Enc))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public virtual AuthenticatedEncryptionProvider CreateAuthenticatedEncryptionProv
return cryptoProvider;
}

if (SupportedAlgorithms.IsSupportedAuthenticatedEncryptionAlgorithm(algorithm, key))
if (SupportedAlgorithms.IsSupportedAuthenticatedEncryptionAlgorithm(algorithm, key) || SupportedAlgorithms.IsSupportedAesGcmEncryptionAlgorithm(algorithm, key))
return new AuthenticatedEncryptionProvider(key, algorithm);

throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10652, algorithm), nameof(algorithm)));
Expand Down
36 changes: 36 additions & 0 deletions src/Microsoft.IdentityModel.Tokens/Encryption/AesGcm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;

namespace Microsoft.IdentityModel.Tokens
{
internal class AesGcm : IDisposable
{
public const int NonceSize = 12;
public const int TagSize = 16;

private static readonly SafeAlgorithmHandle s_aesGcm = AesBCryptModes.OpenAesAlgorithm(Cng.BCRYPT_CHAIN_MODE_GCM).Value;
private SafeKeyHandle _keyHandle;
public AesGcm(byte[] key)
{
if (key == null)
throw new ArgumentNullException(nameof(key));

ImportKey(key);
}

private void ImportKey(byte[] key)
{
_keyHandle = Interop.BCrypt.BCryptImportKey(s_aesGcm, key);
}

public void Dispose()
{
_keyHandle.Dispose();
}

public void Decrypt(byte[] nonce, byte[] ciphertext, byte[] tag, byte[] plaintext, byte[] associatedData = null)
{
AesAEAD.CheckArgumentsForNull(nonce, plaintext, ciphertext, tag);
AesAEAD.Decrypt(_keyHandle, nonce, associatedData, ciphertext, tag, plaintext, clearPlaintextOnFailure: true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@

namespace Microsoft.IdentityModel.Tokens
{
delegate AuthenticatedEncryptionResult EncryptionDelegate(byte[] plaintText, byte[] authenticatedData, byte[] iv);
delegate byte[] DecryptionDelegate(byte[] cipherText, byte[] authenticatedData, byte[] iv, byte[] authenticationTag);

/// <summary>
/// Provides authenticated encryption and decryption services.
/// </summary>
Expand All @@ -48,6 +51,8 @@ private struct AuthenticatedKeys
private bool _disposed;
private string _hmacAlgorithm;
private Lazy<SymmetricSignatureProvider> _symmetricSignatureProvider;
private DecryptionDelegate DecryptFunction;
private EncryptionDelegate EncryptFunction;

/// <summary>
/// Initializes a new instance of the <see cref="AuthenticatedEncryptionProvider"/> class used for encryption and decryption.
Expand All @@ -67,20 +72,117 @@ public AuthenticatedEncryptionProvider(SecurityKey key, string algorithm)
if (string.IsNullOrWhiteSpace(algorithm))
throw LogHelper.LogArgumentNullException(nameof(algorithm));

_authenticatedkeys = new Lazy<AuthenticatedKeys>(CreateAuthenticatedKeys);
_hmacAlgorithm = GetHmacAlgorithm(algorithm);
Key = key;
Algorithm = algorithm;
_cryptoProviderFactory = key.CryptoProviderFactory;

if (SupportedAlgorithms.IsSupportedAesGcmEncryptionAlgorithm(algorithm, key))
{
#if NET_CORE
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
throw LogHelper.LogExceptionMessage(new PlatformNotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX10713, algorithm)));
#endif
InitializeUsingAesGcm();
}
else if (SupportedAlgorithms.IsSupportedAuthenticatedEncryptionAlgorithm(algorithm, key))
InitializeUsingAesCbc();
else
throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10668, GetType(), algorithm, key)));
}

private void InitializeUsingAesGcm()
{
ValidateKeySize(Key, Algorithm);
EncryptFunction = EncryptWithAesGcm;
DecryptFunction = DecryptWithAesGcm;
}

private void InitializeUsingAesCbc()
{
_authenticatedkeys = new Lazy<AuthenticatedKeys>(CreateAuthenticatedKeys);
_hmacAlgorithm = GetHmacAlgorithm(Algorithm);
_symmetricSignatureProvider = new Lazy<SymmetricSignatureProvider>(CreateSymmetricSignatureProvider);
EncryptFunction = EncryptWithAesCbc;
DecryptFunction = DecryptWithAesCbc;
}

private AuthenticatedKeys CreateAuthenticatedKeys()
private AuthenticatedEncryptionResult EncryptWithAesGcm(byte[] plaintext, byte[] authenticatedData, byte[] iv)
{
if (!IsSupportedAlgorithm(Key, Algorithm))
throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10668, GetType(), Algorithm, Key)));
throw LogHelper.LogExceptionMessage(new NotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX10699, Algorithm)));
}

private byte[] DecryptWithAesGcm(byte[] ciphertext, byte[] authenticatedData, byte[] iv, byte[] authenticationTag)
{
byte[] clearBytes = new byte[ciphertext.Length];
using (var aes = new AesGcm(GetKeyBytes(Key)))
{
aes.Decrypt(iv, ciphertext, authenticationTag, clearBytes, authenticatedData);
}

return clearBytes;
}

private AuthenticatedEncryptionResult EncryptWithAesCbc(byte[] plaintext, byte[] authenticatedData, byte[] iv)
{
using Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = _authenticatedkeys.Value.AesKey.Key;
if (iv != null)
aes.IV = iv;

byte[] ciphertext;
try
{
ciphertext = Transform(aes.CreateEncryptor(), plaintext, 0, plaintext.Length);
}
catch (Exception ex)
{
throw LogHelper.LogExceptionMessage(new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(LogMessages.IDX10654, ex)));
}

byte[] al = Utility.ConvertToBigEndian(authenticatedData.Length * 8);
byte[] macBytes = new byte[authenticatedData.Length + aes.IV.Length + ciphertext.Length + al.Length];
Array.Copy(authenticatedData, 0, macBytes, 0, authenticatedData.Length);
Array.Copy(aes.IV, 0, macBytes, authenticatedData.Length, aes.IV.Length);
Array.Copy(ciphertext, 0, macBytes, authenticatedData.Length + aes.IV.Length, ciphertext.Length);
Array.Copy(al, 0, macBytes, authenticatedData.Length + aes.IV.Length + ciphertext.Length, al.Length);
byte[] macHash = _symmetricSignatureProvider.Value.Sign(macBytes);
var authenticationTag = new byte[_authenticatedkeys.Value.HmacKey.Key.Length];
Array.Copy(macHash, authenticationTag, authenticationTag.Length);

return new AuthenticatedEncryptionResult(Key, ciphertext, aes.IV, authenticationTag);
}

private byte[] DecryptWithAesCbc(byte[] ciphertext, byte[] authenticatedData, byte[] iv, byte[] authenticationTag)
{
// Verify authentication Tag
byte[] al = Utility.ConvertToBigEndian(authenticatedData.Length * 8);
byte[] macBytes = new byte[authenticatedData.Length + iv.Length + ciphertext.Length + al.Length];
Array.Copy(authenticatedData, 0, macBytes, 0, authenticatedData.Length);
Array.Copy(iv, 0, macBytes, authenticatedData.Length, iv.Length);
Array.Copy(ciphertext, 0, macBytes, authenticatedData.Length + iv.Length, ciphertext.Length);
Array.Copy(al, 0, macBytes, authenticatedData.Length + iv.Length + ciphertext.Length, al.Length);
if (!_symmetricSignatureProvider.Value.Verify(macBytes, authenticationTag, _authenticatedkeys.Value.HmacKey.Key.Length))
throw LogHelper.LogExceptionMessage(new SecurityTokenDecryptionFailedException(LogHelper.FormatInvariant(LogMessages.IDX10650, Base64UrlEncoder.Encode(authenticatedData), Base64UrlEncoder.Encode(iv), Base64UrlEncoder.Encode(authenticationTag))));

using Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = _authenticatedkeys.Value.AesKey.Key;
aes.IV = iv;
try
{
return Transform(aes.CreateDecryptor(), ciphertext, 0, ciphertext.Length);
}
catch (Exception ex)
{
throw LogHelper.LogExceptionMessage(new SecurityTokenDecryptionFailedException(LogHelper.FormatInvariant(LogMessages.IDX10654, ex)));
}
}

private AuthenticatedKeys CreateAuthenticatedKeys()
{
ValidateKeySize(Key, Algorithm);

return GetAlgorithmParameters(Key, Algorithm);
Expand Down Expand Up @@ -158,34 +260,7 @@ public virtual AuthenticatedEncryptionResult Encrypt(byte[] plaintext, byte[] au
if (_disposed)
throw LogHelper.LogExceptionMessage(new ObjectDisposedException(GetType().ToString()));

using Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = _authenticatedkeys.Value.AesKey.Key;
if (iv != null)
aes.IV = iv;

byte[] ciphertext;
try
{
ciphertext = Transform(aes.CreateEncryptor(), plaintext, 0, plaintext.Length);
}
catch(Exception ex)
{
throw LogHelper.LogExceptionMessage(new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(LogMessages.IDX10654, ex)));
}

byte[] al = Utility.ConvertToBigEndian(authenticatedData.Length * 8);
byte[] macBytes = new byte[authenticatedData.Length + aes.IV.Length + ciphertext.Length + al.Length];
Array.Copy(authenticatedData, 0, macBytes, 0, authenticatedData.Length);
Array.Copy(aes.IV, 0, macBytes, authenticatedData.Length, aes.IV.Length);
Array.Copy(ciphertext, 0, macBytes, authenticatedData.Length + aes.IV.Length, ciphertext.Length);
Array.Copy(al, 0, macBytes, authenticatedData.Length + aes.IV.Length + ciphertext.Length, al.Length);
byte[] macHash = _symmetricSignatureProvider.Value.Sign(macBytes);
var authenticationTag = new byte[_authenticatedkeys.Value.HmacKey.Key.Length];
Array.Copy(macHash, authenticationTag, authenticationTag.Length);

return new AuthenticatedEncryptionResult(Key, ciphertext, aes.IV, authenticationTag);
return EncryptFunction(plaintext, authenticatedData, iv);
}

/// <summary>
Expand Down Expand Up @@ -220,29 +295,7 @@ public virtual byte[] Decrypt(byte[] ciphertext, byte[] authenticatedData, byte[
if (_disposed)
throw LogHelper.LogExceptionMessage(new ObjectDisposedException(GetType().ToString()));

// Verify authentication Tag
byte[] al = Utility.ConvertToBigEndian(authenticatedData.Length * 8);
byte[] macBytes = new byte[authenticatedData.Length + iv.Length + ciphertext.Length + al.Length];
Array.Copy(authenticatedData, 0, macBytes, 0, authenticatedData.Length);
Array.Copy(iv, 0, macBytes, authenticatedData.Length, iv.Length);
Array.Copy(ciphertext, 0, macBytes, authenticatedData.Length + iv.Length, ciphertext.Length);
Array.Copy(al, 0, macBytes, authenticatedData.Length + iv.Length + ciphertext.Length, al.Length);
if (!_symmetricSignatureProvider.Value.Verify(macBytes, authenticationTag, _authenticatedkeys.Value.HmacKey.Key.Length))
throw LogHelper.LogExceptionMessage(new SecurityTokenDecryptionFailedException(LogHelper.FormatInvariant(LogMessages.IDX10650, Base64UrlEncoder.Encode(authenticatedData), Base64UrlEncoder.Encode(iv), Base64UrlEncoder.Encode(authenticationTag))));

using Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = _authenticatedkeys.Value.AesKey.Key;
aes.IV = iv;
try
{
return Transform(aes.CreateDecryptor(), ciphertext, 0, ciphertext.Length);
}
catch (Exception ex)
{
throw LogHelper.LogExceptionMessage(new SecurityTokenDecryptionFailedException(LogHelper.FormatInvariant(LogMessages.IDX10654, ex)));
}
return DecryptFunction(ciphertext, authenticatedData, iv, authenticationTag);
}

/// <summary>
Expand Down Expand Up @@ -404,6 +457,30 @@ protected virtual void ValidateKeySize(SecurityKey key, string algorithm)
return;
}

if (SecurityAlgorithms.Aes128Gcm.Equals(algorithm, StringComparison.Ordinal))
{
if (key.KeySize < 128)
throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, SecurityAlgorithms.Aes128Gcm, 128, key.KeyId, key.KeySize)));

return;
}

if (SecurityAlgorithms.Aes192Gcm.Equals(algorithm, StringComparison.Ordinal))
{
if (key.KeySize < 192)
throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, SecurityAlgorithms.Aes192Gcm, 192, key.KeyId, key.KeySize)));

return;
}

if (SecurityAlgorithms.Aes256Gcm.Equals(algorithm, StringComparison.Ordinal))
{
if (key.KeySize < 256)
throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), LogHelper.FormatInvariant(LogMessages.IDX10653, SecurityAlgorithms.Aes256Gcm, 256, key.KeyId, key.KeySize)));

return;
}

throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX10652, algorithm)));
}
}
Expand Down
Loading

0 comments on commit f2b7a2d

Please sign in to comment.