Skip to content

Commit 9df3569

Browse files
authored
Merge pull request #144 from IcoDeveloper/aes-gcm
Add Support for http://www.w3.org/2009/xmlenc11#aes128-gcm and http://www.w3.org/2009/xmlenc11#aes256-gcm Encryption Methods
2 parents 119c6e6 + 957823b commit 9df3569

File tree

3 files changed

+149
-0
lines changed

3 files changed

+149
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#if !NETFULL
2+
using System;
3+
using System.Security.Cryptography;
4+
5+
namespace ITfoxtec.Identity.Saml2.Cryptography
6+
{
7+
/// <summary>
8+
/// SymmetricAlgorithm decrypting implementation for http://www.w3.org/2009/xmlenc11#aes128-gcm and http://www.w3.org/2009/xmlenc11#aes256-gcm.
9+
/// This is class is not a general implementation and can only do decryption.
10+
/// </summary>
11+
public class AesGcmAlgorithm : SymmetricAlgorithm
12+
{
13+
public const string AesGcm128Identifier = "http://www.w3.org/2009/xmlenc11#aes128-gcm";
14+
public const string AesGcm256Identifier = "http://www.w3.org/2009/xmlenc11#aes256-gcm";
15+
16+
// "For the purposes of this specification, AES-GCM shall be used with a 96 bit Initialization Vector (IV) and a 128 bit Authentication Tag (T)."
17+
// Source: https://www.w3.org/TR/xmlenc-core1/#sec-AES-GCM
18+
public const int NonceSizeInBits = 96;
19+
private const int AuthenticationTagSizeInBits = 128;
20+
21+
public AesGcmAlgorithm()
22+
{
23+
LegalKeySizesValue = new[] {
24+
new KeySizes(128, 256, 128),
25+
};
26+
27+
//iv setter checks that iv is the size of a block. Not sure if there should be other block sizes
28+
LegalBlockSizesValue = new[] { new KeySizes(NonceSizeInBits, NonceSizeInBits, 0) };
29+
BlockSizeValue = NonceSizeInBits;
30+
//dummy iv value since it is accessed first in EncryptedXml.DecryptData
31+
IV = new byte[NonceSizeInBits / 8];
32+
}
33+
34+
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
35+
{
36+
return new AesGcmDecryptor(rgbKey, rgbIV, AuthenticationTagSizeInBits);
37+
}
38+
39+
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
40+
{
41+
throw new NotImplementedException();
42+
}
43+
44+
public override void GenerateIV()
45+
{
46+
throw new NotImplementedException();
47+
}
48+
49+
public override void GenerateKey()
50+
{
51+
throw new NotImplementedException();
52+
}
53+
}
54+
}
55+
#endif
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#if !NETFULL
2+
using System;
3+
using System.Security.Cryptography;
4+
5+
namespace ITfoxtec.Identity.Saml2.Cryptography
6+
{
7+
internal class AesGcmDecryptor : ICryptoTransform
8+
{
9+
10+
private readonly byte[] key;
11+
private readonly byte[] nonce;
12+
private readonly int authenticationTagSizeInBits;
13+
14+
public AesGcmDecryptor(byte[] key, byte[] nonce, int authenticationTagSizeInBits)
15+
{
16+
this.key = key;
17+
this.nonce = nonce;
18+
this.authenticationTagSizeInBits = authenticationTagSizeInBits;
19+
}
20+
21+
public bool CanReuseTransform => throw new NotImplementedException();
22+
23+
public bool CanTransformMultipleBlocks => throw new NotImplementedException();
24+
25+
public int InputBlockSize => throw new NotImplementedException();
26+
27+
public int OutputBlockSize => throw new NotImplementedException();
28+
29+
public void Dispose()
30+
{
31+
}
32+
33+
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
34+
{
35+
throw new NotImplementedException();
36+
}
37+
38+
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
39+
{
40+
//inspired by https://stackoverflow.com/a/60891115
41+
42+
var tagSize = authenticationTagSizeInBits / 8;
43+
var cipherSize = inputCount - tagSize;
44+
45+
// "The cipher text contains the IV first, followed by the encrypted octets and finally the Authentication tag."
46+
// https://www.w3.org/TR/xmlenc-core1/#sec-AES-GCM
47+
var encryptedData = inputBuffer.AsSpan().Slice(inputOffset, inputCount);
48+
var tag = encryptedData.Slice(encryptedData.Length - tagSize);
49+
50+
var cipherBytes = encryptedData.Slice(0, cipherSize);
51+
52+
var plainBytes = cipherSize < 1024
53+
? stackalloc byte[cipherSize]
54+
: new byte[cipherSize];
55+
56+
using var aesgcm = new AesGcm(key);
57+
aesgcm.Decrypt(nonce, cipherBytes, tag, plainBytes);
58+
59+
return plainBytes.ToArray();
60+
}
61+
}
62+
}
63+
#endif

src/ITfoxtec.Identity.Saml2/Cryptography/Saml2EncryptedXml.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ public class Saml2EncryptedXml : EncryptedXml
1313
public RSA EncryptionPublicKey { get; set; }
1414
public RSA EncryptionPrivateKey { get; set; }
1515

16+
#if !NETFULL
17+
static Saml2EncryptedXml()
18+
{
19+
// Register AES-GCM wrapper on .NET Core targets where AES-GCM algorithm is available
20+
CryptoConfig.AddAlgorithm(typeof(AesGcmAlgorithm), AesGcmAlgorithm.AesGcm256Identifier);
21+
CryptoConfig.AddAlgorithm(typeof(AesGcmAlgorithm), AesGcmAlgorithm.AesGcm128Identifier);
22+
}
23+
#endif
24+
1625
public Saml2EncryptedXml(RSA encryptionPublicKey) : base()
1726
{
1827
EncryptionPublicKey = encryptionPublicKey;
@@ -55,6 +64,28 @@ public virtual XmlElement EncryptAassertion(XmlElement assertionElement)
5564
}
5665
}
5766

67+
public override byte[] GetDecryptionIV(EncryptedData encryptedData, string symmetricAlgorithmUri)
68+
{
69+
if (encryptedData is null)
70+
{
71+
throw new ArgumentNullException(nameof(encryptedData));
72+
}
73+
74+
#if !NETFULL
75+
76+
var aesGcmSymmetricAlgorithmUri = symmetricAlgorithmUri ?? encryptedData.EncryptionMethod?.KeyAlgorithm;
77+
if (aesGcmSymmetricAlgorithmUri == AesGcmAlgorithm.AesGcm128Identifier || aesGcmSymmetricAlgorithmUri == AesGcmAlgorithm.AesGcm256Identifier)
78+
{
79+
int initBytesSize = 12;
80+
byte[] iv = new byte[initBytesSize];
81+
Buffer.BlockCopy(encryptedData.CipherData.CipherValue, 0, iv, 0, iv.Length);
82+
return iv;
83+
}
84+
#endif
85+
86+
return base.GetDecryptionIV(encryptedData, symmetricAlgorithmUri);
87+
}
88+
5889
public override byte[] DecryptEncryptedKey(EncryptedKey encryptedKey)
5990
{
6091
if (encryptedKey.EncryptionMethod.KeyAlgorithm == XmlEncKeyAlgorithmRSAOAEPUrl)

0 commit comments

Comments
 (0)