From 6b60061ab6959bfeb5d3ee05a4305727c8d78a24 Mon Sep 17 00:00:00 2001 From: Klaus Fischer <klaus.fischer@eloware.com> Date: Wed, 8 Jun 2022 06:51:04 +0200 Subject: [PATCH] Extracted encrypt/decrypt in spearat class --- FitConnect/EncryptionBaseClass.cs | 81 +++++++++++++++++++++++ FitConnect/FitConnectEndpoints.cs | 70 ++++++++++++++++++++ FitConnect/FunctionalBaseClass.cs | 102 +---------------------------- SenderTest/SenderEncryptionTest.cs | 39 +++++++++++ SenderTest/UnitTest1.cs | 46 ------------- 5 files changed, 192 insertions(+), 146 deletions(-) create mode 100644 FitConnect/EncryptionBaseClass.cs create mode 100644 FitConnect/FitConnectEndpoints.cs create mode 100644 SenderTest/SenderEncryptionTest.cs delete mode 100644 SenderTest/UnitTest1.cs diff --git a/FitConnect/EncryptionBaseClass.cs b/FitConnect/EncryptionBaseClass.cs new file mode 100644 index 00000000..7ecb39cd --- /dev/null +++ b/FitConnect/EncryptionBaseClass.cs @@ -0,0 +1,81 @@ +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using Microsoft.Extensions.Logging; + +namespace FitConnect; + +public class EncryptionBaseClass { + private readonly ILogger _logger; + private RSA _rsa; + + protected EncryptionBaseClass(ILogger logger) { + _logger = logger; + _rsa = RSA.Create(2048); + } + + + /// <summary> + /// + /// </summary> + /// <param name="cert"></param> + /// <returns></returns> + private bool CheckCertificate(X509Certificate2 cert) => true; + + /// <summary> + /// + /// </summary> + /// <param name="certPath"></param> + /// <exception cref="ArgumentException"></exception> + /// <exception cref="Exception"></exception> + public void ImportCertificate(string certPath) { + _logger.LogInformation("Importing certificate {CertPath}", certPath); + var cert = + new X509Certificate2(certPath, "", X509KeyStorageFlags.MachineKeySet); + + if (!CheckCertificate(cert)) { + throw new ArgumentException("Certificate is not valid"); + } + + var parameters = cert.PublicKey.GetRSAPublicKey()?.ExportParameters(true); + if (parameters == null) { + throw new Exception("Could not get public key from certificate"); + } + + _rsa.ImportParameters(parameters.Value); + } + + public byte[] DecryptDataAsync(byte[] data, byte[] privateKey) { + /* + * var keyParams = new PbeParameters( + PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, numberOfIterations); + + var privateKey = + _rsa.ExportEncryptedPkcs8PrivateKey(Encoding.UTF8.GetBytes(password), keyParams); + + logger?.LogInformation( + "Private key: {}", privateKey); + { + */ + return _rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA256); + } + + public byte[] ExportPublicKey() { + return _rsa.ExportRSAPublicKey(); + } + + public byte[] ExportPrivateKey() { + return _rsa.ExportRSAPrivateKey(); + } + + public byte[] EncryptData(byte[] data, byte[]? publicKey) { + _logger?.LogInformation( + "Encrypting data with public key: {}", + Convert.ToBase64String(_rsa.ExportRSAPublicKey())); + + if (publicKey != null) { + _rsa.ImportRSAPublicKey(publicKey, out var read); + } + + return _rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256); + } +} diff --git a/FitConnect/FitConnectEndpoints.cs b/FitConnect/FitConnectEndpoints.cs new file mode 100644 index 00000000..57277b6d --- /dev/null +++ b/FitConnect/FitConnectEndpoints.cs @@ -0,0 +1,70 @@ +namespace FitConnect; + +public class FitConnectEndpoints { + /// <summary> + /// Default constructor. + /// </summary> + /// <param name="tokenUrl">URL for receiving the OAuth token</param> + /// <param name="submissionApi">URL for the submission API</param> + /// <param name="routingApi">URL for the routing API</param> + public FitConnectEndpoints(string tokenUrl, string submissionApi, string routingApi) { + TokenUrl = tokenUrl; + SubmissionApi = submissionApi; + RoutingApi = routingApi; + } + + /// <summary> + /// URL for receiving the OAuth token. + /// </summary> + public string TokenUrl { get; } + + /// <summary> + /// URL for the submission API. + /// </summary> + public string SubmissionApi { get; } + + /// <summary> + /// URL for the routing API. + /// </summary> + public string RoutingApi { get; } + + + public enum EndpointType { + Development, + Testing, + Production + } + + /// <summary> + /// Creates the endpoints for the given environment. + /// </summary> + /// <param name="endpointType">Environment to get endpoints for</param> + /// <returns></returns> + /// <exception cref="ArgumentException">Not all environments are ready to use</exception> + public static FitConnectEndpoints Create(EndpointType endpointType) { + return endpointType switch { + EndpointType.Development => DevEndpoints, + EndpointType.Testing => throw new ArgumentException("Not approved for online testing"), + EndpointType.Production => throw new ArgumentException("NOT PRODUCTION READY"), + _ => throw new ArgumentOutOfRangeException(nameof(endpointType), endpointType, null) + }; + } + + private static readonly FitConnectEndpoints DevEndpoints = new( + "https://auth-testing.fit-connect.fitko.dev/token", + "https://submission-api-testing.fit-connect.fitko.dev", + "https://routing-api-testing.fit-connect.fitko.dev" + ); + + private static readonly FitConnectEndpoints TestEndpoints = new( + "https://auth-testing.fit-connect.fitko.dev/token", + "https://submission-api-testing.fit-connect.fitko.dev", + "https://routing-api-testing.fit-connect.fitko.dev" + ); + + private static readonly FitConnectEndpoints ProductionEndpoints = new( + "https://auth-testing.fit-connect.fitko.dev/token", + "https://submission-api-testing.fit-connect.fitko.dev", + "https://routing-api-testing.fit-connect.fitko.dev" + ); +} diff --git a/FitConnect/FunctionalBaseClass.cs b/FitConnect/FunctionalBaseClass.cs index b2605acd..eeb68911 100644 --- a/FitConnect/FunctionalBaseClass.cs +++ b/FitConnect/FunctionalBaseClass.cs @@ -1,87 +1,16 @@ using System.Net.Http.Headers; using System.Net.Http.Json; -using System.Security.Cryptography; using System.Text; using FitConnect.Models; using Microsoft.Extensions.Logging; namespace FitConnect; -public class FitConnectEndpoints { - /// <summary> - /// Default constructor. - /// </summary> - /// <param name="tokenUrl">URL for receiving the OAuth token</param> - /// <param name="submissionApi">URL for the submission API</param> - /// <param name="routingApi">URL for the routing API</param> - public FitConnectEndpoints(string tokenUrl, string submissionApi, string routingApi) { - TokenUrl = tokenUrl; - SubmissionApi = submissionApi; - RoutingApi = routingApi; - } - - /// <summary> - /// URL for receiving the OAuth token. - /// </summary> - public string TokenUrl { get; } - - /// <summary> - /// URL for the submission API. - /// </summary> - public string SubmissionApi { get; } - - /// <summary> - /// URL for the routing API. - /// </summary> - public string RoutingApi { get; } - - - public enum EndpointType { - Development, - Testing, - Production - } - - /// <summary> - /// Creates the endpoints for the given environment. - /// </summary> - /// <param name="endpointType">Environment to get endpoints for</param> - /// <returns></returns> - /// <exception cref="ArgumentException">Not all environments are ready to use</exception> - public static FitConnectEndpoints Create(EndpointType endpointType) { - return endpointType switch { - EndpointType.Development => DevEndpoints, - EndpointType.Testing => throw new ArgumentException("Not approved for online testing"), - EndpointType.Production => throw new ArgumentException("NOT PRODUCTION READY"), - _ => throw new ArgumentOutOfRangeException(nameof(endpointType), endpointType, null) - }; - } - - private static readonly FitConnectEndpoints DevEndpoints = new( - "https://auth-testing.fit-connect.fitko.dev/token", - "https://submission-api-testing.fit-connect.fitko.dev", - "https://routing-api-testing.fit-connect.fitko.dev" - ); - - private static readonly FitConnectEndpoints TestEndpoints = new( - "https://auth-testing.fit-connect.fitko.dev/token", - "https://submission-api-testing.fit-connect.fitko.dev", - "https://routing-api-testing.fit-connect.fitko.dev" - ); - - private static readonly FitConnectEndpoints ProductionEndpoints = new( - "https://auth-testing.fit-connect.fitko.dev/token", - "https://submission-api-testing.fit-connect.fitko.dev", - "https://routing-api-testing.fit-connect.fitko.dev" - ); -} - -public abstract class FunctionalBaseClass { +public abstract class FunctionalBaseClass : EncryptionBaseClass { protected readonly ILogger? logger; - private RSA _rsa; public FitConnectEndpoints Endpoints { get; } - protected FunctionalBaseClass(ILogger? logger, FitConnectEndpoints? endpoints) { + protected FunctionalBaseClass(ILogger? logger, FitConnectEndpoints? endpoints) : base(logger) { Endpoints = endpoints ?? FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development); @@ -130,33 +59,6 @@ public abstract class FunctionalBaseClass { throw new NotImplementedException(); } - public byte[] EncryptDataAsync(byte[] data, - byte[]? publicKey, - string? password, - int numberOfIterations) { - _rsa = RSA.Create(2048); - // _rsa.ImportRSAPublicKey(publicKey, out var read); - - logger?.LogInformation( - "Encrypting data with public key: {}", - Convert.ToBase64String(_rsa.ExportRSAPublicKey())); - - // var keyParams = new PbeParameters( - // PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, numberOfIterations); - // - // var privateKey = - // rsa.ExportEncryptedPkcs8PrivateKey(Encoding.UTF8.GetBytes(password), keyParams); - // - // logger?.LogInformation( - // "Private key: {}", privateKey); - - return _rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256); - } - - public byte[] DecryptDataAsync(byte[] data, byte[] privateKey) { - return _rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA256); - } - private async Task<T?> RestCall<T>(Uri uri, HttpMethod method, string body) { var client = new HttpClient(); diff --git a/SenderTest/SenderEncryptionTest.cs b/SenderTest/SenderEncryptionTest.cs new file mode 100644 index 00000000..d9435162 --- /dev/null +++ b/SenderTest/SenderEncryptionTest.cs @@ -0,0 +1,39 @@ +using System; +using System.Buffers.Text; +using System.Security.Cryptography; +using System.Text; +using FitConnect; +using FluentAssertions; +using Microsoft.Extensions.Logging; +using NUnit.Framework; + +namespace SenderTest; + +public class SenderEncryptionTest { + private Sender _sender; + private ILogger<SenderEncryptionTest> _logger; + + [SetUp] + public void Setup() { + _logger = LoggerFactory.Create(cfg => cfg.AddConsole()) + .CreateLogger<SenderEncryptionTest>(); + _sender = new Sender(_logger, + FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development)); + } + + [Test] + public void CryptWithPublicKeyImport() { + var publicKey = Convert.FromBase64String( + "MIIBCgKCAQEAzu/ek6A5AMuROs+12pncbYNteGkd6ReU28ZY5gCM4hNFI0h1E+0+OST+Yxw7zhvbFhZbYdVt8LmzonMAtENituLxzZj7MsWom/ZzxTdp4Cx5zlx8x6Qx/ZPoSS2T2Sf0ttymaMc6ZadpWsDhg/Mnf6beF1W/QoGH/bHBa8U4rhkUa+OKf3wyo08km8oyUJaj6kkB0VdhRp5rSyvXJtUMZ5A0LcYFygnkHTSQlQhdrAK+6nTo//mfNfPtqta2wBb9ONpVwN0V7I5PSdH2WxZMZsYFicLOGbNeF08gibmL+7TeBTssYtrNVM88cG0v+aWeBun0WVrpCntDIA9HIujWowIDAQAB"); + + var cypher = _sender.EncryptData(Encoding.UTF8.GetBytes("test"), publicKey); + + _logger.LogInformation("Cypher: {}", Convert.ToBase64String(cypher)); + } + + [Test] + public void ExportPrivateKey() { + var privateKey = _sender.ExportPrivateKey(); + _logger.LogInformation("Private key: {}", Convert.ToBase64String(privateKey)); + } +} diff --git a/SenderTest/UnitTest1.cs b/SenderTest/UnitTest1.cs deleted file mode 100644 index 2980ded5..00000000 --- a/SenderTest/UnitTest1.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using FitConnect; -using FluentAssertions; -using Microsoft.Extensions.Logging; -using NUnit.Framework; - -namespace SenderTest; - -public class SenderEncryptionTest { - private Sender _sender; - - [SetUp] - public void Setup() { - var logger = LoggerFactory.Create(cfg => cfg.AddConsole()) - .CreateLogger<SenderEncryptionTest>(); - _sender = new Sender(logger, - FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development)); - } - - [Test] - public void SimpleEncryptDecryptTest() { - var cypher = _sender.EncryptDataAsync( - Encoding.UTF8.GetBytes("test"), - new byte[] { - 48, 130, 1, 10, 2, 130, 1, 1, 0, 176, 201, 204, 176, 164, 201, 48, 46, 200, 253, - 162, 223, 85, 102, 238, 80, 75, 126, 38, 201, 39, 235, 90, 2, 73, 80, 136, 56, 86, - 18, 247, 249, 131, 245, 167, 21, 159, 79, 236, 173, 234, 88, 67, 114, 19, 173, 201, - 71, 66, 60, 183, 102, 123, 89, 192, 66, 154, 127, 206, 77, 212, 91, 75, 122, 15, - 100, 153, 32, 153, 48, 178, 205, 13, 189, 196, 194, 100, 140, 27, 78, 39, 245, 169, - 30, 241, 114, 168, 228, 63, 42, 31, 114, 118, 196, 136, 254, 31, 95, 105, 191, 170, - 223, 191, 120, 143, 34, 33, 177, 245, 128, 13, 108, 11, 18, 132, 8, 225, 82, 31, - 177, 37, 130, 55, 246, 111, 184, 169, 239, 212, 234, 208, 198, 19, 171, 209, 31, 26, - 104, 66, 248, 112, 55, 182, 51, 13, 68, 84, 196, 175, 124, 166, 42, 50, 172, 226, - 157, 23, 104, 114, 71, 109, 136, 6, 163, 73, 179, 20, 78, 77, 97, 2, 230, 92, 18, - 104, 70, 43, 54, 249, 235, 189, 64, 65, 138, 36, 112, 237, 96, 240, 168, 189, 113, - 250, 175, 198, 23, 200, 106, 106, 15, 234, 247, 204, 254, 199, 53, 191, 224, 195, - 163, 10, 186, 1, 10, 183, 87, 73, 185, 182, 37, 142, 195, 115, 9, 239, 226, 18, 110, - 14, 171, 177, 38, 161, 162, 198, 148, 8, 250, 224, 148, 173, 211, 72, 178, 30, 158, - 50, 225, 53, 102, 43, 133, 253, 164, 80, 127, 2, 3, 1, 0, 1 - }, "dummy", 2); - - Encoding.UTF8.GetString((_sender.DecryptDataAsync(cypher, new byte[] { }))).Should() - .Be("test"); - } -} -- GitLab