Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add .NET 8.0 TFM and use new AesGcm constructor #249

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions UnitTests/AesGcmTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using System.Linq;
using System.Text;
using Jose;
using Xunit;
Expand Down Expand Up @@ -39,5 +41,23 @@ public void Decrypt()
//then
Assert.Equal(Encoding.UTF8.GetBytes("decrypt me"), test);
}

[Fact]
public void DecryptTruncatedTag()
{
//given
byte[] iv = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
byte[] tag = { 121, 235, 93, 169, 185, 192, 202, 230, 130, 37, 35, 135, 46, 129, 168, 104 };
byte[] cipher = { 33, 6, 206, 1, 182, 114, 131, 218, 124, 60 };
byte[] aad = Encoding.UTF8.GetBytes("top secret");

tag = tag.SkipLast(1).ToArray();

Assert.Throws<ArgumentException>(() =>
{
//when
byte[] test = AesGcm.Decrypt(aes128Key, iv, aad, cipher, tag);
});
}
}
}
6 changes: 3 additions & 3 deletions jose-jwt/JWTSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class JwtSettings
{
public JwtSettings()
{
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't it be NET8_0 ? What NET specifically targets?

Copy link
Contributor Author

@zzyzy zzyzy Sep 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NET targets .NET 5.0 and above.

It's just for convenience like e.g. if in the future we want to target .NET 9.0 and beyond, we just need to update the csproj file with net9.0 and NET will cover it automatically without adding NET9_0 to every file.

// By giving the Unix ECDHKeyManagement implementation to windows, we enable windows version of it to work with not only CngKey but also ECDiffieHellman.
// Initially this was implemented separately, but unit tests were failing on windows due to the lack of ECDiffieHellman support.
// Since we don't know what the keys will be provided until runtime, and the registration happens before runtime, we need to make sure
Expand Down Expand Up @@ -58,7 +58,7 @@ public JwtSettings()
{ JwsAlgorithm.ES256, new EcdsaUsingSha(256) },
{ JwsAlgorithm.ES384, new EcdsaUsingSha(384) },
{ JwsAlgorithm.ES512, new EcdsaUsingSha(521) }
#elif NETSTANDARD || NET461 || NET472
#elif NETSTANDARD || NET461 || NET472 || NET
Copy link
Owner

@dvsekhvalnov dvsekhvalnov Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as mentioned in AesGcmNetCore.cs comment, no need to touch all project fuke with with extra targeting || NET as fix is just checking length and should work just fine on every plarform.

{ JwsAlgorithm.ES256, new Jose.netstandard1_4.EcdsaUsingSha(256) },
{ JwsAlgorithm.ES384, new Jose.netstandard1_4.EcdsaUsingSha(384) },
{ JwsAlgorithm.ES512, new Jose.netstandard1_4.EcdsaUsingSha(521) }
Expand Down Expand Up @@ -169,7 +169,7 @@ public JwtSettings()
private IJsonMapper jsMapper = new JSSerializerMapper();
#elif NETSTANDARD1_4
private IJsonMapper jsMapper = new NewtonsoftMapper();
#elif NETSTANDARD2_1
#elif NETSTANDARD2_1 || NET
private IJsonMapper jsMapper = new JsonMapper();
#endif

Expand Down
2 changes: 1 addition & 1 deletion jose-jwt/crypto/AesGcm.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !NETSTANDARD2_1
#if !NETSTANDARD2_1 && !NET
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
Expand Down
19 changes: 17 additions & 2 deletions jose-jwt/crypto/AesGcmNetCore.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#if NETSTANDARD2_1
#if NETSTANDARD2_1 || NET
using System;
using System.Security.Cryptography;

namespace Jose
{
public static class AesGcm
{
public static int FixedTagLength => System.Security.Cryptography.AesGcm.TagByteSizes.MaxSize; // 16 bytes

/// <summary>
/// Performs AES encryption in GCM chaining mode over plain text
/// </summary>
Expand All @@ -16,10 +19,15 @@ public static class AesGcm
/// /// <exception cref="CryptographicException">if encryption failed by any reason</exception>
public static byte[][] Encrypt(byte[] key, byte[] iv, byte[] aad, byte[] plainText)
{
#if NET
using var gcm =
new System.Security.Cryptography.AesGcm(key, FixedTagLength);
#elif NETSTANDARD2_1
using var gcm = new System.Security.Cryptography.AesGcm(key);
#endif

var ciphertext = new byte[plainText.Length];
var tag = new byte[System.Security.Cryptography.AesGcm.TagByteSizes.MaxSize];
var tag = new byte[FixedTagLength];

gcm.Encrypt(nonce: iv, plaintext: plainText, ciphertext: ciphertext, tag: tag, associatedData: aad);

Expand All @@ -37,7 +45,14 @@ public static byte[][] Encrypt(byte[] key, byte[] iv, byte[] aad, byte[] plainTe
/// <exception cref="CryptographicException">if decryption failed by any reason</exception>
public static byte[] Decrypt(byte[] key, byte[] iv, byte[] aad, byte[] cipherText, byte[] authTag)
{
#if NET
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess we can just collapse both branches together now? No need to use .NET 8.0 specific AesGcm() constructor as you check auth tag length explicitly now. And you can leverage Ensure.BitSize(..) helper right at the start of the method.

And after just clean up all NET targeting, cause no need to and PR will become nice & small, just of couple files :)

using var gcm =
new System.Security.Cryptography.AesGcm(key, FixedTagLength);
#elif NETSTANDARD2_1
if (authTag.Length != FixedTagLength)
throw new ArgumentException("The specified tag is not a valid size for this algorithm (must be " + FixedTagLength + " bytes).", nameof(authTag));
using var gcm = new System.Security.Cryptography.AesGcm(key);
#endif

var plaintext = new byte[cipherText.Length];

Expand Down
4 changes: 2 additions & 2 deletions jose-jwt/crypto/AesKeyWrap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private static byte[] AesDec(byte[] sharedKey, byte[] cipherText)
}
}
}
#elif NETSTANDARD
#elif NETSTANDARD || NET
using (Aes aes = System.Security.Cryptography.Aes.Create())
{
aes.Key = sharedKey;
Expand Down Expand Up @@ -147,7 +147,7 @@ private static byte[] AesEnc(byte[] sharedKey, byte[] plainText)
}
}
}
#elif NETSTANDARD || NET472
#elif NETSTANDARD || NET472 || NET
using (Aes aes = System.Security.Cryptography.Aes.Create())
{
aes.Key = sharedKey;
Expand Down
18 changes: 10 additions & 8 deletions jose-jwt/crypto/ConcatKDF.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using Jose.native;
using Microsoft.Win32.SafeHandles;
Expand All @@ -9,9 +10,10 @@ public static class ConcatKDF
{
// Microsoft CNG implementation is unusable on NIST-384 and NISP-521 curves due to broken key derivation
// https://stackoverflow.com/questions/10879658/existing-implementations-for-nist-sp-800-56a-concatenation-single-step-key-deriv
[SupportedOSPlatform("windows")]
public static byte[] DeriveKey(CngKey externalPubKey, CngKey privateKey, int keyBitLength, byte[] algorithmId, byte[] partyVInfo, byte[] partyUInfo, byte[] suppPubInfo)
{
#if NET40 || NET461 || NET472 || NETSTANDARD2_1
#if NET40 || NET461 || NET472 || NETSTANDARD2_1 || NET
using (var cng = new ECDiffieHellmanCng(privateKey))
{
using (SafeNCryptSecretHandle hSecretAgreement = cng.DeriveSecretAgreementHandle(externalPubKey))
Expand Down Expand Up @@ -45,7 +47,7 @@ public static byte[] DeriveKey(CngKey externalPubKey, CngKey privateKey, int key
throw new NotImplementedException("not yet");
#endif
}
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
public static byte[] DeriveEcdhKey(ECDiffieHellman externalPubKey, ECDiffieHellman privateKey, int keyBitLength, byte[] algorithmId, byte[] partyVInfo, byte[] partyUInfo, byte[] suppPubInfo)
{
// Concat KDF, as defined in Section 5.8.1 of [NIST.800-56A]
Expand All @@ -63,16 +65,16 @@ public static byte[] DeriveEcdhKey(ECDiffieHellman externalPubKey, ECDiffieHellm
suppPubInfo
);

for (int c = 1; c <= reps; c++)
{
for (int c = 1; c <= reps; c++)
{
byte[] keyMaterial = privateKey.DeriveKeyFromHash(
externalPubKey.PublicKey,
HashAlgorithmName.SHA256,
Arrays.IntToBytes(c),
otherInfo);
K[c - 1] = keyMaterial;
otherInfo);

K[c - 1] = keyMaterial;

}

return Arrays.LeftmostBits(Arrays.Concat(K), keyBitLength);
Expand Down
8 changes: 4 additions & 4 deletions jose-jwt/crypto/RsaPss.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ private static HashAlgorithm HashAlgorithm(CngAlgorithm hash)
return new SHA384Cng();
if (hash == CngAlgorithm.Sha512)
return new SHA512Cng();
throw new ArgumentException(string.Format("RsaPss expects hash function to be SHA256, SHA384 or SHA512, but was given:{0}", hash));
#elif NETSTANDARD

throw new ArgumentException(string.Format("RsaPss expects hash function to be SHA256, SHA384 or SHA512, but was given:{0}", hash));

#elif NETSTANDARD || NET
throw new NotImplementedException("not yet");
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion jose-jwt/jose-jwt.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ JSON Web Key (RFC 7517):
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>5.0.0</VersionPrefix>
<Authors>Dmitry Vsekhvalnov</Authors>
<TargetFrameworks>net40;net461;net472;netstandard1.4;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net40;net461;net472;netstandard1.4;netstandard2.1;net8.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<AssemblyName>jose-jwt</AssemblyName>
<PackageId>jose-jwt</PackageId>
Expand Down
13 changes: 7 additions & 6 deletions jose-jwt/jose-jwt.net40.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,15 @@
<Compile Include="util\Compact.cs" />
<Compile Include="util\Dictionaries.cs" />
<Compile Include="util\Ensure.cs" />
<Compile Include="util\SupportedOSPlatform.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
1 change: 1 addition & 0 deletions jose-jwt/jose-jwt.net46.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
<Compile Include="util\Compact.cs" />
<Compile Include="util\Dictionaries.cs" />
<Compile Include="util\Ensure.cs" />
<Compile Include="util\SupportedOSPlatform.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
1 change: 1 addition & 0 deletions jose-jwt/jose-jwt.net47.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<Compile Include="util\Compact.cs" />
<Compile Include="util\Dictionaries.cs" />
<Compile Include="util\Ensure.cs" />
<Compile Include="util\SupportedOSPlatform.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
2 changes: 1 addition & 1 deletion jose-jwt/json/JsonMapper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NETSTANDARD2_1
#if NETSTANDARD2_1 || NET
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
Expand Down
4 changes: 2 additions & 2 deletions jose-jwt/jwa/EcdhKeyManagementUnix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Jose
{
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
public class EcdhKeyManagementUnix : IKeyManagement
{
private readonly string algIdHeader;
Expand Down Expand Up @@ -79,7 +79,7 @@ public virtual byte[] Unwrap(byte[] encryptedCek, object key, int cekSizeBits, I
{
privateKey = jwk.EcDiffieHellmanKey();
}
}
}
else if (key is ECDsa ecdsa)
{
privateKey = EcdhKey.FromPrivate(ecdsa);
Expand Down
6 changes: 4 additions & 2 deletions jose-jwt/jwa/EcdhKeyManagementWin.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Collections.Generic;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using Jose.keys;

namespace Jose
{
[SupportedOSPlatform("windows")]
public class EcdhKeyManagementWin : IKeyManagement
{
private readonly IKeyManagement ecdhKeyManagementUnix;
Expand All @@ -18,7 +20,7 @@ public EcdhKeyManagementWin(bool isDirectAgreement, IKeyManagement ecdhKeyManage

public virtual byte[][] WrapNewKey(int cekSizeBits, object key, IDictionary<string, object> header)
{
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
if (key is ECDiffieHellman || key is ECDsa || key is Jwk)
{
return ecdhKeyManagementUnix.WrapNewKey(cekSizeBits, key, header);
Expand Down Expand Up @@ -69,7 +71,7 @@ public virtual byte[] Wrap(byte[] cek, object key)

public virtual byte[] Unwrap(byte[] encryptedCek, object key, int cekSizeBits, IDictionary<string, object> header)
{
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
if (key is ECDiffieHellman || key is ECDsa || key is Jwk)
{
return ecdhKeyManagementUnix.Unwrap(encryptedCek, key, cekSizeBits, header);
Expand Down
8 changes: 5 additions & 3 deletions jose-jwt/jwa/EcdhKeyManagementWinWithAesKeyWrap.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
using System.Security.Cryptography;

namespace Jose
{
[SupportedOSPlatform("windows")]
public class EcdhKeyManagementWinWithAesKeyWrap : EcdhKeyManagementWin
{
private readonly AesKeyWrapManagement aesKW;
Expand All @@ -19,7 +21,7 @@ public EcdhKeyManagementWinWithAesKeyWrap(int keyLengthBits, AesKeyWrapManagemen

public override byte[][] WrapNewKey(int cekSizeBits, object key, IDictionary<string, object> header)
{
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
if (key is ECDiffieHellman || key is ECDsa || key is Jwk)
{
return ecdhKeyManagementUnixWithAesKeyWrap.WrapNewKey(cekSizeBits, key, header);
Expand All @@ -32,7 +34,7 @@ public override byte[][] WrapNewKey(int cekSizeBits, object key, IDictionary<str

public override byte[] WrapKey(byte[] cek, object key, IDictionary<string, object> header)
{
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
if (key is ECDiffieHellman || key is ECDsa || key is Jwk)
{
return ecdhKeyManagementUnixWithAesKeyWrap.WrapKey(cek, key, header);
Expand All @@ -47,7 +49,7 @@ public override byte[] WrapKey(byte[] cek, object key, IDictionary<string, objec

public override byte[] Unwrap(byte[] encryptedCek, object key, int cekSizeBits, IDictionary<string, object> header)
{
#if NET472 || NETSTANDARD2_1
#if NET472 || NETSTANDARD2_1 || NET
if (key is ECDiffieHellman || key is ECDsa || key is Jwk)
{
return ecdhKeyManagementUnixWithAesKeyWrap.Unwrap(encryptedCek, key, cekSizeBits, header);
Expand Down
Loading
Loading