diff --git a/FitConnect/EncryptionBaseClass.cs b/FitConnect/EncryptionBaseClass.cs index 7ecb39cdec2e5c5088e13a276f0afd525ccb23e9..bdcf0ff85d7574047a049108f79cb464b597644b 100644 --- a/FitConnect/EncryptionBaseClass.cs +++ b/FitConnect/EncryptionBaseClass.cs @@ -6,7 +6,9 @@ namespace FitConnect; public class EncryptionBaseClass { private readonly ILogger _logger; - private RSA _rsa; + private readonly RSA _rsa; + private RSA? _publicKey; + private RSA? _privateKey; protected EncryptionBaseClass(ILogger logger) { _logger = logger; @@ -19,18 +21,41 @@ public class EncryptionBaseClass { /// </summary> /// <param name="cert"></param> /// <returns></returns> - private bool CheckCertificate(X509Certificate2 cert) => true; + private bool CheckCertificate(X509Certificate2 cert) => + cert.HasPrivateKey; // && cert.Verify(); + + + public void ImportCertificate(X509Certificate2 cert) { + if (!CheckCertificate(cert)) { + throw new Exception("Invalid certificate"); + } + + _publicKey = cert.GetRSAPublicKey(); + + if (_publicKey == null) + throw new Exception("Invalid certificate, no public key"); + + _logger.LogInformation("Public key imported {}", + Convert.ToBase64String(_publicKey.ExportRSAPrivateKey())); + + + if (cert.HasPrivateKey) { + _privateKey = cert.GetRSAPrivateKey(); + _logger.LogInformation("Certificate imported"); + } + } /// <summary> - /// + /// Import a public key from a PEM file /// </summary> - /// <param name="certPath"></param> + /// <param name="certificatePath"></param> + /// <param name="password">Password for the certificate</param> /// <exception cref="ArgumentException"></exception> /// <exception cref="Exception"></exception> - public void ImportCertificate(string certPath) { - _logger.LogInformation("Importing certificate {CertPath}", certPath); + public void ImportCertificate(string certificatePath, string password) { + _logger.LogInformation("Importing certificate {CertPath}", certificatePath); var cert = - new X509Certificate2(certPath, "", X509KeyStorageFlags.MachineKeySet); + new X509Certificate2(certificatePath, password, X509KeyStorageFlags.MachineKeySet); if (!CheckCertificate(cert)) { throw new ArgumentException("Certificate is not valid"); @@ -44,19 +69,8 @@ public class EncryptionBaseClass { _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[] DecryptDataAsync(byte[] data) { + return (_privateKey ?? _rsa).Decrypt(data, RSAEncryptionPadding.OaepSHA256); } public byte[] ExportPublicKey() { @@ -67,15 +81,16 @@ public class EncryptionBaseClass { return _rsa.ExportRSAPrivateKey(); } - public byte[] EncryptData(byte[] data, byte[]? publicKey) { + public byte[] EncryptData(byte[] data) { + return (_publicKey ?? _rsa).Encrypt(data, RSAEncryptionPadding.OaepSHA256); + } + + 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); - } - + _rsa.ImportRSAPublicKey(publicKey, out var read); return _rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256); } } diff --git a/SenderTest/SenderEncryptionTest.cs b/SenderTest/SenderEncryptionTest.cs index 768b0f0937793c06d3fe9d43e5176f27ecc767d0..ac3409a4b8e05e668b2a22998c08e75929742764 100644 --- a/SenderTest/SenderEncryptionTest.cs +++ b/SenderTest/SenderEncryptionTest.cs @@ -1,19 +1,22 @@ using System; -using System.Buffers.Text; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; 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; +public partial class SenderEncryptionTest { + private Sender _sender = null!; + private ILogger<SenderEncryptionTest> _logger = null!; + + /* + * Encryption test must be changed for production to only allow extern signed certificates + * and forbid self-signed certificates. + */ [SetUp] public void Setup() { @@ -21,26 +24,21 @@ public class SenderEncryptionTest { .CreateLogger<SenderEncryptionTest>(); _sender = new Sender(_logger, FitConnectEndpoints.Create(FitConnectEndpoints.EndpointType.Development)); + var certificate = CreateSelfSignedCertificate(null); + // _sender.ImportCertificate(certificate); } - private X509Certificate2 CreateSelfSignedCertificate() { - var req = new CertificateRequest("cn=foobar", ECDsa.Create(), HashAlgorithmName.SHA256); - var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5)); - - // Create PFX (PKCS #12) with private key - File.WriteAllBytes("../../../mycert.pfx", cert.Export(X509ContentType.Pfx, "P@55w0rd")); - // Create Base 64 encoded CER (public key only) - File.WriteAllText("../../../mycert.cer", - "-----BEGIN CERTIFICATE-----\r\n" - + Convert.ToBase64String(cert.Export(X509ContentType.Cert), - Base64FormattingOptions.InsertLineBreaks) - + "\r\n-----END CERTIFICATE-----"); + [Test] + public void CryptWithOutPublicKeyImport() { + var cypher = _sender.EncryptData(Encoding.UTF8.GetBytes("test")); - return cert; + _logger.LogInformation("Cypher: {}", Convert.ToBase64String(cypher)); } + [Test] + [Ignore("Not applicable for production")] public void CryptWithPublicKeyImport() { var publicKey = Convert.FromBase64String( "MIIBCgKCAQEAzu/ek6A5AMuROs+12pncbYNteGkd6ReU28ZY5gCM4hNFI0h1E+0+OST+Yxw7zhvbFhZbYdVt8LmzonMAtENituLxzZj7MsWom/ZzxTdp4Cx5zlx8x6Qx/ZPoSS2T2Sf0ttymaMc6ZadpWsDhg/Mnf6beF1W/QoGH/bHBa8U4rhkUa+OKf3wyo08km8oyUJaj6kkB0VdhRp5rSyvXJtUMZ5A0LcYFygnkHTSQlQhdrAK+6nTo//mfNfPtqta2wBb9ONpVwN0V7I5PSdH2WxZMZsYFicLOGbNeF08gibmL+7TeBTssYtrNVM88cG0v+aWeBun0WVrpCntDIA9HIujWowIDAQAB"); @@ -56,3 +54,38 @@ public class SenderEncryptionTest { _logger.LogInformation("Private key: {}", Convert.ToBase64String(privateKey)); } } + +#region Static helpers + +public partial class SenderEncryptionTest { + private X509Certificate2 CreateSelfSignedCertificate(string? exportPath = "../../../") { + var req = new CertificateRequest("cn=foobar", ECDsa.Create(), HashAlgorithmName.SHA256); + var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5)); + + // Export the certificate to a PEM file, just for + // additional extern testing + if (exportPath != null) { + ExportCertificateToFile(exportPath, cert); + } + + return cert; + } + + private void ExportCertificateToFile(string exportPath, X509Certificate cert) { + // Create PFX (PKCS #12) with private key + File.WriteAllBytes($"{exportPath}/certificate.pfx", + cert.Export(X509ContentType.Pfx, "")); + + // Create Base 64 encoded CER (public key only) + File.WriteAllText($"{exportPath}/certificate.cer", + "-----BEGIN CERTIFICATE-----\r\n" + + Convert.ToBase64String(cert.Export(X509ContentType.Cert, ""), + Base64FormattingOptions.InsertLineBreaks) + + "\r\n-----END CERTIFICATE-----"); + + _logger?.LogInformation("Exporting {}", + Convert.ToBase64String(cert.Export(X509ContentType.Cert, ""))); + } +} + +#endregion