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); + } + + } +}