diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs
index 7b24360058..e615334fe9 100644
--- a/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs
+++ b/src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs
@@ -300,6 +300,27 @@ public static byte[] GenerateKeyBytes(int sizeInBits)
return key;
}
+ ///
+ /// Generates key bytes.
+ ///
+ public static byte[] GenerateAesGcmKeyBytes(int sizeInBits)
+ {
+ byte[] key = null;
+ if (sizeInBits != 128 && sizeInBits != 192 && sizeInBits != 256)
+ throw LogHelper.LogExceptionMessage(new ArgumentException(TokenLogMessages.IDX10402, nameof(sizeInBits)));
+
+ using (var aes = Aes.Create())
+ {
+ int sizeInBytes = sizeInBits >> 3;
+ key = new byte[sizeInBytes];
+ aes.KeySize = sizeInBits;
+ aes.GenerateKey();
+ Array.Copy(aes.Key, key, sizeInBytes);
+ }
+
+ return key;
+ }
+
internal static SecurityKey GetSecurityKey(
EncryptingCredentials encryptingCredentials,
CryptoProviderFactory cryptoProviderFactory,
@@ -362,9 +383,17 @@ internal static SecurityKey GetSecurityKey(
securityKey = new SymmetricSecurityKey(GenerateKeyBytes(384));
else if (SecurityAlgorithms.Aes256CbcHmacSha512.Equals(encryptingCredentials.Enc))
securityKey = new SymmetricSecurityKey(GenerateKeyBytes(512));
+
+ // only 128, 192 and 256 AesGcm for CEK algorithm
+ else if(SecurityAlgorithms.Aes128Gcm.Equals(encryptingCredentials.Enc))
+ securityKey = new SymmetricSecurityKey(GenerateAesGcmKeyBytes(128));
+ else if (SecurityAlgorithms.Aes192Gcm.Equals(encryptingCredentials.Enc))
+ securityKey = new SymmetricSecurityKey(GenerateAesGcmKeyBytes(192));
+ else if (SecurityAlgorithms.Aes256Gcm.Equals(encryptingCredentials.Enc))
+ securityKey = new SymmetricSecurityKey(GenerateAesGcmKeyBytes(256));
else
throw LogHelper.LogExceptionMessage(
- new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10617, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes128CbcHmacSha256), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes192CbcHmacSha384), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes256CbcHmacSha512), LogHelper.MarkAsNonPII(encryptingCredentials.Enc))));
+ new SecurityTokenEncryptionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10617, LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes128CbcHmacSha256), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes192CbcHmacSha384), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes256CbcHmacSha512), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes128Gcm), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes192Gcm), LogHelper.MarkAsNonPII(SecurityAlgorithms.Aes256Gcm), LogHelper.MarkAsNonPII(encryptingCredentials.Enc))));
kwProvider = cryptoProviderFactory.CreateKeyWrapProvider(encryptingCredentials.Key, encryptingCredentials.Alg);
wrappedKey = kwProvider.WrapKey(((SymmetricSecurityKey)securityKey).Key);
diff --git a/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs b/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs
index bf137b3491..a75e6d71bc 100644
--- a/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs
+++ b/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs
@@ -98,7 +98,35 @@ internal bool ValidKeySize()
private AuthenticatedEncryptionResult EncryptWithAesGcm(byte[] plaintext, byte[] authenticatedData, byte[] iv)
{
- throw LogHelper.LogExceptionMessage(new NotSupportedException(LogHelper.FormatInvariant(LogMessages.IDX10715, LogHelper.MarkAsNonPII(Algorithm))));
+ _ = _keySizeIsValid.Value;
+
+ byte[] nonce = new byte[Tokens.AesGcm.NonceSize];
+ byte[] cipherText = new byte[plaintext.Length];
+ byte[] authenticationTag = new byte[Tokens.AesGcm.TagSize];
+
+ using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
+ {
+ rng.GetBytes(nonce);
+ }
+
+ AesGcm aes = null;
+ try
+ {
+ aes = _aesGcmObjectPool.Allocate();
+ aes.Encrypt(nonce, plaintext, cipherText, authenticationTag, authenticatedData);
+ }
+ catch
+ {
+ Dispose(true);
+ throw;
+ }
+ finally
+ {
+ if (!_disposed)
+ _aesGcmObjectPool.Free(aes);
+ }
+
+ return new AuthenticatedEncryptionResult(Key, cipherText, nonce, authenticationTag);
}
private AesGcm CreateAesGcmInstance()
diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs
index d01e092787..74fb6219a5 100644
--- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs
+++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs
@@ -115,7 +115,7 @@ internal static class LogMessages
// public const string IDX10614 = "IDX10614:";
public const string IDX10615 = "IDX10615: Encryption failed. No support for: Algorithm: '{0}', SecurityKey: '{1}'.";
public const string IDX10616 = "IDX10616: Encryption failed. EncryptionProvider failed for: Algorithm: '{0}', SecurityKey: '{1}'. See inner exception.";
- public const string IDX10617 = "IDX10617: Encryption failed. Keywrap is only supported for: '{0}', '{1}' and '{2}'. The content encryption specified is: '{3}'.";
+ public const string IDX10617 = "IDX10617: Encryption failed. Keywrap is only supported for: '{0}', '{1}', '{2}', '{3}', '{4}', and '{5}'. The content encryption specified is: '{6}'.";
public const string IDX10618 = "IDX10618: Key unwrap failed using decryption Keys: '{0}'.\nExceptions caught:\n '{1}'.\ntoken: '{2}'.";
public const string IDX10619 = "IDX10619: Decryption failed. Algorithm: '{0}'. Either the Encryption Algorithm: '{1}' or none of the Security Keys are supported by the CryptoProviderFactory.";
public const string IDX10620 = "IDX10620: Unable to obtain a CryptoProviderFactory, both EncryptingCredentials.CryptoProviderFactory and EncryptingCredentials.Key.CrypoProviderFactory are null.";
@@ -126,6 +126,7 @@ internal static class LogMessages
// Formating
public const string IDX10400 = "IDX10400: Unable to decode: '{0}' as Base64url encoded string.";
public const string IDX10401 = "IDX10401: Invalid requested key size. Valid key sizes are: 256, 384, and 512.";
+ public const string IDX10402 = "IDX10402: Invalid requested key size. Valid key sizes are: 128, 192, and 256.";
// Crypto Errors
public const string IDX10621 = "IDX10621: '{0}' supports: '{1}' of types: '{2}' or '{3}'. SecurityKey received was of type '{4}'.";
diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs
index 1357f6cff2..7e790960b5 100644
--- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs
+++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs
@@ -437,18 +437,16 @@ public static TheoryData CreateJWEWithAesGcmTheoryData
};
tokenHandler.InboundClaimTypeMap.Clear();
- var encryptionCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm128;
- encryptionCredentials.CryptoProviderFactory = new CryptoProviderFactoryMock();
return new TheoryData
{
new CreateTokenTheoryData
{
First = true,
- TestId = "AesGcm128EncryptionWithMock",
+ TestId = "AesGcm128Encryption",
TokenDescriptor = new SecurityTokenDescriptor
{
SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
- EncryptingCredentials = encryptionCredentials,
+ EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm128,
Subject = new ClaimsIdentity(Default.PayloadClaims),
TokenType = "TokenType"
},
@@ -463,6 +461,27 @@ public static TheoryData CreateJWEWithAesGcmTheoryData
}
},
new CreateTokenTheoryData
+ {
+ First = true,
+ TestId = "AesGcm192Encryption",
+ TokenDescriptor = new SecurityTokenDescriptor
+ {
+ SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
+ EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm192,
+ Subject = new ClaimsIdentity(Default.PayloadClaims),
+ TokenType = "TokenType"
+ },
+ JsonWebTokenHandler = new JsonWebTokenHandler(),
+ JwtSecurityTokenHandler = tokenHandler,
+ ValidationParameters = new TokenValidationParameters
+ {
+ IssuerSigningKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key,
+ TokenDecryptionKey = KeyingMaterial.DefaultSymmetricSecurityKey_192,
+ ValidAudience = Default.Audience,
+ ValidIssuer = Default.Issuer
+ }
+ },
+ new CreateTokenTheoryData
{
TestId = "AesGcm256Encryption",
TokenDescriptor = new SecurityTokenDescriptor
@@ -474,7 +493,73 @@ public static TheoryData CreateJWEWithAesGcmTheoryData
},
JsonWebTokenHandler = new JsonWebTokenHandler(),
JwtSecurityTokenHandler = tokenHandler,
- ExpectedException = ExpectedException.SecurityTokenEncryptionFailedException("IDX10616:", typeof(NotSupportedException))
+ ValidationParameters = new TokenValidationParameters
+ {
+ IssuerSigningKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key,
+ TokenDecryptionKey = KeyingMaterial.DefaultSymmetricSecurityKey_256,
+ ValidAudience = Default.Audience,
+ ValidIssuer = Default.Issuer
+ }
+ },
+ new CreateTokenTheoryData
+ {
+ TestId = "AesGcm128Encryption_Aes128KW",
+ TokenDescriptor = new SecurityTokenDescriptor
+ {
+ SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
+ EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm128_Aes128KW,
+ Subject = new ClaimsIdentity(Default.PayloadClaims),
+ TokenType = "TokenType"
+ },
+ JsonWebTokenHandler = new JsonWebTokenHandler(),
+ JwtSecurityTokenHandler = tokenHandler,
+ ValidationParameters = new TokenValidationParameters
+ {
+ IssuerSigningKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key,
+ TokenDecryptionKey = KeyingMaterial.DefaultSymmetricSecurityKey_128,
+ ValidAudience = Default.Audience,
+ ValidIssuer = Default.Issuer
+ }
+ },
+ new CreateTokenTheoryData
+ {
+ TestId = "AesGcm192Encryption_Aes192KW",
+ TokenDescriptor = new SecurityTokenDescriptor
+ {
+ SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
+ EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm192_Aes192KW,
+ Subject = new ClaimsIdentity(Default.PayloadClaims),
+ TokenType = "TokenType"
+ },
+ JsonWebTokenHandler = new JsonWebTokenHandler(),
+ JwtSecurityTokenHandler = tokenHandler,
+ ValidationParameters = new TokenValidationParameters
+ {
+ IssuerSigningKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key,
+ TokenDecryptionKey = KeyingMaterial.DefaultSymmetricSecurityKey_192,
+ ValidAudience = Default.Audience,
+ ValidIssuer = Default.Issuer
+ }
+ },
+ new CreateTokenTheoryData
+ {
+ TestId = "AesGcm256Encryption_Aes256KW",
+ TokenDescriptor = new SecurityTokenDescriptor
+ {
+ SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
+ EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm256_Aes256KW,
+ Subject = new ClaimsIdentity(Default.PayloadClaims),
+ TokenType = "TokenType"
+ },
+ JsonWebTokenHandler = new JsonWebTokenHandler(),
+ JwtSecurityTokenHandler = tokenHandler,
+ ValidationParameters = new TokenValidationParameters
+ {
+ IssuerSigningKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key,
+ TokenDecryptionKey = KeyingMaterial.DefaultSymmetricSecurityKey_256,
+ ValidAudience = Default.Audience,
+ ValidIssuer = Default.Issuer
+ }
},
new CreateTokenTheoryData
{
@@ -482,7 +567,7 @@ public static TheoryData CreateJWEWithAesGcmTheoryData
TokenDescriptor = new SecurityTokenDescriptor
{
SigningCredentials = KeyingMaterial.JsonWebKeyRsa256SigningCredentials,
- EncryptingCredentials = encryptionCredentials,
+ EncryptingCredentials = KeyingMaterial.DefaultSymmetricEncryptingCreds_AesGcm128,
Subject = new ClaimsIdentity(Default.PayloadClaims),
TokenType = "TokenType"
},
diff --git a/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs b/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs
index ce44b35a13..3ae3bd211a 100644
--- a/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs
+++ b/test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs
@@ -226,11 +226,19 @@ public static RsaSecurityKey RsaSecurityKey2
public static byte[] DefaultSymmetricKeyBytes_128 = Convert.FromBase64String(DefaultSymmetricKeyEncoded_128);
public static SymmetricSecurityKey DefaultSymmetricSecurityKey_128 = new SymmetricSecurityKey(DefaultSymmetricKeyBytes_128) { KeyId = "DefaultSymmetricSecurityKey_128" };
public static EncryptingCredentials DefaultSymmetricEncryptingCreds_AesGcm128 = new EncryptingCredentials(DefaultSymmetricSecurityKey_128, "dir", SecurityAlgorithms.Aes128Gcm);
+ public static EncryptingCredentials DefaultSymmetricEncryptingCreds_AesGcm128_Aes128KW = new EncryptingCredentials(DefaultSymmetricSecurityKey_128, SecurityAlgorithms.Aes128KW, SecurityAlgorithms.Aes128Gcm);
+
+ public static string DefaultSymmetricKeyEncoded_192 = "06P7WdwAEybptADtJis9n0oWnG5imp8G";
+ public static byte[] DefaultSymmetricKeyBytes_192 = Convert.FromBase64String(DefaultSymmetricKeyEncoded_192);
+ public static SymmetricSecurityKey DefaultSymmetricSecurityKey_192 = new SymmetricSecurityKey(DefaultSymmetricKeyBytes_192) { KeyId = "DefaultSymmetricSecurityKey_192" };
+ public static EncryptingCredentials DefaultSymmetricEncryptingCreds_AesGcm192 = new EncryptingCredentials(DefaultSymmetricSecurityKey_192, "dir", SecurityAlgorithms.Aes192Gcm);
+ public static EncryptingCredentials DefaultSymmetricEncryptingCreds_AesGcm192_Aes192KW = new EncryptingCredentials(DefaultSymmetricSecurityKey_192, SecurityAlgorithms.Aes192KW, SecurityAlgorithms.Aes192Gcm);
public static string DefaultSymmetricKeyEncoded_256 = "Vbxq2mlbGJw8XH+ZoYBnUHmHga8/o/IduvU/Tht70iE=";
public static byte[] DefaultSymmetricKeyBytes_256 = Convert.FromBase64String(DefaultSymmetricKeyEncoded_256);
public static SymmetricSecurityKey DefaultSymmetricSecurityKey_256 = new SymmetricSecurityKey(DefaultSymmetricKeyBytes_256) { KeyId = "DefaultSymmetricSecurityKey_256" };
public static EncryptingCredentials DefaultSymmetricEncryptingCreds_AesGcm256 = new EncryptingCredentials(DefaultSymmetricSecurityKey_256, "dir", SecurityAlgorithms.Aes256Gcm);
+ public static EncryptingCredentials DefaultSymmetricEncryptingCreds_AesGcm256_Aes256KW = new EncryptingCredentials(DefaultSymmetricSecurityKey_256, SecurityAlgorithms.Aes256KW, SecurityAlgorithms.Aes256Gcm);
public static SigningCredentials DefaultSymmetricSigningCreds_256_Sha2 = new SigningCredentials(DefaultSymmetricSecurityKey_256, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256);
public static EncryptingCredentials DefaultSymmetricEncryptingCreds_Aes128_Sha2 = new EncryptingCredentials(DefaultSymmetricSecurityKey_256, "dir", SecurityAlgorithms.Aes128CbcHmacSha256);
public static SymmetricSecurityKey DefaultSymmetricSecurityKey_256_NoKeyId = new SymmetricSecurityKey(DefaultSymmetricKeyBytes_256);