diff --git a/dotnet/DotNetStandardClasses.sln b/dotnet/DotNetStandardClasses.sln
index 01e391f0b..ee757432f 100644
--- a/dotnet/DotNetStandardClasses.sln
+++ b/dotnet/DotNetStandardClasses.sln
@@ -263,6 +263,28 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogTest", "test\benchmarks\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccessTokenController_Test", "test\NativeAccessControllerTest\AccessTokenController_Test.csproj", "{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gam", "gam", "{BAD7F078-C67E-484A-AF74-EC29F163F1F7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7465132B-47BD-44D1-8193-483465FD94F4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{035C3DAF-553E-4E64-BA9E-113F5C80FD97}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DotNet", "DotNet", "{56429994-8A51-48AB-8105-737B77840D18}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DotNetFramework", "DotNetFramework", "{B3B988A2-AFF1-41E6-82DC-578D332A5CB8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GamUtils", "src\extensions\gam\src\DotNetFramework\GamUtils\GamUtils.csproj", "{34FE57F2-E45F-4F9B-AFEE-60D9CA8373A7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DotNet", "DotNet", "{1942B0FE-49BD-4EC4-9788-F19FDD921E69}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DotNetFramework", "DotNetFramework", "{B33F3709-5EA0-4FE8-9E3A-50D3046817D6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GamTest", "src\extensions\gam\test\DotNetFramework\GamTest\GamTest.csproj", "{52B67EA3-B17D-4002-8EC3-0D5DDB62988B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GamUtilsNet", "src\extensions\gam\src\DotNet\GamUtilsNet\GamUtilsNet.csproj", "{AA93273B-2E0B-4CD3-A921-A462B214F424}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GamTestNet", "src\extensions\gam\test\DotNet\GamTestNet\GamTestNet.csproj", "{D46D0666-AF65-4875-954C-82AB2240B17D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -641,6 +663,22 @@ Global
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {34FE57F2-E45F-4F9B-AFEE-60D9CA8373A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {34FE57F2-E45F-4F9B-AFEE-60D9CA8373A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {34FE57F2-E45F-4F9B-AFEE-60D9CA8373A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {34FE57F2-E45F-4F9B-AFEE-60D9CA8373A7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {52B67EA3-B17D-4002-8EC3-0D5DDB62988B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {52B67EA3-B17D-4002-8EC3-0D5DDB62988B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {52B67EA3-B17D-4002-8EC3-0D5DDB62988B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {52B67EA3-B17D-4002-8EC3-0D5DDB62988B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AA93273B-2E0B-4CD3-A921-A462B214F424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA93273B-2E0B-4CD3-A921-A462B214F424}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AA93273B-2E0B-4CD3-A921-A462B214F424}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AA93273B-2E0B-4CD3-A921-A462B214F424}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D46D0666-AF65-4875-954C-82AB2240B17D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D46D0666-AF65-4875-954C-82AB2240B17D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D46D0666-AF65-4875-954C-82AB2240B17D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D46D0666-AF65-4875-954C-82AB2240B17D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -767,6 +805,17 @@ Global
{46DAAFD1-FAF5-4904-8EC5-406BE04E5538} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
{A1DBDCE0-4F09-445F-A202-9B260CDD46CF} = {46DAAFD1-FAF5-4904-8EC5-406BE04E5538}
{A5589382-DB6F-4450-AE2B-6C6AA1643EF1} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC}
+ {BAD7F078-C67E-484A-AF74-EC29F163F1F7} = {C6AFB6A3-FF0B-4970-B1F1-10BCD3D932B2}
+ {7465132B-47BD-44D1-8193-483465FD94F4} = {BAD7F078-C67E-484A-AF74-EC29F163F1F7}
+ {035C3DAF-553E-4E64-BA9E-113F5C80FD97} = {BAD7F078-C67E-484A-AF74-EC29F163F1F7}
+ {56429994-8A51-48AB-8105-737B77840D18} = {7465132B-47BD-44D1-8193-483465FD94F4}
+ {B3B988A2-AFF1-41E6-82DC-578D332A5CB8} = {7465132B-47BD-44D1-8193-483465FD94F4}
+ {34FE57F2-E45F-4F9B-AFEE-60D9CA8373A7} = {B3B988A2-AFF1-41E6-82DC-578D332A5CB8}
+ {1942B0FE-49BD-4EC4-9788-F19FDD921E69} = {035C3DAF-553E-4E64-BA9E-113F5C80FD97}
+ {B33F3709-5EA0-4FE8-9E3A-50D3046817D6} = {035C3DAF-553E-4E64-BA9E-113F5C80FD97}
+ {52B67EA3-B17D-4002-8EC3-0D5DDB62988B} = {B33F3709-5EA0-4FE8-9E3A-50D3046817D6}
+ {AA93273B-2E0B-4CD3-A921-A462B214F424} = {56429994-8A51-48AB-8105-737B77840D18}
+ {D46D0666-AF65-4875-954C-82AB2240B17D} = {1942B0FE-49BD-4EC4-9788-F19FDD921E69}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E18684C9-7D76-45CD-BF24-E3944B7F174C}
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusCryptographyNetCore/GeneXusCryptographyNetCore.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusCryptographyNetCore/GeneXusCryptographyNetCore.csproj
index 174ed6a9a..23ce5bf84 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusCryptographyNetCore/GeneXusCryptographyNetCore.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusCryptographyNetCore/GeneXusCryptographyNetCore.csproj
@@ -68,7 +68,7 @@
-
+
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusJWTNetCore/GeneXusJWTNetCore.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusJWTNetCore/GeneXusJWTNetCore.csproj
index 96047c388..60adc91d7 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusJWTNetCore/GeneXusJWTNetCore.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusJWTNetCore/GeneXusJWTNetCore.csproj
@@ -33,7 +33,7 @@
-
+
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusXmlSignatureNetCore/GeneXusXmlSignatureNetCore.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusXmlSignatureNetCore/GeneXusXmlSignatureNetCore.csproj
index 666954743..252a66f4d 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusXmlSignatureNetCore/GeneXusXmlSignatureNetCore.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/GeneXusXmlSignatureNetCore/GeneXusXmlSignatureNetCore.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/SecurityAPICommonsNetCore/SecurityAPICommonsNetCore.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/SecurityAPICommonsNetCore/SecurityAPICommonsNetCore.csproj
index 7bdacca1e..2346a7ad4 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/SecurityAPICommonsNetCore/SecurityAPICommonsNetCore.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetcore/SecurityAPICommonsNetCore/SecurityAPICommonsNetCore.csproj
@@ -34,7 +34,7 @@
-
+
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusCryptography/GeneXusCryptography.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusCryptography/GeneXusCryptography.csproj
index 1d9a763cc..17b58f372 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusCryptography/GeneXusCryptography.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusCryptography/GeneXusCryptography.csproj
@@ -1,4 +1,4 @@
-
+
net47
GeneXusCryptography
@@ -7,7 +7,7 @@
GeneXus.SecurityApi.Cryptography
-
+
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusJWT/GeneXusJWT.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusJWT/GeneXusJWT.csproj
index 2cac667b1..18fa6ecca 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusJWT/GeneXusJWT.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusJWT/GeneXusJWT.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusXmlSignature/GeneXusXmlSignature.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusXmlSignature/GeneXusXmlSignature.csproj
index ea8ad6834..f4fcb3ff5 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusXmlSignature/GeneXusXmlSignature.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/GeneXusXmlSignature/GeneXusXmlSignature.csproj
@@ -7,7 +7,7 @@
GeneXus.SecurityApi.XmlSignature
-
+
diff --git a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/SecurityAPICommons/SecurityAPICommons.csproj b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/SecurityAPICommons/SecurityAPICommons.csproj
index 4a9c504e2..85efd61da 100644
--- a/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/SecurityAPICommons/SecurityAPICommons.csproj
+++ b/dotnet/src/extensions/SecurityAPI/dotnet/dotnetframework/SecurityAPICommons/SecurityAPICommons.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/dotnet/src/extensions/gam/gamkey.snk b/dotnet/src/extensions/gam/gamkey.snk
new file mode 100644
index 000000000..caa9e0fe9
Binary files /dev/null and b/dotnet/src/extensions/gam/gamkey.snk differ
diff --git a/dotnet/src/extensions/gam/src/DotNet/GamUtilsNet/GamUtilsNet.csproj b/dotnet/src/extensions/gam/src/DotNet/GamUtilsNet/GamUtilsNet.csproj
new file mode 100644
index 000000000..dd3d7ecd5
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNet/GamUtilsNet/GamUtilsNet.csproj
@@ -0,0 +1,45 @@
+
+
+
+ net8.0
+ GamUtilsNetImpl
+ 17.4.0
+ CA1031, CA1801, SYSLIB0027
+ Gam.Utils.Net
+
+
+
+ NETCORE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/GamUtils.csproj b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/GamUtils.csproj
new file mode 100644
index 000000000..a3776e3dd
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/GamUtils.csproj
@@ -0,0 +1,27 @@
+
+
+ net47
+ GamUtilsImpl
+ CA1031, CA1801
+ Gam.Utils
+ True
+ ..\..\..\gamkey.snk
+
+
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/GamUtilsEO.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/GamUtilsEO.cs
new file mode 100644
index 000000000..9f3d51428
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/GamUtilsEO.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Security;
+using GamUtils.Utils;
+using GamUtils.Utils.Cryprography;
+using GamUtils.Utils.Json;
+
+namespace GamUtils
+{
+ [SecuritySafeCritical]
+ public class GamUtilsEO
+ {
+ /********EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/
+
+ //**HASH**//
+ [SecuritySafeCritical]
+ public static string Sha512(string plainText)
+ {
+ return HashUtil.Hashing(plainText, Hash.SHA512);
+ }
+
+ [SecuritySafeCritical]
+ public static string Sha256(string plainText)
+ {
+ return HashUtil.Hashing(plainText, Hash.SHA256);
+ }
+
+ //**ENCRYPTION**//
+
+ [SecuritySafeCritical]
+ public static string AesGcm(string input, string key, string nonce, int macSize, bool toEncrypt)
+ {
+ return Encryption.AesGcm(input, key, nonce, macSize, toEncrypt);
+ }
+
+ //**RANDOM**//
+ [SecuritySafeCritical]
+ public static string RandomAlphanumeric(int length)
+ {
+ return Utils.Random.Alphanumeric(length);
+ }
+
+ [SecuritySafeCritical]
+ public static string RandomNumeric(int length)
+ {
+ return Utils.Random.Numeric(length);
+ }
+
+ [SecuritySafeCritical]
+ public static string RandomHexaBits(int bits)
+ {
+ return Utils.Random.HexaBits(bits);
+ }
+
+ //**JWK**//
+ [SecuritySafeCritical]
+ public static string GenerateKeyPair() { return Jwk.GenerateKeyPair(); }
+
+ [SecuritySafeCritical]
+ public static string GetPublicJwk(string jwkString) { return Jwk.GetPublic(jwkString); }
+
+ //**JWT**//
+ [SecuritySafeCritical]
+ public static bool VerifyJwt(string path, string alias, string password, string token) { return Jwt.Verify(path, alias, password, token); }
+
+ [SecuritySafeCritical]
+ public static string CreateJwt(string path, string alias, string password, string payload, string header) { return Jwt.Create(path, alias, password, payload, header); }
+
+ [SecuritySafeCritical]
+ public static long CreateUnixTimestamp(DateTime date) { return UnixTimestamp.Create(date); }
+
+ [SecuritySafeCritical]
+ public static string GetJwtHeader(string token) { return Jwt.GetHeader(token); }
+
+ [SecuritySafeCritical]
+ public static string GetJwtPayload(string token) { return Jwt.GetPayload(token); }
+
+ //**ENCODING**//
+ public static string Base64ToBase64Url(string base64) { return Encoding.B64ToB64Url(base64); }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Properties/AssemblyInfo.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..19c0cf3b9
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Properties/AssemblyInfo.cs
@@ -0,0 +1,5 @@
+using System.Security;
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AllowPartiallyTrustedCallers]
\ No newline at end of file
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Cryprography/Encryption.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Cryprography/Encryption.cs
new file mode 100644
index 000000000..b50517451
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Cryprography/Encryption.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Security;
+using System.Text;
+using log4net;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace GamUtils.Utils.Cryprography
+{
+ [SecuritySafeCritical]
+ internal class Encryption
+ {
+
+ private static readonly ILog logger = LogManager.GetLogger(typeof(Encryption));
+
+ [SecuritySafeCritical]
+ public static string AesGcm(string input, string key, string nonce, int macSize, bool toEncrypt)
+ {
+ return toEncrypt ? Base64.ToBase64String(Internal_AesGcm(System.Text.Encoding.UTF8.GetBytes(input), key, nonce, macSize, toEncrypt)) : System.Text.Encoding.UTF8.GetString(Internal_AesGcm(Base64.Decode(input), key, nonce, macSize, toEncrypt));
+ }
+
+ [SecuritySafeCritical]
+ private static byte[] Internal_AesGcm(byte[] inputBytes, string key, string nonce, int macSize, bool toEncrypt)
+ {
+ logger.Debug("Internal_AesGcm");
+
+ IAeadBlockCipher cipher = new GcmBlockCipher(new AesEngine());
+ AeadParameters AEADparams = new AeadParameters(new KeyParameter(Hex.Decode(key)), macSize, Hex.Decode(nonce));
+ try
+ {
+ cipher.Init(toEncrypt, AEADparams);
+ byte[] outputBytes = new byte[cipher.GetOutputSize(inputBytes.Length)];
+ int length = cipher.ProcessBytes(inputBytes, 0, inputBytes.Length, outputBytes, 0);
+ cipher.DoFinal(outputBytes, length);
+ return outputBytes;
+ }
+ catch (Exception e)
+ {
+ logger.Error("Internal_AesGcm", e);
+ return null;
+ }
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Cryprography/Hash.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Cryprography/Hash.cs
new file mode 100644
index 000000000..6fabc32a0
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Cryprography/Hash.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Text;
+using log4net;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.Encoders;
+using System.Security;
+
+namespace GamUtils.Utils
+{
+ [SecuritySafeCritical]
+ internal enum Hash
+ {
+ NONE, SHA512, SHA256
+ }
+
+ [SecuritySafeCritical]
+ public class HashUtil
+ {
+
+ private static readonly ILog logger = LogManager.GetLogger(typeof(HashUtil));
+
+ [SecuritySafeCritical]
+ internal static string Hashing(string plainText, Hash hash)
+ {
+ switch (hash)
+ {
+ case Hash.SHA256:
+ return InternalHash(new Sha256Digest(), plainText);
+ case Hash.SHA512:
+ return InternalHash(new Sha512Digest(), plainText);
+ default:
+ logger.Error("unrecognized hash");
+ return "";
+ }
+ }
+
+ private static string InternalHash(IDigest digest, string plainText)
+ {
+ logger.Debug("InternalHash");
+ if (String.IsNullOrEmpty(plainText))
+ {
+ logger.Error("hash plainText is empty");
+ return "";
+ }
+ byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
+ byte[] retValue = new byte[digest.GetDigestSize()];
+ digest.BlockUpdate(inputBytes, 0, inputBytes.Length);
+ digest.DoFinal(retValue, 0);
+ return Base64.ToBase64String(retValue);
+ }
+ }
+}
+
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/DynamicCall.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/DynamicCall.cs
new file mode 100644
index 000000000..23041618c
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/DynamicCall.cs
@@ -0,0 +1,207 @@
+using System;
+using System.Text;
+using System.Reflection;
+using System.IO;
+using System.Globalization;
+using GeneXus.Application;
+using log4net;
+
+#if NETCORE
+using GxClasses.Helpers;
+using GeneXus.Utils;
+#endif
+
+namespace GamUtils.Utils
+{
+ public class DynamicCall
+ {
+
+ private IGxContext mGxContext;
+ private static readonly ILog logger = LogManager.GetLogger(typeof(DynamicCall));
+
+ /********EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/
+
+ public DynamicCall(IGxContext context)
+ {
+ mGxContext = context;
+ }
+
+ public bool Execute(string assembly, string typeName, bool useContext, string method, string jsonParms, out string jsonOutput)
+ {
+ logger.Debug("Execute");
+ return DoCall(assembly, typeName, useContext, method, false, "", jsonParms, out jsonOutput);
+ }
+
+ public bool ExecuteEventHandler(string assembly, string typeName, bool useContext, string method, string eventType, string jsonInput, out string jsonOutput)
+ {
+ logger.Debug("ExecuteEventHandler");
+ return DoCall(assembly, typeName, useContext, method, true, eventType, jsonInput, out jsonOutput);
+ }
+
+
+ /********EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/
+
+
+ private bool DoCall(string assembly, string typeName, bool useContext, string method, bool isEventHandler, string input1, string input2, out string jsonOutput)
+ {
+ logger.Debug("DoCall");
+ try
+ {
+ jsonOutput = "{}";
+ Assembly assm;
+ if (Path.IsPathRooted(assembly))
+ assm = Assembly.LoadFrom(assembly);
+ else
+ assm = Assembly.LoadFrom(Path.Combine(GetStartupDirectory(), assembly));
+
+ if (assm != null)
+ {
+ Type type = assm.GetType(typeName);
+ if (type != null)
+ {
+ object instance = null;
+ if (useContext && (mGxContext != null))
+ {
+ ConstructorInfo constructorWithContext = type.GetConstructor(new Type[] { typeof(IGxContext) });
+ if (constructorWithContext != null)
+ {
+ instance = constructorWithContext.Invoke(new object[] { mGxContext });
+ }
+ }
+ if (instance == null)
+ instance = assm.CreateInstance(typeName);
+
+ if (instance != null)
+ {
+ MethodInfo methodInfo;
+ object[] parameters;
+
+ if (isEventHandler)
+ {
+ methodInfo = instance.GetType().GetMethod(method, new Type[] { input1.GetType(), input2.GetType(), jsonOutput.GetType().MakeByRefType() });
+ parameters = new object[] { input1, input2, jsonOutput };
+ }
+ else
+ {
+ methodInfo = instance.GetType().GetMethod(method, new Type[] { input2.GetType(), jsonOutput.GetType().MakeByRefType() });
+ parameters = new object[] { input2, jsonOutput };
+ }
+
+ if (methodInfo != null)
+ {
+ object result = methodInfo.Invoke(instance, parameters);
+ if (methodInfo.ReturnType == typeof(void) && (parameters.Length > 0))
+ jsonOutput = (string)parameters[parameters.Length - 1];
+ else
+ jsonOutput = result.ToString();
+
+ return true;
+ }
+ else
+ {
+ logger.Error("error: " + method + "(String, out String)" + " in " + assembly + " not found");
+ jsonOutput = "{\"error\":\"" + method + "(String, out String)" + " in " + assembly + " not found" + "\"}";
+ return false;
+ }
+ }
+ else
+ {
+ logger.Error("error: " + "constructor for " + typeName + " in " + assembly + " not found");
+ jsonOutput = "{\"error\":\"" + "constructor for " + typeName + " in " + assembly + " not found" + "\"}";
+ return false;
+ }
+ }
+ else
+ {
+ logger.Error("error: " + typeName + " in " + assembly + " not found");
+ jsonOutput = "{\"error\":\"" + typeName + " in " + assembly + " not found" + "\"}";
+ return false;
+ }
+ }
+ else
+ {
+ logger.Error("error: " + assembly + " not found");
+ jsonOutput = "{\"error\":\"" + assembly + " not found" + "\"}";
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ StringBuilder str = new StringBuilder();
+ str.Append(ex.Message);
+ while (ex.InnerException != null)
+ {
+ str.Append(ex.InnerException.Message);
+ ex = ex.InnerException;
+ }
+ logger.Error("error: " + Enquote(str.ToString()));
+ jsonOutput = "{\"error\":" + Enquote(str.ToString()) + "}";
+ return false;
+ }
+ }
+
+ private static string GetStartupDirectory()
+ {
+ logger.Debug("GetStartupDirectory");
+#if NETCORE
+ return FileUtil.GetStartupDirectory();
+#else
+ string dir = Path.GetDirectoryName(Assembly.GetCallingAssembly().GetName().CodeBase); ;
+ if (dir.StartsWith("file:\\"))
+ dir = dir.Substring(6);
+ return dir;
+#endif
+ }
+
+
+ private static string Enquote(string s)
+ {
+ logger.Debug("Enquote)");
+ if (s == null || s.Length == 0)
+ return "\"\"";
+
+ int length = s.Length;
+ StringBuilder sb = new StringBuilder(length + 4);
+
+ sb.Append('"');
+
+ for (int index = 0; index < length; index++)
+ {
+ char ch = s[index];
+
+ if ((ch == '\\') || (ch == '"') || (ch == '>'))
+ {
+ sb.Append('\\');
+ sb.Append(ch);
+ }
+ else if (ch == '\b')
+ sb.Append("\\b");
+ else if (ch == '\t')
+ sb.Append("\\t");
+ else if (ch == '\n')
+ sb.Append("\\n");
+ else if (ch == '\f')
+ sb.Append("\\f");
+ else if (ch == '\r')
+ sb.Append("\\r");
+ else
+ {
+ if (ch < ' ')
+ {
+ //t = "000" + Integer.toHexString(c);
+ //string tmp = new string(ch, 1);
+ string t = "000" + ((int)ch).ToString(CultureInfo.InvariantCulture);
+ sb.Append("\\u" + t.Substring(t.Length - 4));
+ }
+ else
+ {
+ sb.Append(ch);
+ }
+ }
+ }
+
+ sb.Append('"');
+ return sb.ToString();
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Encoding.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Encoding.cs
new file mode 100644
index 000000000..3dc97497e
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Encoding.cs
@@ -0,0 +1,28 @@
+using System;
+using Org.BouncyCastle.Utilities.Encoders;
+using log4net;
+using System.Security;
+
+namespace GamUtils.Utils
+{
+ [SecuritySafeCritical]
+ internal class Encoding
+ {
+ private static readonly ILog logger = LogManager.GetLogger(typeof(Encoding));
+
+ [SecuritySafeCritical]
+ internal static string B64ToB64Url(string input)
+ {
+ logger.Debug("B64ToB64Url");
+ try
+ {
+ return System.Text.Encoding.UTF8.GetString(UrlBase64.Encode(Base64.Decode(input)));
+ }
+ catch (Exception e)
+ {
+ logger.Error("B64ToB64Url", e);
+ return "";
+ }
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/Jwk.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/Jwk.cs
new file mode 100644
index 000000000..c7491a00f
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/Jwk.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Security;
+using log4net;
+using Newtonsoft.Json;
+
+namespace GamUtils.Utils.Json
+{
+ [SecuritySafeCritical]
+ public class Jwk
+ {
+ private static readonly ILog logger = LogManager.GetLogger(typeof(Jwk));
+
+ /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/
+
+ [SecuritySafeCritical]
+ internal static string GenerateKeyPair()
+ {
+ Jose.Jwk jwk = CreateJwk();
+ if (jwk == null) { return ""; }
+ return jwk.ToJson();
+ }
+
+
+ [SecuritySafeCritical]
+ internal static string GetPublic(string jwkString)
+ {
+ if (string.IsNullOrEmpty(jwkString))
+ {
+ logger.Error("GetPublicJwk jwkString parameter is empty");
+ return "";
+ }
+ else
+ {
+ logger.Debug("GetPublicJwk jwkString parameter: " + jwkString);
+ }
+ try
+ {
+ Jose.Jwk jwk = Jose.Jwk.FromJson(jwkString);
+ var dict = new Dictionary
+ {
+ ["kty"] = jwk.Kty,
+ ["e"] = jwk.E,
+ ["use"] = jwk.Use,
+ ["kid"] = jwk.KeyId,
+ ["alg"] = jwk.Alg,
+ ["n"] = jwk.N,
+ };
+
+ return JsonConvert.SerializeObject(dict);
+ }
+ catch (Exception e)
+ {
+ logger.Error("GetPublicJwk", e);
+ return "";
+ }
+ }
+
+ /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/
+
+ [SecuritySafeCritical]
+ private static Jose.Jwk CreateJwk()
+ {
+ try
+ {
+ RSA key = Create(2048);
+
+ RSAParameters parameters = key.ExportParameters(true);
+ Jose.Jwk jwk = new Jose.Jwk
+ {
+ Kty = "RSA",
+ Alg = "RS256",
+ Use = "sig",
+ KeyId = Guid.NewGuid().ToString(),
+ N = Convert.ToBase64String(parameters.Modulus),
+ E = Convert.ToBase64String(parameters.Exponent),
+ P = Convert.ToBase64String(parameters.P),
+ Q = Convert.ToBase64String(parameters.Q),
+ DP = Convert.ToBase64String(parameters.DP),
+ DQ = Convert.ToBase64String(parameters.DQ),
+ QI = Convert.ToBase64String(parameters.InverseQ),
+ D = Convert.ToBase64String(parameters.D)
+ };
+
+ return jwk;
+
+ }
+ catch (Exception e)
+ {
+ logger.Error("CreateJwk", e);
+ return null;
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static RSA Create(int keySizeInBits)
+ {
+#if NETCORE
+ RSA rSA = RSA.Create();
+#else
+ RSA rSA = (RSA)CryptoConfig.CreateFromName("RSAPSS");
+#endif
+ rSA.KeySize = keySizeInBits;
+ if (rSA.KeySize != keySizeInBits)
+ {
+ throw new CryptographicException();
+ }
+
+ return rSA;
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/Jwt.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/Jwt.cs
new file mode 100644
index 000000000..e7671bf25
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/Jwt.cs
@@ -0,0 +1,126 @@
+using System;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security;
+using System.Security.Cryptography;
+using GamUtils.Utils.Keys;
+using Jose;
+using log4net;
+using Microsoft.IdentityModel.Tokens;
+
+namespace GamUtils.Utils
+{
+ [SecuritySafeCritical]
+ public class Jwt
+ {
+ private static readonly ILog logger = LogManager.GetLogger(typeof(Jwt));
+
+ /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/
+
+ [SecuritySafeCritical]
+ public static bool Verify(string path, string alias, string password, string token)
+ {
+ logger.Debug("Verify");
+ try
+ {
+ return Verify(PublicKeyUtil.GetPublicKey(path, alias, password, token), token);
+ }catch(Exception e)
+ {
+ logger.Error("Verify", e);
+ return false;
+ }
+ }
+
+ [SecuritySafeCritical]
+ public static string Create(string path, string alias, string password, string payload, string header)
+ {
+ logger.Debug("Create");
+ try
+ {
+ return Create(PrivateKeyUtil.GetPrivateKey(path, alias, password), payload, header);
+ }catch(Exception e)
+ {
+ logger.Error("Create", e);
+ return "";
+ }
+ }
+
+ [SecuritySafeCritical]
+ public static string GetHeader(string token)
+ {
+ logger.Debug("GetHeader");
+ return GetParts(token, 0);
+ }
+
+ [SecuritySafeCritical]
+ public static string GetPayload(string token)
+ {
+ logger.Debug("GetPayload");
+ return GetParts(token, 1);
+ }
+
+ /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/
+
+ private static string GetParts(string token, int part)
+ {
+ logger.Debug("GetParts");
+ try
+ {
+ string[] parts = token.Split('.');
+ return System.Text.Encoding.UTF8.GetString(Base64Url.Decode(parts[part]));
+ }
+ catch (Exception e)
+ {
+ logger.Error("GetParts", e);
+ return "";
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static bool Verify(RSAParameters publicKey, string token)
+ {
+ try
+ {
+ using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
+ {
+ rsa.ImportParameters(publicKey);
+ string payload = JWT.Decode(token, rsa, JwsAlgorithm.RS256);
+ return payload.IsNullOrEmpty() ? false : true;
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Error("verify", e);
+ return false;
+ }
+ }
+
+
+ [SecuritySafeCritical]
+ private static string Create(RSAParameters privateKey, string payload, string header)
+ {
+ try
+ {
+ using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
+ {
+ rsa.ImportParameters(privateKey);
+
+ return JWT.Encode(
+ payload: payload,
+ key: rsa,
+ algorithm: JwsAlgorithm.RS256,
+ extraHeaders: JwtHeader.Deserialize(header),
+ options: new JwtOptions { DetachPayload = false, EncodePayload = true }
+ );
+ }
+
+ }
+ catch (Exception e)
+ {
+ logger.Error("create", e);
+ return "";
+ }
+ }
+
+
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/UnixTimestamp.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/UnixTimestamp.cs
new file mode 100644
index 000000000..f33847814
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Json/UnixTimestamp.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Globalization;
+using System.Security;
+
+namespace GamUtils.Utils.Json
+{
+ [SecuritySafeCritical]
+ internal class UnixTimestamp
+ {
+ [SecuritySafeCritical]
+ internal static long Create(DateTime gxdate)
+ {
+ return (long)gxdate.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Keys/PrivateKeyExt.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Keys/PrivateKeyExt.cs
new file mode 100644
index 000000000..546ff7494
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Keys/PrivateKeyExt.cs
@@ -0,0 +1,290 @@
+using System;
+using System.IO;
+using System.Security;
+using System.Security.Cryptography;
+using log4net;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Microsoft.IdentityModel.Tokens;
+using System.Runtime.InteropServices;
+using Jose;
+
+namespace GamUtils.Utils.Keys
+{
+ [SecuritySafeCritical]
+ internal enum PrivateKeyExt
+ {
+ NONE, pfx, pkcs12, p12, pem, key, b64, json
+ }
+
+ [SecuritySafeCritical]
+ internal static class PrivateKeyUtil
+ {
+ private static readonly ILog logger = LogManager.GetLogger(typeof(PrivateKeyUtil));
+
+
+ [SecuritySafeCritical]
+ internal static RSAParameters GetPrivateKey(string path, string alias, string password)
+ {
+ PrivateKeyExt ext = PrivateKeyUtil.Value(FixType(path));
+ if (ext == PrivateKeyExt.NONE)
+ {
+ logger.Error("Error reading certificate path");
+ return new RSAParameters();
+ }
+ switch (ext)
+ {
+ case PrivateKeyExt.pfx:
+ case PrivateKeyExt.pkcs12:
+ case PrivateKeyExt.p12:
+ return GetPrivateRSAParameters(LoadFromPkcs12(path, alias, password));
+ case PrivateKeyExt.pem:
+ case PrivateKeyExt.key:
+ return GetPrivateRSAParameters(LoadFromPkcs8(path));
+ case PrivateKeyExt.b64:
+ return GetPrivateRSAParameters(LoadFromBase64(path));
+ case PrivateKeyExt.json:
+ return LoadFromJson(path);
+ default:
+ logger.Error("Invalid certificate file extension");
+ return new RSAParameters();
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static RSAParameters LoadFromJson(string json)
+ {
+ logger.Debug("LoadFromJson");
+ RSAParameters privateKey = new RSAParameters();
+ try
+ {
+ Jwk jwk = Jwk.FromJson(json);
+ privateKey.Exponent = Base64Url.Decode(jwk.E);
+ privateKey.Modulus = Base64Url.Decode(jwk.N);
+ privateKey.D = Base64Url.Decode(jwk.D);
+ privateKey.DP = Base64Url.Decode(jwk.DP);
+ privateKey.DQ = Base64Url.Decode(jwk.DQ);
+ privateKey.P = Base64Url.Decode(jwk.P);
+ privateKey.Q = Base64Url.Decode(jwk.Q);
+ privateKey.InverseQ = Base64Url.Decode(jwk.QI);
+
+ }
+ catch (Exception e)
+ {
+ logger.Error("LoadFromJson", e);
+ }
+ return privateKey;
+ }
+
+ private static string FixType(string input)
+ {
+ try
+ {
+ string extension = Path.GetExtension(input).Replace(".", string.Empty).Trim();
+#if !NETCORE
+ return extension.IsNullOrEmpty() ? "b64" : extension;
+#else
+ if (extension.IsNullOrEmpty())
+ {
+ try
+ {
+ Base64.Decode(input);
+ return "b64";
+ }
+ catch (Exception)
+ {
+ return "json";
+ }
+ }
+ else
+ {
+ return extension;
+ }
+#endif
+ }
+ catch (ArgumentException)
+ {
+ return "json";
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static PrivateKeyExt Value(string ext)
+ {
+ switch (ext.ToLower().Trim())
+ {
+ case "pfx":
+ return PrivateKeyExt.pfx;
+ case "pkcs12":
+ return PrivateKeyExt.pkcs12;
+ case "p12":
+ return PrivateKeyExt.p12;
+ case "pem":
+ return PrivateKeyExt.pem;
+ case "key":
+ return PrivateKeyExt.key;
+ case "b64":
+ return PrivateKeyExt.b64;
+ case "json":
+ return PrivateKeyExt.json;
+ default:
+ logger.Error("Invalid certificate file extension");
+ return PrivateKeyExt.NONE;
+ }
+ }
+
+ private static PrivateKeyInfo LoadFromBase64(string base64)
+ {
+ logger.Debug("LoadFromBase64");
+ byte[] keybytes = Base64.Decode(base64);
+ using (Asn1InputStream istream = new Asn1InputStream(keybytes))
+ {
+ Asn1Sequence seq = (Asn1Sequence)istream.ReadObject();
+ return PrivateKeyInfo.GetInstance(seq);
+ }
+ }
+
+ private static RSAParameters GetPrivateRSAParameters(PrivateKeyInfo privateKeyInfo)
+ {
+ logger.Debug("GetPrivateRSAParameters");
+ byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetDerEncoded();
+ string serializedPrivate = Convert.ToBase64String(serializedPrivateBytes);
+ RsaPrivateCrtKeyParameters privateKey = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(serializedPrivate));
+
+#if NETCORE
+
+if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+{
+try
+ {
+ RSA rsa = RSA.Create();
+ rsa.ImportPkcs8PrivateKey(serializedPrivateBytes, out int outthing);
+ return rsa.ExportParameters(true);
+ }catch(Exception e )
+ {
+ logger.Error("CastPrivateKeyInfo", e);
+ return new RSAParameters();
+ }
+}
+#endif
+ return DotNetUtilities.ToRSA(privateKey).ExportParameters(true);
+
+ }
+
+ private static PrivateKeyInfo LoadFromPkcs8(string path)
+ {
+ logger.Debug("LoadFromPkcs8");
+ using (StreamReader streamReader = new StreamReader(path))
+ {
+ Org.BouncyCastle.OpenSsl.PemReader pemReader = null;
+ try
+ {
+ pemReader = new Org.BouncyCastle.OpenSsl.PemReader(streamReader);
+ Object obj = pemReader.ReadObject();
+ if (obj.GetType() == typeof(RsaPrivateCrtKeyParameters))
+ {
+
+ AsymmetricKeyParameter asymKeyParm = (AsymmetricKeyParameter)obj;
+ return CreatePrivateKeyInfo(asymKeyParm);
+
+ }
+ else if (obj.GetType() == typeof(AsymmetricCipherKeyPair))
+ {
+ AsymmetricCipherKeyPair asymKeyPair = (AsymmetricCipherKeyPair)obj;
+ return PrivateKeyInfoFactory.CreatePrivateKeyInfo(asymKeyPair.Private);
+ }
+ else
+ {
+ logger.Error("loadFromPkcs8: Could not load private key");
+ return null;
+ }
+ }catch(Exception e)
+ {
+ logger.Error("LoadFromPkcs8", e);
+ return null;
+ }finally
+ {
+ pemReader.Reader.Close();
+ }
+
+ }
+ }
+ private static PrivateKeyInfo LoadFromPkcs12(string path, string alias, string password)
+ {
+ logger.Debug("LoadFromPkcs12");
+ try
+ {
+ Pkcs12Store pkcs12 = new Pkcs12StoreBuilder().Build();
+ using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
+ {
+ pkcs12.Load(fs, password.ToCharArray());
+ foreach (string n in pkcs12.Aliases)
+ {
+ if (pkcs12.IsKeyEntry(n) && pkcs12.GetKey(n).Key.IsPrivate)
+ {
+ return PrivateKeyInfoFactory.CreatePrivateKeyInfo(pkcs12.GetKey(n).Key);
+ }
+ }
+ }
+ }catch (Exception e)
+ {
+ logger.Error("LoadFromPkcs12", e);
+ return null;
+ }
+ logger.Error("LoadFromPkcs12: path not found");
+ return null;
+
+ }
+
+ private static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter key)
+ {
+ logger.Debug("CreatePrivateKeyInfo");
+ if (key is RsaKeyParameters)
+ {
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance);
+
+ RsaPrivateKeyStructure keyStruct;
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key;
+
+ keyStruct = new RsaPrivateKeyStructure(
+ _key.Modulus,
+ _key.PublicExponent,
+ _key.Exponent,
+ _key.P,
+ _key.Q,
+ _key.DP,
+ _key.DQ,
+ _key.QInv);
+ }
+ else
+ {
+ RsaKeyParameters _key = (RsaKeyParameters)key;
+
+ keyStruct = new RsaPrivateKeyStructure(
+ _key.Modulus,
+ BigInteger.Zero,
+ _key.Exponent,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero);
+ }
+
+ return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object());
+ }
+ logger.Error("CreatePrivateKeyInfo");
+ throw new ArgumentNullException("Class provided is not convertible: " + key.GetType().FullName);
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Keys/PublicKeyExt.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Keys/PublicKeyExt.cs
new file mode 100644
index 000000000..141848d67
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Keys/PublicKeyExt.cs
@@ -0,0 +1,299 @@
+using System;
+using System.IO;
+using System.Security;
+using log4net;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.Pkcs;
+using Microsoft.IdentityModel.Tokens;
+using Org.BouncyCastle.Security;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography;
+using Org.BouncyCastle.Utilities.Encoders;
+using Jose;
+using System.Collections.Generic;
+
+namespace GamUtils.Utils.Keys
+{
+ [SecuritySafeCritical]
+ internal enum PublicKeyExt
+ {
+ NONE, crt, cer, pfx, pkcs12, p12, pem, key, b64, json
+ }
+
+
+ [SecuritySafeCritical]
+ internal static class PublicKeyUtil
+ {
+ private static readonly ILog logger = LogManager.GetLogger(typeof(PublicKeyUtil));
+
+
+
+ [SecuritySafeCritical]
+ internal static RSAParameters GetPublicKey(string path, string alias, string password, string token)
+ {
+ logger.Debug("GetPublicKey");
+ PublicKeyExt ext = PublicKeyUtil.Value(FixType(path));
+ switch (ext)
+ {
+ case PublicKeyExt.crt:
+ case PublicKeyExt.cer:
+ return GetPublicRSAParameters(LoadFromDer(path));
+ case PublicKeyExt.pfx:
+ case PublicKeyExt.pkcs12:
+ case PublicKeyExt.p12:
+ return GetPublicRSAParameters(LoadFromPkcs12(path, alias, password));
+ case PublicKeyExt.pem:
+ case PublicKeyExt.key:
+ return GetPublicRSAParameters(LoadFromPkcs8(path));
+ case PublicKeyExt.b64:
+ return GetPublicRSAParameters(LoadFromBase64(path));
+ case PublicKeyExt.json:
+ return LoadFromJson(path, token);
+ default:
+ logger.Error("Invalid certificate file extension");
+ return new RSAParameters();
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static PublicKeyExt Value(string ext)
+ {
+ switch (ext.ToLower().Trim())
+ {
+ case "crt":
+ return PublicKeyExt.crt;
+ case "cer":
+ return PublicKeyExt.cer;
+ case "pfx":
+ return PublicKeyExt.pfx;
+ case "pkcs12":
+ return PublicKeyExt.pkcs12;
+ case "p12":
+ return PublicKeyExt.p12;
+ case "pem":
+ return PublicKeyExt.pem;
+ case "key":
+ return PublicKeyExt.key;
+ case "b64":
+ return PublicKeyExt.b64;
+ case "json":
+ return PublicKeyExt.json;
+ default:
+ logger.Error("Invalid certificate file extension");
+ return PublicKeyExt.NONE;
+ }
+ }
+
+ private static RSAParameters LoadFromJson(string json, string token)
+ {
+ logger.Debug("LoadFromJson");
+ RSAParameters publicKey = new RSAParameters();
+ try
+ {
+ Jwk jwk = Jwk.FromJson(json);
+#if !NETCORE
+ publicKey.Exponent = Base64Url.Decode(jwk.E);
+ publicKey.Modulus = Base64Url.Decode(jwk.N);
+ return publicKey;
+#else
+ if(jwk.E == null)
+ {
+ return LoadFromJwks(json, token);
+ }
+ else
+ {
+ publicKey.Exponent = Base64Url.Decode(jwk.E);
+ publicKey.Modulus = Base64Url.Decode(jwk.N);
+ return publicKey;
+ }
+#endif
+ }
+ catch(Exception)
+ {
+
+ return LoadFromJwks(json, token);
+ }
+
+ }
+
+ private static RSAParameters LoadFromJwks(string json, string token)
+ {
+ logger.Debug("LoadFromJwks");
+ RSAParameters publicKey = new RSAParameters();
+ try
+ {
+ JwkSet jwks = JwkSet.FromJson(json);
+ IDictionary headers = JWT.Headers(token);
+ string kid = headers["kid"];
+ foreach (Jwk jwk in jwks)
+ {
+ if (jwk.KeyId.Equals(kid))
+ {
+ publicKey.Exponent = Base64Url.Decode(jwk.E);
+ publicKey.Modulus = Base64Url.Decode(jwk.N);
+ }
+ }
+ logger.Error("No matching token kid to jwks");
+ }
+ catch(Exception e)
+ {
+ logger.Error("LoadFromJwks", e);
+ }
+ return publicKey;
+ }
+
+
+ private static string FixType(string input)
+ {
+ try
+ {
+ string extension = Path.GetExtension(input).Replace(".", string.Empty).Trim();
+#if !NETCORE
+ return extension.IsNullOrEmpty() ? "b64" : extension;
+#else
+ if (extension.IsNullOrEmpty())
+ {
+ try
+ {
+ Base64.Decode(input);
+ return "b64";
+ }
+ catch (Exception)
+ {
+ return "json";
+ }
+ }
+ else
+ {
+ return extension;
+ }
+#endif
+ }
+ catch (ArgumentException)
+ {
+ return "json";
+ }
+ }
+
+ private static Org.BouncyCastle.X509.X509Certificate LoadFromBase64(string base64)
+ {
+ logger.Debug("LoadFromBase64");
+ try
+ {
+ return new X509CertificateParser().ReadCertificate(Base64.Decode(base64));
+
+ }
+ catch (Exception e)
+ {
+ logger.Error("LoadFromBase64", e);
+ Console.WriteLine("error LoadFromBase64");
+ return null;
+ }
+ }
+
+ private static RSAParameters GetPublicRSAParameters(Org.BouncyCastle.X509.X509Certificate cert)
+ {
+ logger.Debug("GetPublicRSAParameters");
+ try
+ {
+ X509Certificate2 cert2 = new X509Certificate2(DotNetUtilities.ToX509Certificate(cert));
+ Console.WriteLine("GetPublicRSAParameters" + cert2.GetSerialNumberString());
+ return cert2.GetRSAPublicKey().ExportParameters(false);
+ }catch(Exception e)
+ {
+ logger.Error("GetPublicRSAParameters", e);
+ return new RSAParameters();
+ }
+ }
+
+ private static Org.BouncyCastle.X509.X509Certificate LoadFromPkcs12(string path, string alias, string password)
+ {
+ logger.Debug("LoadFromPkcs12");
+ if (password.IsNullOrEmpty())
+ {
+ logger.Error("LoadFromPkcs12: password is null or empty");
+ return null;
+ }
+
+ try
+ {
+ Pkcs12Store pkcs12 = new Pkcs12StoreBuilder().Build();
+ using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
+ {
+ pkcs12.Load(fs, password.ToCharArray());
+ foreach (string n in pkcs12.Aliases)
+ {
+ if (pkcs12.IsKeyEntry(n))
+ {
+ return pkcs12.GetCertificate(n).Certificate;
+ }
+ }
+ }
+
+
+ }
+
+ catch (Exception e)
+ {
+ logger.Error("LoadFromPkcs12", e);
+ return null;
+ }
+ logger.Error("LoadFromPkcs12: path not found");
+ return null;
+
+ }
+ private static Org.BouncyCastle.X509.X509Certificate LoadFromPkcs8(string path)
+ {
+ logger.Debug("LoadFromPkcs8");
+ using (StreamReader streamReader = new StreamReader(path))
+ {
+ PemReader pemReader = null;
+ try
+ {
+ pemReader = new PemReader(streamReader);
+ object obj = pemReader.ReadObject();
+
+ if (obj.GetType() == typeof(System.Security.Cryptography.X509Certificates.X509Certificate) || obj.GetType() == typeof(Org.BouncyCastle.X509.X509Certificate) || obj.GetType() == typeof(X509CertificateStructure))
+ {
+ return (Org.BouncyCastle.X509.X509Certificate)obj;
+ }
+ else
+ {
+ logger.Error("Unknown certificate type: " + obj.GetType().FullName);
+ return null;
+ }
+ }
+ catch (Exception e)
+ {
+ logger.Error("LoadFromPkcs8", e);
+ return null;
+ }
+ finally
+ {
+ pemReader.Reader.Close();
+ }
+ }
+ }
+
+ private static Org.BouncyCastle.X509.X509Certificate LoadFromDer(string path)
+ {
+ logger.Debug("LoadFromDer");
+ try
+ {
+ using (FileStream fs = new FileStream(path, FileMode.Open))
+ {
+ X509CertificateParser parser = new X509CertificateParser();
+ return parser.ReadCertificate(fs);
+ }
+
+ }
+ catch (Exception e)
+ {
+ logger.Error("LoadFromDer", e);
+ return null;
+ }
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Random.cs b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Random.cs
new file mode 100644
index 000000000..89b20b1b0
--- /dev/null
+++ b/dotnet/src/extensions/gam/src/DotNetFramework/GamUtils/Utils/Random.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Security;
+using System.Security.Cryptography;
+using System.Text;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace GamUtils.Utils
+{
+ [SecuritySafeCritical]
+ public class Random
+ {
+ internal static string Numeric(int length)
+ {
+ string s = "";
+ byte[] buffer = new byte[sizeof(uint)];
+ using (var rng = RandomNumberGenerator.Create())
+ {
+
+
+ for (int i = 0; i <= length / 10; i++)
+ {
+ rng.GetBytes(buffer);
+ s += BitConverter.ToUInt32(buffer, 0).ToString();
+ }
+ }
+ return s.Length >= length ? s.Substring(0, length) : Numeric(length);
+ }
+
+ [SecuritySafeCritical]
+ internal static string Alphanumeric(int length)
+ {
+
+
+ char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
+ byte[] data = new byte[length];
+#if NETCORE
+ var arraySpan = new Span(data);
+ System.Security.Cryptography.RandomNumberGenerator.Fill(arraySpan);
+#else
+ RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
+ crypto.GetBytes(data);
+#endif
+ StringBuilder result = new StringBuilder(length);
+ foreach (byte b in data)
+ {
+ result.Append(chars[b % (chars.Length)]);
+ }
+ return result.ToString();
+ }
+
+ [SecuritySafeCritical]
+ internal static string HexaBits(int length)
+ {
+ Byte[] result = new Byte[length / 8];
+
+#if NETCORE
+ var arraySpan = new Span(result);
+ System.Security.Cryptography.RandomNumberGenerator.Fill(arraySpan);
+#else
+
+ using (System.Security.Cryptography.RNGCryptoServiceProvider rngCsp = new System.Security.Cryptography.RNGCryptoServiceProvider())
+ {
+
+ rngCsp.GetBytes(result);
+ }
+#endif
+ return Hex.ToHexString(result);
+
+ }
+
+ }
+}
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/GamTestNet.csproj b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/GamTestNet.csproj
new file mode 100644
index 000000000..1d3da5008
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/GamTestNet.csproj
@@ -0,0 +1,73 @@
+
+
+
+ net8.0
+ false
+ CS0618,CA1707
+ false
+
+
+
+ NETCORE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.cer b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.cer
new file mode 100644
index 000000000..bd788b5de
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.cer differ
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.crt b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.crt
new file mode 100644
index 000000000..bd788b5de
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.crt differ
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.key b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.key
new file mode 100644
index 000000000..d9abc2f04
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.key
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYD
+VQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRl
+bzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMM
+CXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29t
+MB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZ
+MRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYD
+VQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1w
+b25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN4
+9AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bm
+ZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBI
+SeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+Y
+UqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+K
+YP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGj
+UDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQt
+QAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhu
+f95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq1
+8PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjK
+dZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9
+/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8Y
+YhsWMIarew5uNT+RS28YHNlbmogh
+-----END CERTIFICATE-----
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.p12 b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.p12
new file mode 100644
index 000000000..54cc6fb26
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.p12 differ
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pem b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pem
new file mode 100644
index 000000000..d9abc2f04
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYD
+VQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRl
+bzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMM
+CXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29t
+MB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZ
+MRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYD
+VQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1w
+b25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN4
+9AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bm
+ZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBI
+SeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+Y
+UqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+K
+YP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGj
+UDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQt
+QAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhu
+f95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq1
+8PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjK
+dZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9
+/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8Y
+YhsWMIarew5uNT+RS28YHNlbmogh
+-----END CERTIFICATE-----
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pkcs12 b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pkcs12
new file mode 100644
index 000000000..54cc6fb26
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pkcs12 differ
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256d_key.key b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256d_key.key
new file mode 100644
index 000000000..e41d6f252
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256d_key.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtc4GlPloet6fQzVqAMuuNudhL2YzePQGN8dEApwGvCTvT5O8
+50MK8RBVCoGc79BhxGFu/l/rsia+wVuEwOn7iSfGoBP25mUWco3SY6LntBTC+n25
+gmfU7MacXuKc4rKclkPI2E+CpeCN33WTVEp+F0onZwygSEngtOZq3HIQyoSJ6YmA
+yePNZbAeCUxLYt0uF8v06CsGOLemrbcOs+UA4QXPmK6PmFKq7pYjgCqnH8m3vZNO
+48DArxVTNYa2GCe4cBw0haNzCsGdMtoMNMOkoFQcSxaPimD96ut2+cFYQ/Jc2kof
+vFHMohzNv8oxHo+xJ0Rc3XJU0jV0RTWoi5xFXQIDAQABAoIBAQCT/Go7JXE4YrI8
+4OOyVhkvM9RV4tkPIYNWL+taPGr3BxGNMvLXRClJ5EN00+BNDNAoLC9O/AE8+HDZ
+r4c2CL/o+umhL98P10UYZfzVgasdWLEFeQVh8ubM/TYXvlp55W20muSHvuDX6RtS
+w7/zItfUWVYNeaeWcBxq5Awj+O1WCoBV8OdWT8av5dyCHquD8rngvxD0gKeHvano
+u6fOZN4tsolrB4GWh8B4A08dh4Ktcv/vxOfhzcS9jpT6+Zc5TdriD2fUYsdiw4dB
+a4rghI61xbEyR8OC0ytOK5HhpXnTLcOv2zk8YmxW4HrkLWNV8xvzNPsZT9p4gWwB
+AOGer07BAoGBAOpOy0rIems7JNFvfnROqW3Nx4rDqCiO+q14t/IBEHQrhdODireO
+lrbUIeK9fnbHjuDoI17UTEtPuR5sdoxV4zyXsTIC37b628GlaoPVh3pyi/6o+Ypg
+p+JFWmuCaNVRxWiGPtW/or/ulmP5XhcRp7QJIvbuD0aIEa1K1i0R/ZHlAoGBAMai
+4rIDB0BnKSQxybSNjfh1ICwzdOuT7SpRD/aOlgcAG/OvyJ1Wk6NoJhL5rJTUA2B9
+es3U3M1jB55wcdQdNdiqVA/reQliLzGXbE5zEQ41oXYJucpTfTU/PbeV/Bj76N+l
+o7lwCllo3EaHc0YKOe8/WnIQsjCoRlOcgzsYfI4ZAoGAMeq7cKEpQ3MEMwI3xHuF
+qPjwC+YHCyz6xr4zIgGMCdPD3P3nLZfZD/Y9idqo+JEnJU8PSgKchmbjn1GoJ9mc
+YapHe8oU8xyaeLTO7mstQ67nmEdTcmGJIrF3w/Oydc/H6K7A8DS1bYJc08uqeeuu
++LIBmu24n2QZr/uDiXKNvOkCgYEAuHRlwxxgzYN+hufdANc6cPCC8cjO2DxDzjn8
+ct6xnsqRKlegGctdyi5avOAxTPscL6wWL7FtYSSG3LBaY7jEWfDBow7tFLOiU5Dj
+uG3N9r4Cs5QQfTvOV3Xkn+idc63p8FTmlrreQWzIsI3zk6THa84O9UFf1yNMOzRq
+AKSadXECgYBEXyOgHyU2irRKX197nUdQd862tWONqaVNk7xiOSdv3CLRDaMkZrci
+mA6diNN+vz3ut57iM7N9Yuqv4Qq/U79wBqElSrjy6Qlr+cVTvwT4RrOXcMfNZ1KN
+Pz/h9l/Hce4Oez0GOLn+BffhCF3gHWz6nwfBgVu0V9xQ8eTaQfh4fw==
+-----END RSA PRIVATE KEY-----
diff --git a/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256d_key.pem b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256d_key.pem
new file mode 100644
index 000000000..e41d6f252
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNet/GamTestNet/Resources/dummycerts/RSA_sha256_2048/sha256d_key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtc4GlPloet6fQzVqAMuuNudhL2YzePQGN8dEApwGvCTvT5O8
+50MK8RBVCoGc79BhxGFu/l/rsia+wVuEwOn7iSfGoBP25mUWco3SY6LntBTC+n25
+gmfU7MacXuKc4rKclkPI2E+CpeCN33WTVEp+F0onZwygSEngtOZq3HIQyoSJ6YmA
+yePNZbAeCUxLYt0uF8v06CsGOLemrbcOs+UA4QXPmK6PmFKq7pYjgCqnH8m3vZNO
+48DArxVTNYa2GCe4cBw0haNzCsGdMtoMNMOkoFQcSxaPimD96ut2+cFYQ/Jc2kof
+vFHMohzNv8oxHo+xJ0Rc3XJU0jV0RTWoi5xFXQIDAQABAoIBAQCT/Go7JXE4YrI8
+4OOyVhkvM9RV4tkPIYNWL+taPGr3BxGNMvLXRClJ5EN00+BNDNAoLC9O/AE8+HDZ
+r4c2CL/o+umhL98P10UYZfzVgasdWLEFeQVh8ubM/TYXvlp55W20muSHvuDX6RtS
+w7/zItfUWVYNeaeWcBxq5Awj+O1WCoBV8OdWT8av5dyCHquD8rngvxD0gKeHvano
+u6fOZN4tsolrB4GWh8B4A08dh4Ktcv/vxOfhzcS9jpT6+Zc5TdriD2fUYsdiw4dB
+a4rghI61xbEyR8OC0ytOK5HhpXnTLcOv2zk8YmxW4HrkLWNV8xvzNPsZT9p4gWwB
+AOGer07BAoGBAOpOy0rIems7JNFvfnROqW3Nx4rDqCiO+q14t/IBEHQrhdODireO
+lrbUIeK9fnbHjuDoI17UTEtPuR5sdoxV4zyXsTIC37b628GlaoPVh3pyi/6o+Ypg
+p+JFWmuCaNVRxWiGPtW/or/ulmP5XhcRp7QJIvbuD0aIEa1K1i0R/ZHlAoGBAMai
+4rIDB0BnKSQxybSNjfh1ICwzdOuT7SpRD/aOlgcAG/OvyJ1Wk6NoJhL5rJTUA2B9
+es3U3M1jB55wcdQdNdiqVA/reQliLzGXbE5zEQ41oXYJucpTfTU/PbeV/Bj76N+l
+o7lwCllo3EaHc0YKOe8/WnIQsjCoRlOcgzsYfI4ZAoGAMeq7cKEpQ3MEMwI3xHuF
+qPjwC+YHCyz6xr4zIgGMCdPD3P3nLZfZD/Y9idqo+JEnJU8PSgKchmbjn1GoJ9mc
+YapHe8oU8xyaeLTO7mstQ67nmEdTcmGJIrF3w/Oydc/H6K7A8DS1bYJc08uqeeuu
++LIBmu24n2QZr/uDiXKNvOkCgYEAuHRlwxxgzYN+hufdANc6cPCC8cjO2DxDzjn8
+ct6xnsqRKlegGctdyi5avOAxTPscL6wWL7FtYSSG3LBaY7jEWfDBow7tFLOiU5Dj
+uG3N9r4Cs5QQfTvOV3Xkn+idc63p8FTmlrreQWzIsI3zk6THa84O9UFf1yNMOzRq
+AKSadXECgYBEXyOgHyU2irRKX197nUdQd862tWONqaVNk7xiOSdv3CLRDaMkZrci
+mA6diNN+vz3ut57iM7N9Yuqv4Qq/U79wBqElSrjy6Qlr+cVTvwT4RrOXcMfNZ1KN
+Pz/h9l/Hce4Oez0GOLn+BffhCF3gHWz6nwfBgVu0V9xQ8eTaQfh4fw==
+-----END RSA PRIVATE KEY-----
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/GamTest.csproj b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/GamTest.csproj
new file mode 100644
index 000000000..89f44a7bc
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/GamTest.csproj
@@ -0,0 +1,57 @@
+
+
+ net471
+ false
+ GamTest
+ GamTest
+ CS0618,CA1707
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
\ No newline at end of file
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Properties/AssemblyInfo.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..e69de29bb
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.cer b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.cer
new file mode 100644
index 000000000..bd788b5de
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.cer differ
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.crt b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.crt
new file mode 100644
index 000000000..bd788b5de
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.crt differ
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.key b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.key
new file mode 100644
index 000000000..d9abc2f04
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.key
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYD
+VQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRl
+bzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMM
+CXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29t
+MB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZ
+MRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYD
+VQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1w
+b25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN4
+9AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bm
+ZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBI
+SeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+Y
+UqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+K
+YP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGj
+UDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQt
+QAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhu
+f95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq1
+8PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjK
+dZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9
+/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8Y
+YhsWMIarew5uNT+RS28YHNlbmogh
+-----END CERTIFICATE-----
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.p12 b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.p12
new file mode 100644
index 000000000..54cc6fb26
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.p12 differ
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pem b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pem
new file mode 100644
index 000000000..d9abc2f04
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYD
+VQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRl
+bzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMM
+CXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29t
+MB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZ
+MRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYD
+VQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1w
+b25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN4
+9AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bm
+ZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBI
+SeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+Y
+UqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+K
+YP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGj
+UDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQt
+QAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhu
+f95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq1
+8PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjK
+dZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9
+/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8Y
+YhsWMIarew5uNT+RS28YHNlbmogh
+-----END CERTIFICATE-----
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pkcs12 b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pkcs12
new file mode 100644
index 000000000..54cc6fb26
Binary files /dev/null and b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256_cert.pkcs12 differ
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256d_key.key b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256d_key.key
new file mode 100644
index 000000000..e41d6f252
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256d_key.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtc4GlPloet6fQzVqAMuuNudhL2YzePQGN8dEApwGvCTvT5O8
+50MK8RBVCoGc79BhxGFu/l/rsia+wVuEwOn7iSfGoBP25mUWco3SY6LntBTC+n25
+gmfU7MacXuKc4rKclkPI2E+CpeCN33WTVEp+F0onZwygSEngtOZq3HIQyoSJ6YmA
+yePNZbAeCUxLYt0uF8v06CsGOLemrbcOs+UA4QXPmK6PmFKq7pYjgCqnH8m3vZNO
+48DArxVTNYa2GCe4cBw0haNzCsGdMtoMNMOkoFQcSxaPimD96ut2+cFYQ/Jc2kof
+vFHMohzNv8oxHo+xJ0Rc3XJU0jV0RTWoi5xFXQIDAQABAoIBAQCT/Go7JXE4YrI8
+4OOyVhkvM9RV4tkPIYNWL+taPGr3BxGNMvLXRClJ5EN00+BNDNAoLC9O/AE8+HDZ
+r4c2CL/o+umhL98P10UYZfzVgasdWLEFeQVh8ubM/TYXvlp55W20muSHvuDX6RtS
+w7/zItfUWVYNeaeWcBxq5Awj+O1WCoBV8OdWT8av5dyCHquD8rngvxD0gKeHvano
+u6fOZN4tsolrB4GWh8B4A08dh4Ktcv/vxOfhzcS9jpT6+Zc5TdriD2fUYsdiw4dB
+a4rghI61xbEyR8OC0ytOK5HhpXnTLcOv2zk8YmxW4HrkLWNV8xvzNPsZT9p4gWwB
+AOGer07BAoGBAOpOy0rIems7JNFvfnROqW3Nx4rDqCiO+q14t/IBEHQrhdODireO
+lrbUIeK9fnbHjuDoI17UTEtPuR5sdoxV4zyXsTIC37b628GlaoPVh3pyi/6o+Ypg
+p+JFWmuCaNVRxWiGPtW/or/ulmP5XhcRp7QJIvbuD0aIEa1K1i0R/ZHlAoGBAMai
+4rIDB0BnKSQxybSNjfh1ICwzdOuT7SpRD/aOlgcAG/OvyJ1Wk6NoJhL5rJTUA2B9
+es3U3M1jB55wcdQdNdiqVA/reQliLzGXbE5zEQ41oXYJucpTfTU/PbeV/Bj76N+l
+o7lwCllo3EaHc0YKOe8/WnIQsjCoRlOcgzsYfI4ZAoGAMeq7cKEpQ3MEMwI3xHuF
+qPjwC+YHCyz6xr4zIgGMCdPD3P3nLZfZD/Y9idqo+JEnJU8PSgKchmbjn1GoJ9mc
+YapHe8oU8xyaeLTO7mstQ67nmEdTcmGJIrF3w/Oydc/H6K7A8DS1bYJc08uqeeuu
++LIBmu24n2QZr/uDiXKNvOkCgYEAuHRlwxxgzYN+hufdANc6cPCC8cjO2DxDzjn8
+ct6xnsqRKlegGctdyi5avOAxTPscL6wWL7FtYSSG3LBaY7jEWfDBow7tFLOiU5Dj
+uG3N9r4Cs5QQfTvOV3Xkn+idc63p8FTmlrreQWzIsI3zk6THa84O9UFf1yNMOzRq
+AKSadXECgYBEXyOgHyU2irRKX197nUdQd862tWONqaVNk7xiOSdv3CLRDaMkZrci
+mA6diNN+vz3ut57iM7N9Yuqv4Qq/U79wBqElSrjy6Qlr+cVTvwT4RrOXcMfNZ1KN
+Pz/h9l/Hce4Oez0GOLn+BffhCF3gHWz6nwfBgVu0V9xQ8eTaQfh4fw==
+-----END RSA PRIVATE KEY-----
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256d_key.pem b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256d_key.pem
new file mode 100644
index 000000000..e41d6f252
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Resources/dummycerts/RSA_sha256_2048/sha256d_key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtc4GlPloet6fQzVqAMuuNudhL2YzePQGN8dEApwGvCTvT5O8
+50MK8RBVCoGc79BhxGFu/l/rsia+wVuEwOn7iSfGoBP25mUWco3SY6LntBTC+n25
+gmfU7MacXuKc4rKclkPI2E+CpeCN33WTVEp+F0onZwygSEngtOZq3HIQyoSJ6YmA
+yePNZbAeCUxLYt0uF8v06CsGOLemrbcOs+UA4QXPmK6PmFKq7pYjgCqnH8m3vZNO
+48DArxVTNYa2GCe4cBw0haNzCsGdMtoMNMOkoFQcSxaPimD96ut2+cFYQ/Jc2kof
+vFHMohzNv8oxHo+xJ0Rc3XJU0jV0RTWoi5xFXQIDAQABAoIBAQCT/Go7JXE4YrI8
+4OOyVhkvM9RV4tkPIYNWL+taPGr3BxGNMvLXRClJ5EN00+BNDNAoLC9O/AE8+HDZ
+r4c2CL/o+umhL98P10UYZfzVgasdWLEFeQVh8ubM/TYXvlp55W20muSHvuDX6RtS
+w7/zItfUWVYNeaeWcBxq5Awj+O1WCoBV8OdWT8av5dyCHquD8rngvxD0gKeHvano
+u6fOZN4tsolrB4GWh8B4A08dh4Ktcv/vxOfhzcS9jpT6+Zc5TdriD2fUYsdiw4dB
+a4rghI61xbEyR8OC0ytOK5HhpXnTLcOv2zk8YmxW4HrkLWNV8xvzNPsZT9p4gWwB
+AOGer07BAoGBAOpOy0rIems7JNFvfnROqW3Nx4rDqCiO+q14t/IBEHQrhdODireO
+lrbUIeK9fnbHjuDoI17UTEtPuR5sdoxV4zyXsTIC37b628GlaoPVh3pyi/6o+Ypg
+p+JFWmuCaNVRxWiGPtW/or/ulmP5XhcRp7QJIvbuD0aIEa1K1i0R/ZHlAoGBAMai
+4rIDB0BnKSQxybSNjfh1ICwzdOuT7SpRD/aOlgcAG/OvyJ1Wk6NoJhL5rJTUA2B9
+es3U3M1jB55wcdQdNdiqVA/reQliLzGXbE5zEQ41oXYJucpTfTU/PbeV/Bj76N+l
+o7lwCllo3EaHc0YKOe8/WnIQsjCoRlOcgzsYfI4ZAoGAMeq7cKEpQ3MEMwI3xHuF
+qPjwC+YHCyz6xr4zIgGMCdPD3P3nLZfZD/Y9idqo+JEnJU8PSgKchmbjn1GoJ9mc
+YapHe8oU8xyaeLTO7mstQ67nmEdTcmGJIrF3w/Oydc/H6K7A8DS1bYJc08uqeeuu
++LIBmu24n2QZr/uDiXKNvOkCgYEAuHRlwxxgzYN+hufdANc6cPCC8cjO2DxDzjn8
+ct6xnsqRKlegGctdyi5avOAxTPscL6wWL7FtYSSG3LBaY7jEWfDBow7tFLOiU5Dj
+uG3N9r4Cs5QQfTvOV3Xkn+idc63p8FTmlrreQWzIsI3zk6THa84O9UFf1yNMOzRq
+AKSadXECgYBEXyOgHyU2irRKX197nUdQd862tWONqaVNk7xiOSdv3CLRDaMkZrci
+mA6diNN+vz3ut57iM7N9Yuqv4Qq/U79wBqElSrjy6Qlr+cVTvwT4RrOXcMfNZ1KN
+Pz/h9l/Hce4Oez0GOLn+BffhCF3gHWz6nwfBgVu0V9xQ8eTaQfh4fw==
+-----END RSA PRIVATE KEY-----
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/Resources/CryptographicHash.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/Resources/CryptographicHash.cs
new file mode 100644
index 000000000..578a7778a
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/Resources/CryptographicHash.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace GamTest.Utils.Resources
+{
+ internal class CryptographicHash
+ {
+ HashAlgorithm alg;
+ public CryptographicHash(string algorithm)
+ {
+ // Supports algorithm = {MD5, RIPEMD160, SHA1, SHA256, SHA384, SHA512}
+ if (String.IsNullOrEmpty(algorithm))
+ algorithm = "SHA256";
+
+#if NETCORE
+ alg = CryptoUtils.CreateHashAlgorithm(algorithm);
+#else
+ alg = HashAlgorithm.Create(algorithm);
+#endif
+ }
+ static public CryptographicHash Create(string algorithm)
+ {
+ return new CryptographicHash(algorithm);
+ }
+ public string ComputeHash(string data)
+ {
+ byte[] bin = Encoding.UTF8.GetBytes(data);
+ return Convert.ToBase64String(alg.ComputeHash(bin));
+ }
+ }
+
+ internal class CryptoUtils
+ {
+ internal static HashAlgorithm CreateHashAlgorithm(string hashAlgorithmName)
+ {
+ switch (hashAlgorithmName)
+ {
+ case "SHA256": case "SHA-256": case "System.Security.Cryptography.SHA256": return SHA256.Create();
+ case "SHA384": case "SHA-384": case "System.Security.Cryptography.SHA384": return SHA384.Create();
+ case "SHA512": case "SHA-512": case "System.Security.Cryptography.SHA512": return SHA512.Create();
+ default: return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestEncoding.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestEncoding.cs
new file mode 100644
index 000000000..add62090e
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestEncoding.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Text;
+using NUnit.Framework;
+using GamUtils;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace GamTest.Utils
+{
+ [TestFixture]
+ public class TestEncoding
+ {
+ [SetUp]
+ public virtual void SetUp()
+ {
+
+ }
+
+ [Test]
+ public void TestB64ToB64Url()
+ {
+ int i = 0;
+ do
+ {
+ string randomString = GamUtilsEO.RandomAlphanumeric(128);
+ string testing = GamUtilsEO.Base64ToBase64Url(Base64.ToBase64String(Encoding.UTF8.GetBytes(randomString)));
+ Assert.AreEqual(randomString, B64UrlToUtf8(testing), "TestB64ToB64Url");
+ i++;
+ } while (i < 50);
+ }
+
+ private static string B64UrlToUtf8(string base64Url)
+ {
+ try
+ {
+ byte[] bytes = UrlBase64.Decode(base64Url);
+ return Encoding.UTF8.GetString(bytes);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.StackTrace);
+ return "";
+ }
+ }
+
+ }
+}
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestEncryption.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestEncryption.cs
new file mode 100644
index 000000000..9a1d891da
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestEncryption.cs
@@ -0,0 +1,23 @@
+using GamUtils;
+using Microsoft.IdentityModel.Tokens;
+using NUnit.Framework;
+
+namespace GamTest.Utils
+{
+ [TestFixture]
+ public class TestEncryption
+ {
+ [Test]
+ public void TestAesGcm()
+ {
+ string key = GamUtilsEO.RandomHexaBits(256);
+ string nonce = GamUtilsEO.RandomHexaBits(128);
+ string txt = "hello world";
+ int macSize = 64;
+ string encrypted = GamUtilsEO.AesGcm(txt, key, nonce, macSize, true);
+ Assert.IsFalse(encrypted.IsNullOrEmpty(), "testAesGcm encrypt");
+ string decrypted = GamUtilsEO.AesGcm(encrypted, key, nonce, macSize, false);
+ Assert.AreEqual(txt, decrypted, "testAesGcm decrypt");
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestHash.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestHash.cs
new file mode 100644
index 000000000..46a7093e1
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestHash.cs
@@ -0,0 +1,63 @@
+using GamTest.Utils.Resources;
+using NUnit.Framework;
+using GamUtils;
+using System;
+
+namespace GamTest.Utils
+{
+ [TestFixture]
+ public class TestHash
+ {
+#pragma warning disable CS0414
+ private static string one;
+ private static string two;
+ private static string three;
+ private static string four;
+ private static string five;
+
+ private CryptographicHash cryptographicHash;
+#pragma warning restore CS0414
+
+ [SetUp]
+ public virtual void SetUp()
+ {
+ one = "one";
+ two = "two";
+ three = "three";
+ four = "four";
+ five = "five";
+ cryptographicHash = new CryptographicHash("SHA-512");
+ }
+
+ [Test]
+ public void TestSha512()
+ {
+ Assert.AreEqual(cryptographicHash.ComputeHash(one), GamUtilsEO.Sha512(one), "one");
+ Assert.AreEqual(cryptographicHash.ComputeHash(two), GamUtilsEO.Sha512(two), "two");
+ Assert.AreEqual(cryptographicHash.ComputeHash(three), GamUtilsEO.Sha512(three), "three");
+ Assert.AreEqual(cryptographicHash.ComputeHash(four), GamUtilsEO.Sha512(four), "four");
+ Assert.AreEqual(cryptographicHash.ComputeHash(five), GamUtilsEO.Sha512(five), "five");
+ }
+
+ [Test]
+ public void TestSha512Random()
+ {
+ for (int i = 0; i < 100; i++)
+ {
+ string value = GamUtilsEO.RandomAlphanumeric(15);
+ Assert.AreEqual(cryptographicHash.ComputeHash(value), GamUtilsEO.Sha512(value), "random sha512 ");
+ }
+ }
+
+ [Test]
+ public void TestSha256()
+ {
+ string[] arrayInputs = { one, two, three, four, five };
+ string[] arrayRes = { "dpLDrTVAu4A8Ags67mbNiIcSMjTqDG5xQ8Ct1z/0Me0=", "P8TM/nRYcOLA2Z9x8w/wZWyN7dQcwdfT03aw2+aF4vM=", "i1udsME9skJWyCmqNkqpDG0uujGLkjKkq5MTuVTTVV8=", "BO+vCA9aPnThwp0cpqSFaTgsu80yTo1Z0rg+8hwDnwA=", "IisL1R/O9+ZcLmLbLtZUVwE7q1a+b6/rGe4R1FMVPIA=" };
+ for (int i = 0; i < arrayInputs.Length; i++)
+ {
+ Assert.AreEqual(GamUtilsEO.Sha256(arrayInputs[i]), arrayRes[i], "TestSha256 error");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestJwk.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestJwk.cs
new file mode 100644
index 000000000..3956853e3
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestJwk.cs
@@ -0,0 +1,43 @@
+using Jose;
+using NUnit.Framework;
+using GamUtils;
+using Microsoft.IdentityModel.Tokens;
+using System;
+
+namespace GamTest.Utils
+{
+ [TestFixture]
+ public class TestJwk
+ {
+
+ [SetUp]
+ public virtual void SetUp()
+ {
+ }
+
+ [Test]
+ public void TestGenerateKeyPair()
+ {
+ string jwk = GamUtilsEO.GenerateKeyPair();
+ Assert.IsFalse(jwk.IsNullOrEmpty(), "Generate key pair jwk");
+ }
+
+
+ [Test]
+ public void TestPublicJwk()
+ {
+ string jwk = GamUtilsEO.GenerateKeyPair();
+ string public_jwk = GamUtilsEO.GetPublicJwk(jwk);
+ string public_jwks = "{\"keys\": [" + public_jwk + "]}";
+ try
+ {
+ JwkSet jwks = JwkSet.FromJson(public_jwks);
+ Assert.NotNull(jwks, "To public JWK fail");
+ }
+ catch (Exception e)
+ {
+ Assert.Fail("Exception on testPublicJwk" + e.Message);
+ }
+ }
+ }
+}
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestJwt.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestJwt.cs
new file mode 100644
index 000000000..60c727fa4
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestJwt.cs
@@ -0,0 +1,187 @@
+using System;
+using System.IO;
+using System.Reflection;
+using NUnit.Framework;
+using GamUtils;
+using Microsoft.IdentityModel.Tokens;
+
+
+
+
+namespace GamTest.Utils
+{
+ [TestFixture]
+ public class TestJwt
+ {
+#pragma warning disable CS0414
+ private static string resources;
+ private static string header;
+ private static string payload;
+ private static string path_RSA_sha256_2048;
+ private static string alias;
+ private static string password;
+#pragma warning disable IDE0044
+ private static string BASE_PATH;
+#pragma warning restore IDE0044
+#pragma warning restore CS0414
+
+
+
+ [SetUp]
+ public virtual void SetUp()
+ {
+ BASE_PATH = GetStartupDirectory();
+ resources = Path.Combine(BASE_PATH, "Resources", "dummycerts");
+
+ string kid = Guid.NewGuid().ToString();
+
+ header = "{\n" +
+ " \"alg\": \"RS256\",\n" +
+ " \"kid\": \"" + kid + "\",\n" +
+ " \"typ\": \"JWT\"\n" +
+ "}";
+ payload = "{\n" +
+ " \"sub\": \"1234567890\",\n" +
+ " \"name\": \"John Doe\",\n" +
+ " \"iat\": 1516239022\n" +
+ "}";
+
+ alias = "1";
+ password = "dummy";
+ path_RSA_sha256_2048 = Path.Combine(resources, "RSA_sha256_2048");
+
+ }
+
+ [Test]
+ public void Test_pkcs8_pem()
+ {
+ string token = GamUtilsEO.CreateJwt(Path.Combine(path_RSA_sha256_2048, "sha256d_key.pem"), "", "", payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "Test_pkcs8_pem");
+ bool result = GamUtilsEO.VerifyJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.cer"), "", "", token);
+ Assert.IsTrue(result, "test_pkcs8 verify cer");
+ }
+
+ [Test]
+ public void Test_get()
+ {
+ string token = GamUtilsEO.CreateJwt(Path.Combine(path_RSA_sha256_2048, "sha256d_key.pem"), "", "", payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_get create");
+ string header_get = GamUtilsEO.GetJwtHeader(token);
+ Assert.IsFalse(header_get.IsNullOrEmpty(), "test_get getHeader");
+ string payload_get = GamUtilsEO.GetJwtPayload(token);
+ Assert.IsFalse(payload_get.IsNullOrEmpty(), "test_get getPayload");
+ }
+
+ [Test]
+ public void Test_pkcs8_key()
+ {
+ string token = GamUtilsEO.CreateJwt(Path.Combine(path_RSA_sha256_2048, "sha256d_key.key"), "", "", payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_pkcs8 create");
+ bool result = GamUtilsEO.VerifyJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.crt"), "", "", token);
+ Assert.IsTrue(result, "test_pkcs8 verify crt");
+ }
+
+ [Test]
+ public void Test_pkcs12_p12()
+ {
+ string token = GamUtilsEO.CreateJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.p12"), alias, password, payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_pkcs12_p12 create");
+ bool result = GamUtilsEO.VerifyJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.p12"), alias, password, token);
+ Assert.IsTrue(result, "test_pkcs12_p12 verify");
+ }
+
+ [Test]
+ public void Test_pkcs12_pkcs12()
+ {
+ string token = GamUtilsEO.CreateJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.pkcs12"), alias, password, payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_pkcs12_pkcs12 create");
+ bool result = GamUtilsEO.VerifyJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.pkcs12"), alias, password, token);
+ Assert.IsTrue(result, "test_pkcs12_pkcs12 verify");
+ }
+
+ [Test]
+ [Ignore("issues with pfx extension in .Net")]
+ public void Test_pkcs12_pfx()
+ {
+ string token = GamUtilsEO.CreateJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.pfx"), alias, password, payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_pkcs12_pfx create");
+ bool result = GamUtilsEO.VerifyJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.pfx"), alias, password, token);
+ Assert.IsTrue(result, "test_pkcs12_pfx verify");
+ }
+
+ [Test]
+ public void Test_pkcs12_noalias()
+ {
+ string token = GamUtilsEO.CreateJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.p12"), "", password, payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_pkcs12_noalias jks create");
+ bool result = GamUtilsEO.VerifyJwt(Path.Combine(path_RSA_sha256_2048, "sha256_cert.p12"), "", password, token);
+ Assert.IsTrue(result, "test_pkcs12_noalias jks verify");
+ }
+
+ [Test]
+ public void Test_b64()
+ {
+ string publicKey = "MIIEATCCAumgAwIBAgIJAIAqvKHZ+gFhMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYDVQQGEwJVWTETMBEGA1UECAwKTW9udGV2aWRlbzETMBEGA1UEBwwKTW9udGV2aWRlbzEQMA4GA1UECgwHR2VuZVh1czERMA8GA1UECwwIU2VjdXJpdHkxEjAQBgNVBAMMCXNncmFtcG9uZTEkMCIGCSqGSIb3DQEJARYVc2dyYW1wb25lQGdlbmV4dXMuY29tMB4XDTIwMDcwODE4NTcxN1oXDTI1MDcwNzE4NTcxN1owgZYxCzAJBgNVBAYTAlVZMRMwEQYDVQQIDApNb250ZXZpZGVvMRMwEQYDVQQHDApNb250ZXZpZGVvMRAwDgYDVQQKDAdHZW5lWHVzMREwDwYDVQQLDAhTZWN1cml0eTESMBAGA1UEAwwJc2dyYW1wb25lMSQwIgYJKoZIhvcNAQkBFhVzZ3JhbXBvbmVAZ2VuZXh1cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAGjUDBOMB0GA1UdDgQWBBQtQAWJRWNr/OswPSAdwCQh0Eei/DAfBgNVHSMEGDAWgBQtQAWJRWNr/OswPSAdwCQh0Eei/DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjHe3JbNKv0Ywc1zlLacUNWcjLbmzvnjs8Wq5oxtf5wG5PUlhLSYZ9MPhuf95PlibnrO/xVY292P5lo4NKhS7VOonpbPQ/PrCMO84Pz1LGfM/wCWQIowh6VHq18PiZka9zbwl6So0tgClKkFSRk4wpKrWX3+M3+Y+D0brd8sEtA6dXeYHDtqV0YgjKdZIIOx0vDT4alCoVQrQ1yAIq5INT3cSLgJezIhEadDv3Tc7bMxMFeL+81qHm9Z/9/KE6Z+JB0ZEOkF/2NSQJd+Z7MBR8CxOdTQis3ltMoXDatNkjZ2Env40sw4NICB8YYhsWMIarew5uNT+RS28YHNlbmogh";
+ string privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1zgaU+Wh63p9DNWoAy64252EvZjN49AY3x0QCnAa8JO9Pk7znQwrxEFUKgZzv0GHEYW7+X+uyJr7BW4TA6fuJJ8agE/bmZRZyjdJjoue0FML6fbmCZ9Tsxpxe4pzispyWQ8jYT4Kl4I3fdZNUSn4XSidnDKBISeC05mrcchDKhInpiYDJ481lsB4JTEti3S4Xy/ToKwY4t6attw6z5QDhBc+Yro+YUqruliOAKqcfybe9k07jwMCvFVM1hrYYJ7hwHDSFo3MKwZ0y2gw0w6SgVBxLFo+KYP3q63b5wVhD8lzaSh+8UcyiHM2/yjEej7EnRFzdclTSNXRFNaiLnEVdAgMBAAECggEBAJP8ajslcThisjzg47JWGS8z1FXi2Q8hg1Yv61o8avcHEY0y8tdEKUnkQ3TT4E0M0CgsL078ATz4cNmvhzYIv+j66aEv3w/XRRhl/NWBqx1YsQV5BWHy5sz9Nhe+WnnlbbSa5Ie+4NfpG1LDv/Mi19RZVg15p5ZwHGrkDCP47VYKgFXw51ZPxq/l3IIeq4PyueC/EPSAp4e9qei7p85k3i2yiWsHgZaHwHgDTx2Hgq1y/+/E5+HNxL2OlPr5lzlN2uIPZ9Rix2LDh0FriuCEjrXFsTJHw4LTK04rkeGledMtw6/bOTxibFbgeuQtY1XzG/M0+xlP2niBbAEA4Z6vTsECgYEA6k7LSsh6azsk0W9+dE6pbc3HisOoKI76rXi38gEQdCuF04OKt46WttQh4r1+dseO4OgjXtRMS0+5Hmx2jFXjPJexMgLftvrbwaVqg9WHenKL/qj5imCn4kVaa4Jo1VHFaIY+1b+iv+6WY/leFxGntAki9u4PRogRrUrWLRH9keUCgYEAxqLisgMHQGcpJDHJtI2N+HUgLDN065PtKlEP9o6WBwAb86/InVaTo2gmEvmslNQDYH16zdTczWMHnnBx1B012KpUD+t5CWIvMZdsTnMRDjWhdgm5ylN9NT89t5X8GPvo36WjuXAKWWjcRodzRgo57z9achCyMKhGU5yDOxh8jhkCgYAx6rtwoSlDcwQzAjfEe4Wo+PAL5gcLLPrGvjMiAYwJ08Pc/ectl9kP9j2J2qj4kSclTw9KApyGZuOfUagn2Zxhqkd7yhTzHJp4tM7uay1DrueYR1NyYYkisXfD87J1z8forsDwNLVtglzTy6p56674sgGa7bifZBmv+4OJco286QKBgQC4dGXDHGDNg36G590A1zpw8ILxyM7YPEPOOfxy3rGeypEqV6AZy13KLlq84DFM+xwvrBYvsW1hJIbcsFpjuMRZ8MGjDu0Us6JTkOO4bc32vgKzlBB9O85XdeSf6J1zrenwVOaWut5BbMiwjfOTpMdrzg71QV/XI0w7NGoApJp1cQKBgERfI6AfJTaKtEpfX3udR1B3zra1Y42ppU2TvGI5J2/cItENoyRmtyKYDp2I036/Pe63nuIzs31i6q/hCr9Tv3AGoSVKuPLpCWv5xVO/BPhGs5dwx81nUo0/P+H2X8dx7g57PQY4uf4F9+EIXeAdbPqfB8GBW7RX3FDx5NpB+Hh/";
+ string token = GamUtilsEO.CreateJwt(privateKey, "", "", payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_b64 create");
+ bool result = GamUtilsEO.VerifyJwt(publicKey, "", "", token);
+ Assert.IsTrue(result, "test_b64 verify");
+ }
+
+ [Test]
+ public void Test_json_jwk()
+ {
+ string keyPair = GamUtilsEO.GenerateKeyPair();
+ string token = GamUtilsEO.CreateJwt(keyPair, "", "", payload, header);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_json_jwk create");
+ string publicJwk = GamUtilsEO.GetPublicJwk(keyPair);
+ bool result = GamUtilsEO.VerifyJwt(publicJwk, "", "", token);
+ Assert.IsTrue(result, "test_json_jwk verify");
+ }
+
+ [Test]
+ public void Test_json_jwks()
+ {
+ string keyPair = GamUtilsEO.GenerateKeyPair();
+ string publicJwk = GamUtilsEO.GetPublicJwk(keyPair);
+ string header_jwks = MakeHeader(publicJwk);
+ string token = GamUtilsEO.CreateJwt(keyPair, "", "", payload, header_jwks);
+ Assert.IsFalse(token.IsNullOrEmpty(), "test_json_jwks create");
+ string publicJwks = "{\"keys\": [" + publicJwk + "]}";
+ bool result = GamUtilsEO.VerifyJwt(publicJwks, "", "", token);
+ Assert.IsTrue(result, "test_json_jwks verify");
+ }
+
+
+ private static string GetStartupDirectory()
+ {
+#pragma warning disable SYSLIB0044
+ string dir = Assembly.GetCallingAssembly().GetName().CodeBase;
+#pragma warning restore SYSLIB0044
+ Uri uri = new Uri(dir);
+ return Path.GetDirectoryName(uri.LocalPath);
+ }
+
+ private static string MakeHeader(string publicJwk)
+ {
+ try
+ {
+ Jose.Jwk jwk = Jose.Jwk.FromJson(publicJwk);
+ return "{\n" +
+ " \"alg\": \"RS256\",\n" +
+ " \"kid\": \"" + jwk.KeyId + "\",\n" +
+ " \"typ\": \"JWT\"\n" +
+ "}";
+
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.StackTrace);
+ return "";
+ }
+ }
+
+
+ }
+}
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestRandom.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestRandom.cs
new file mode 100644
index 000000000..628177cf0
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestRandom.cs
@@ -0,0 +1,85 @@
+using NUnit.Framework;
+using GamUtils;
+using Microsoft.IdentityModel.Tokens;
+using Org.BouncyCastle.Utilities.Encoders;
+using System;
+
+namespace GamTest.Utils
+{
+ [TestFixture]
+ public class TestRandom
+ {
+#pragma warning disable CS0414
+ private static int l128;
+ private static int l256;
+
+ private static int l5;
+
+ private static int l10;
+#pragma warning restore CS0414
+
+ [SetUp]
+ public virtual void SetUp()
+ {
+ l128 = 128;
+ l256 = 256;
+ l5 = 5;
+ l10 = 10;
+ }
+
+ [Test]
+ public void TestRandomNumeric()
+ {
+ string l5_string = GamUtilsEO.RandomNumeric(l5);
+ Assert.AreEqual(l5, l5_string.Length, "l5 numeric");
+
+ string l10_string = GamUtilsEO.RandomNumeric(l10);
+ Assert.AreEqual(l10, l10_string.Length, "l10 numeric");
+
+ string l128_string = GamUtilsEO.RandomNumeric(l128);
+ Assert.AreEqual(l128, l128_string.Length, "l128 numeric");
+
+ string l256_string = GamUtilsEO.RandomNumeric(l256);
+ Assert.AreEqual(l256, l256_string.Length, "l256 numeric");
+
+ }
+
+ [Test]
+ public void TestRandomAlphanumeric()
+ {
+ string l5_string = GamUtilsEO.RandomAlphanumeric(l5);
+ Assert.AreEqual(l5, l5_string.Length, "l5 alphanumeric");
+
+ string l10_string = GamUtilsEO.RandomAlphanumeric(l10);
+ Assert.AreEqual(l10, l10_string.Length, "l10 alphanumeric");
+
+ string l128_string = GamUtilsEO.RandomAlphanumeric(l128);
+ Assert.AreEqual(l128, l128_string.Length, "l128 alphanumeric");
+
+ string l256_string = GamUtilsEO.RandomAlphanumeric(l256);
+ Assert.AreEqual(l256, l256_string.Length, "l256 alphanumeric");
+ }
+
+ [Test]
+ public void TestHexaBits()
+ {
+ int[] lengths = new int[] { 32, 64, 128, 256, 512, 1024 };
+ foreach(int n in lengths)
+ {
+ string hexa = GamUtilsEO.RandomHexaBits(n);
+ Assert.IsFalse(hexa.IsNullOrEmpty(), "TestHexaBits");
+ try
+ {
+ byte[] decoded = Hex.Decode(hexa);
+ if(decoded.Length*8 != n)
+ {
+ Assert.Fail("TestHexaBits wrong hexa length");
+ }
+ }catch(Exception e)
+ {
+ Assert.Fail("TestHexaBits nt hexa characters " + e.Message);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestUnixTimestamp.cs b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestUnixTimestamp.cs
new file mode 100644
index 000000000..64321c0a7
--- /dev/null
+++ b/dotnet/src/extensions/gam/test/DotNetFramework/GamTest/Utils/TestUnixTimestamp.cs
@@ -0,0 +1,37 @@
+using System;
+using NUnit.Framework;
+using System.Globalization;
+using GamUtils;
+
+namespace GamTest.Utils
+{
+ [TestFixture]
+ public class TestUnixTimestamp
+ {
+
+ [Test]
+ public void TestCreate()
+ {
+ DateTime one = CreateDate("2024/02/02 02:02:02"); //1706839322
+ DateTime two = CreateDate("2023/03/03 03:03:03"); //1677812583
+ DateTime three = CreateDate("2022/04/04 04:04:04"); //1649045044
+ DateTime four = CreateDate("2020/02/02 02:22:22"); //1580610142
+ DateTime five = CreateDate("2010/05/05 05:05:05"); //1273035905
+ DateTime six = CreateDate("2000/05/05 05:05:05"); //957503105
+
+ DateTime[] arrayDates = new DateTime[] { one, two, three, four, five, six };
+ long[] arrayStamps = new long[] { 1706839322L, 1677812583L, 1649045044L, 1580610142L, 1273035905L, 957503105L};
+
+ for (int i = 0; i < arrayDates.Length; i++)
+ {
+ Assert.AreEqual(GamUtilsEO.CreateUnixTimestamp(arrayDates[i]), arrayStamps[i], "testCreate");
+ }
+ }
+
+ private static DateTime CreateDate(string date)
+ {
+ return DateTime.ParseExact(date, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
+ }
+
+ }
+}