diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bd7316e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +bin/ +obj/ +.git/ +*.txt # If you want to exclude all .txt files +run_codecoverage.txt # Exclude this specific file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f1bc1a..e8613aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,8 +6,8 @@ on: - "main" - "version3" - "feature/*" - - "bugfix/*" - - "hotfix/*" + - "bugfix/*" + - "hotfix/*" - "!feature/ci*" paths-ignore: - "**/README.md" diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index e249474..8300ff6 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -1,68 +1,68 @@ -# name: "Code Coverage" +name: "Code Coverage" -# on: -# push: -# branches: -# - "main" -# - "version3" -# - "feature/*" -# - "bugfix/*" -# - "hotfix/*" +on: + push: + branches: + - "main" + - "version3" + - "feature/*" + - "bugfix/*" + - "hotfix/*" -# jobs: -# build: -# runs-on: ubuntu-latest +jobs: + build: + runs-on: ubuntu-latest -# steps: -# - name: Checkout repository -# uses: actions/checkout@v4 + steps: + - name: Checkout repository + uses: actions/checkout@v4 -# - name: Setup .NET -# uses: actions/setup-dotnet@v4 -# with: -# dotnet-version: 8.0.x + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x -# - name: Install ReportGenerator tool -# run: dotnet tool install --global dotnet-reportgenerator-globaltool + - name: Install ReportGenerator tool + run: dotnet tool install --global dotnet-reportgenerator-globaltool -# - name: Restore dependencies -# run: dotnet restore + - name: Restore dependencies + run: dotnet restore -# - name: Build the solution -# run: dotnet build --no-restore + - name: Build the solution + run: dotnet build --no-restore -# - name: Run tests and collect code coverage -# run: dotnet test --no-build --collect:"XPlat Code Coverage" + - name: Run tests and collect code coverage + run: dotnet test --no-build --collect:"XPlat Code Coverage" -# - name: Generate code coverage report -# run: reportgenerator -reports:"**/coverage.cobertura.xml" -targetdir:"coverage" -reporttypes:"HtmlInline_AzurePipelines;Badges" + - name: Generate code coverage report + run: reportgenerator -reports:"**/coverage.cobertura.xml" -targetdir:"coverage" -reporttypes:"HtmlInline_AzurePipelines;Badges" -# - name: Upload coverage report -# uses: actions/upload-artifact@v4 -# with: -# name: code-coverage-report -# path: coverage + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: code-coverage-report + path: coverage -# - name: Upload coverage badge -# uses: actions/upload-artifact@v4 -# with: -# name: code-coverage-badge -# path: coverage/badge_linecoverage.svg + - name: Upload coverage badge + uses: actions/upload-artifact@v4 + with: + name: code-coverage-badge + path: coverage/badge_linecoverage.svg -# - name: Create coverage badge -# run: cp coverage/badge_linecoverage.svg ./coverage-badge.svg + - name: Create coverage badge + run: cp coverage/badge_linecoverage.svg ./coverage-badge.svg -# - name: Print Directory Structure -# uses: FiorelaCiroku/XDTesting-Print-Directory-Structure@v1.0.2 + - name: Print Directory Structure + uses: FiorelaCiroku/XDTesting-Print-Directory-Structure@v1.0.2 -# - name: Commit coverage badge -# run: | -# git config --global user.name 'github-actions[bot]' -# git config --global user.email 'github-actions[bot]@users.noreply.github.com' -# git add coverage-badge.svg -# if git diff-index --cached --name-only HEAD | grep -vsxF coverage-badge.svg; then -# git commit -m 'Update coverage badge' -# git push -# fi -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Commit coverage badge + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git add coverage-badge.svg + if git diff-index --cached --name-only HEAD | grep -vsxF coverage-badge.svg; then + git commit -m 'Update coverage badge' + git push + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CryptoNet.Share/Common.cs b/CryptoNet.Share/Common.cs index 20398aa..fdf7528 100644 --- a/CryptoNet.Share/Common.cs +++ b/CryptoNet.Share/Common.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; using System.Text; using CryptoNet.Share.Extensions; @@ -17,13 +18,9 @@ public static class Common public static readonly string RsaStoredKeyPair = Path.Combine(RsaKeysPath, "RsaKeys"); public static readonly string EncryptedContentFile = Path.Combine(RsaKeysPath, "encrypted.txt"); - public static readonly string PrivateKeyFile = Path.Combine(RsaKeysPath, "privateKey"); - public static readonly string PublicKeyFile = Path.Combine(RsaKeysPath, "publicKey.pub"); public static readonly string[] DummyFiles = [ - EncryptedContentFile, - PublicKeyFile, - PrivateKeyFile + EncryptedContentFile ]; #region Private methods @@ -46,5 +43,40 @@ public static string CalculateMd5(string content) var hash = MD5.HashData(Encoding.UTF8.GetBytes(content)); return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } + + public static string UniqueKeyGenerator(string input) + { + byte[] inputBytes = Encoding.ASCII.GetBytes(input); + byte[] hashBytes = MD5.HashData(inputBytes); + + var stringBuilder = new StringBuilder(); + foreach (var byteValue in hashBytes) + { + stringBuilder.Append(byteValue.ToString("X2")); + } + return stringBuilder.ToString(); + } + + public static char[] ExportPemKey(X509Certificate2 cert, bool privateKey = true) + { + AsymmetricAlgorithm rsa = cert.GetRSAPrivateKey()!; + + if (privateKey) + { + byte[] priKeyBytes = rsa.ExportPkcs8PrivateKey(); + return PemEncoding.Write("PRIVATE KEY", priKeyBytes); + } + + byte[] pubKeyBytes = rsa.ExportSubjectPublicKeyInfo(); + return PemEncoding.Write("PUBLIC KEY", pubKeyBytes); + } + + public static byte[] ExportPemKeyWithPassword(X509Certificate2 cert, string password) + { + AsymmetricAlgorithm rsa = cert.GetRSAPrivateKey()!; + byte[] pass = Encoding.UTF8.GetBytes(password); + return rsa.ExportEncryptedPkcs8PrivateKey(pass, + new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, iterationCount: 100_000)); + } #endregion } diff --git a/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj b/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj index 8c334c5..c79f0b4 100644 --- a/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj +++ b/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj @@ -33,12 +33,6 @@ Always - - Always - - - Always - Always diff --git a/CryptoNet.UnitTests/CryptoNetAesTests.cs b/CryptoNet.UnitTests/CryptoNetAesTests.cs index c058de3..66ade72 100644 --- a/CryptoNet.UnitTests/CryptoNetAesTests.cs +++ b/CryptoNet.UnitTests/CryptoNetAesTests.cs @@ -31,7 +31,6 @@ namespace CryptoNet.UnitTests; [TestFixture] public class CryptoNetAesTests { - private const string ConfidentialData = @"Some Secret Data"; private static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory; private static readonly string SymmetricKeyFile = Path.Combine(BaseFolder, $"{KeyType.SymmetricKey}.xml"); private static readonly byte[] symmetricKey = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315a1916"); @@ -46,11 +45,11 @@ public void Encrypt_And_Decrypt_With_SymmetricKey_Test() var cryptoNetAes = new CryptoNetAes(symmetricKey, iv); // Act - var encryptedData = cryptoNetAes.EncryptFromString(ConfidentialData); + var encryptedData = cryptoNetAes.EncryptFromString(Common.ConfidentialDummyData); var decryptedData = cryptoNetAes.DecryptToString(encryptedData); // Assert - ConfidentialData.ShouldBe(decryptedData); + Common.ConfidentialDummyData.ShouldBe(decryptedData); cryptoNetAes.Info.KeyType.ShouldBe(KeyType.SymmetricKey); cryptoNetAes.Info.KeyType.ShouldNotBe(KeyType.PublicKey); cryptoNetAes.Info.KeyType.ShouldNotBe(KeyType.PrivateKey); @@ -66,7 +65,7 @@ public void Encrypt_And_Decrypt_With_Wrong_SymmetricKey_Should_Throw_Exception() var wrongKey = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315b1916"); var iv = new byte[16]; var cryptoNetAes = new CryptoNetAes(correctKey, iv); - var encryptedData = cryptoNetAes.EncryptFromString(ConfidentialData); + var encryptedData = cryptoNetAes.EncryptFromString(Common.ConfidentialDummyData); // Act & Assert Assert.Throws(() => @@ -123,11 +122,11 @@ public void Encrypt_And_Decrypt_Content_With_SelfGenerated_SymmetricKey_Test() var cryptoNetAes = new CryptoNetAes(key); // Act - var encryptedData = cryptoNetAes.EncryptFromString(ConfidentialData); + var encryptedData = cryptoNetAes.EncryptFromString(Common.ConfidentialDummyData); var decryptedData = cryptoNetAes.DecryptToString(encryptedData); // Assert - ConfidentialData.ShouldBe(decryptedData); + Common.ConfidentialDummyData.ShouldBe(decryptedData); } [Test] @@ -139,12 +138,12 @@ public void SelfGenerated_And_Save_SymmetricKey_Test() // Act cryptoNet.SaveKey(file); - var encryptedData = cryptoNet.EncryptFromString(ConfidentialData); + var encryptedData = cryptoNet.EncryptFromString(Common.ConfidentialDummyData); var decryptedData = new CryptoNetAes(file).DecryptToString(encryptedData); // Assert File.Exists(file.FullName).ShouldBeTrue(); - ConfidentialData.ShouldBe(decryptedData); + Common.ConfidentialDummyData.ShouldBe(decryptedData); } [Test] @@ -158,43 +157,29 @@ public void Encrypt_And_Decrypt_Content_With_Own_SymmetricKey_Test() var cryptoNetAes = new CryptoNetAes(keyBytes, ivBytes); // Act - var encryptedData = cryptoNetAes.EncryptFromString(ConfidentialData); + var encryptedData = cryptoNetAes.EncryptFromString(Common.ConfidentialDummyData); var decryptedData = cryptoNetAes.DecryptToString(encryptedData); // Assert - ConfidentialData.ShouldBe(decryptedData); + Common.ConfidentialDummyData.ShouldBe(decryptedData); } [Test] public void Encrypt_And_Decrypt_With_Human_Readable_Key_And_Secret_SymmetricKey_Test() { // Arrange - var key = UniqueKeyGenerator("symmetricKey"); - var iv = new string(UniqueKeyGenerator("password").Take(16).ToArray()); + var key = Common.UniqueKeyGenerator("symmetricKey"); + var iv = new string(Common.UniqueKeyGenerator("password").Take(16).ToArray()); var keyBytes = Encoding.UTF8.GetBytes(key); var ivBytes = Encoding.UTF8.GetBytes(iv); var cryptoNetAes = new CryptoNetAes(keyBytes, ivBytes); // Act - var encryptedData = cryptoNetAes.EncryptFromString(ConfidentialData); + var encryptedData = cryptoNetAes.EncryptFromString(Common.ConfidentialDummyData); var decryptedData = cryptoNetAes.DecryptToString(encryptedData); // Assert - ConfidentialData.ShouldBe(decryptedData); - } - - // Helper method - private static string UniqueKeyGenerator(string input) - { - byte[] inputBytes = Encoding.ASCII.GetBytes(input); - byte[] hashBytes = MD5.HashData(inputBytes); - - var stringBuilder = new StringBuilder(); - foreach (var byteValue in hashBytes) - { - stringBuilder.Append(byteValue.ToString("X2")); - } - return stringBuilder.ToString(); + Common.ConfidentialDummyData.ShouldBe(decryptedData); } [Test] @@ -231,6 +216,5 @@ public void DecryptContent_Throws_ArgumentNullException() Assert.Throws(() => encoder.DecryptToBytes(null!)); Assert.Throws(() => encoder.DecryptToBytes(new byte[0])); } - } diff --git a/CryptoNet.UnitTests/CryptoNetRsaTests.cs b/CryptoNet.UnitTests/CryptoNetRsaTests.cs index 87f1f9a..e3f5935 100644 --- a/CryptoNet.UnitTests/CryptoNetRsaTests.cs +++ b/CryptoNet.UnitTests/CryptoNetRsaTests.cs @@ -31,44 +31,54 @@ namespace CryptoNet.UnitTests; [TestFixture] public class CryptoNetRsaTests { - private const string ConfidentialData = @"Some Secret Data"; private static readonly string BaseFolder = AppContext.BaseDirectory; - private static readonly string PrivateKeyFile = Path.Combine(BaseFolder, "privateKey"); private static readonly string PublicKeyFile = Path.Combine(BaseFolder, "publicKey.pub"); - [Test] - public void SelfGenerated_AsymmetricKey_And_TypeValidation_Test() + public CryptoNetRsaTests() { ICryptoNetRsa cryptoNet = new CryptoNetRsa(); + cryptoNet.SaveKey(new FileInfo(PrivateKeyFile), true); + cryptoNet.SaveKey(new FileInfo(PublicKeyFile), false); + } - cryptoNet.SaveKey(new FileInfo(Common.PrivateKeyFile), true); - cryptoNet.SaveKey(new FileInfo(Common.PublicKeyFile), false); + [Test] + public void SelfGenerated_AsymmetricKey_And_TypeValidation_Test() + { + // Arrange & Act + var privateKeyCrypto = new CryptoNetRsa(new FileInfo(PrivateKeyFile)); + var publicKeyCrypto = new CryptoNetRsa(new FileInfo(PublicKeyFile)); - new CryptoNetRsa(new FileInfo(Common.PrivateKeyFile)).Info.KeyType.ShouldBe(KeyType.PrivateKey); - new CryptoNetRsa(new FileInfo(Common.PublicKeyFile)).Info.KeyType.ShouldBe(KeyType.PublicKey); + // Assert + privateKeyCrypto.Info.KeyType.ShouldBe(KeyType.PrivateKey); + publicKeyCrypto.Info.KeyType.ShouldBe(KeyType.PublicKey); } [Test] public void Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey_Test() { + // Arrange ICryptoNetRsa cryptoNet = new CryptoNetRsa(); var privateKey = cryptoNet.GetKey(true); var publicKey = cryptoNet.GetKey(false); + // Act var encrypt = new CryptoNetRsa(publicKey).EncryptFromString(Common.ConfidentialDummyData); var decrypt = new CryptoNetRsa(privateKey).DecryptToString(encrypt); + // Assert Common.CheckContent(Common.ConfidentialDummyData, decrypt).ShouldBeTrue(); } [Test] public void Encrypt_Decrypt_Content_With_Invalid_AsymmetricKey_Test() { + // Arrange var encrypt = new CryptoNetRsa().EncryptFromString(Common.ConfidentialDummyData); - const string invalidKey = "invalid-key"; string decrypt = string.Empty; + + // Act & Assert try { decrypt = new CryptoNetRsa(invalidKey).DecryptToString(encrypt); @@ -83,16 +93,17 @@ public void Encrypt_Decrypt_Content_With_Invalid_AsymmetricKey_Test() [Test] public void Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test() { + // Arrange ICryptoNetRsa cryptoNet = new CryptoNetRsa(); var encrypt = cryptoNet.EncryptFromString(Common.ConfidentialDummyData); File.WriteAllBytes(Common.EncryptedContentFile, encrypt); + // Act var encryptFile = File.ReadAllBytes(Common.EncryptedContentFile); var content = cryptoNet.DecryptToString(encryptFile); + // Assert Common.CheckContent(Common.ConfidentialDummyData, content).ShouldBeTrue(); - - Common.DeleteTestFiles(Common.DummyFiles); } [TestCase("test.docx"), Order(5)] @@ -101,49 +112,45 @@ public void Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey_That_Is_Sto [TestCase("test.pdf")] public void Encrypt_Decrypt_Documents_With_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test(string filename) { + // Arrange var testDocument = File.ReadAllBytes(Path.Combine(Common.TestFilesPath, filename)); + var encrypt = new CryptoNetRsa(new FileInfo(PublicKeyFile)).EncryptFromBytes(testDocument); - ICryptoNetRsa cryptoNet = new CryptoNetRsa(); - cryptoNet.SaveKey(new FileInfo(Common.PrivateKeyFile), true); - cryptoNet.SaveKey(new FileInfo(Common.PublicKeyFile), false); - - // arrange - var encrypt = new CryptoNetRsa(new FileInfo(Common.PublicKeyFile)).EncryptFromBytes(testDocument); - - // act - var decrypt = new CryptoNetRsa(new FileInfo(Common.PrivateKeyFile)).DecryptToBytes(encrypt); + // Act + var decrypt = new CryptoNetRsa(new FileInfo(PrivateKeyFile)).DecryptToBytes(encrypt); - // assert + // Assert ClassicAssert.AreEqual(testDocument, decrypt); } [Test] public void Encrypt_Decrypt_Content_With_PreStored_SelfGenerated_AsymmetricKey_Test() { + // Arrange ICryptoNetRsa cryptoNet = new CryptoNetRsa(new FileInfo(Common.RsaStoredKeyPair)); + // Act var encrypt = cryptoNet.EncryptFromString(Common.ConfidentialDummyData); var content = cryptoNet.DecryptToString(encrypt); - Common.CheckContent(Common.ConfidentialDummyData, content); + // Assert + Common.CheckContent(Common.ConfidentialDummyData, content).ShouldBeTrue(); } [Test] public void Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Using_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test() { + // Arrange var certificate = new FileInfo(Common.RsaStoredKeyPair); + new CryptoNetRsa(certificate).SaveKey(new FileInfo(PublicKeyFile), false); - // Export public key - new CryptoNetRsa(certificate).SaveKey(new FileInfo(Common.PublicKeyFile), false); - - // Import public key and encrypt - var importPublicKey = new FileInfo(Common.PublicKeyFile); - + // Act + var importPublicKey = new FileInfo(PublicKeyFile); var encryptWithPublicKey = new CryptoNetRsa(importPublicKey).EncryptFromString(Common.ConfidentialDummyData); var decryptWithPrivateKey = new CryptoNetRsa(certificate).DecryptToString(encryptWithPublicKey); - Common.CheckContent(Common.ConfidentialDummyData, decryptWithPrivateKey); - + // Assert + Common.CheckContent(Common.ConfidentialDummyData, decryptWithPrivateKey).ShouldBeTrue(); Common.DeleteTestFiles(Common.DummyFiles); } @@ -153,41 +160,31 @@ public void Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Using_SelfGenerated_A [TestCase("test.pdf")] public void Validate_Decrypted_File_Against_The_Original_File_By_Comparing_Bytes_Test(string filename) { - // arrange + // Arrange var certificate = new FileInfo(Common.RsaStoredKeyPair); - // Export public key ICryptoNetRsa cryptoNet = new CryptoNetRsa(certificate); - var filePath = Path.Combine(Common.TestFilesPath, filename); byte[] originalFileBytes = File.ReadAllBytes(filePath); + + // Act byte[] encryptedBytes = cryptoNet.EncryptFromBytes(originalFileBytes); byte[] decryptedBytes = cryptoNet.DecryptToBytes(encryptedBytes); + // Assert var isIdenticalFile = CryptoNetExtensions.ByteArrayCompare(originalFileBytes, decryptedBytes); - isIdenticalFile.ShouldBeTrue(); } [Test] - public void SelfGenerated_And_Save_AsymmetricKey_Test() + public void Control_SelfGenerated_Exist_AsymmetricKey_Test() { - // Arrange - var cryptoNet = new CryptoNetRsa(); - - // Act - cryptoNet.SaveKey(new FileInfo(PrivateKeyFile), true); - cryptoNet.SaveKey(new FileInfo(PublicKeyFile), false); - + // Arrange & Act var fileExistsPrivateKey = File.Exists(new FileInfo(PrivateKeyFile).FullName); var fileExistsPublicKey = File.Exists(new FileInfo(PublicKeyFile).FullName); - var encryptedData = new CryptoNetRsa(new FileInfo(PublicKeyFile)).EncryptFromString(ConfidentialData); - var decryptedData = new CryptoNetRsa(new FileInfo(PrivateKeyFile)).DecryptToString(encryptedData); - // Assert fileExistsPrivateKey.ShouldBeTrue(); fileExistsPublicKey.ShouldBeTrue(); - ConfidentialData.ShouldBe(decryptedData); } [Test] @@ -198,11 +195,11 @@ public void Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Of_Content_Test() var privateKeyRsa = new CryptoNetRsa(new FileInfo(PrivateKeyFile)); // Act - var encryptedData = publicKeyRsa.EncryptFromString(ConfidentialData); + var encryptedData = publicKeyRsa.EncryptFromString(Common.ConfidentialDummyData); var decryptedData = privateKeyRsa.DecryptToString(encryptedData); // Assert - ConfidentialData.ShouldBe(decryptedData); + Common.ConfidentialDummyData.ShouldBe(decryptedData); } [Ignore("Private")] @@ -214,15 +211,15 @@ public void Encrypt_Decrypt_Using_X509_Certificate_Test() var rsaPrivateKey = new CryptoNetRsa(certificate, KeyType.PrivateKey); // Act - var encryptedData = rsaPublicKey.EncryptFromString(ConfidentialData); + var encryptedData = rsaPublicKey.EncryptFromString(Common.ConfidentialDummyData); var decryptedData = rsaPrivateKey.DecryptToString(encryptedData); // Assert - ConfidentialData.ShouldBe(decryptedData); + Common.ConfidentialDummyData.ShouldBe(decryptedData); } - [Test] + [Ignore("Private")] public void Export_Public_Key_For_X509_Certificate_Test() { // Arrange @@ -243,61 +240,38 @@ public void Customize_PEM_Key_Encryption_Decryption_Test() // Arrange X509Certificate2? cert = CryptoNetExtensions.GetCertificateFromStore("CN=Maytham"); - var pubKeyPem = ExportPemKey(cert!, false); - var priKeyPem = ExportPemKey(cert!); + var pubKeyPem = Common.ExportPemKey(cert!, false); + var priKeyPem = Common.ExportPemKey(cert!); var password = "password"; - var encryptedPriKeyBytes = ExportPemKeyWithPassword(cert!, password); + var encryptedPriKeyBytes = Common.ExportPemKeyWithPassword(cert!, password); // Act ICryptoNetRsa cryptoNet1 = ImportPemKeyWithPassword(encryptedPriKeyBytes, password); - var encryptedData1 = cryptoNet1.EncryptFromString(ConfidentialData); + var encryptedData1 = cryptoNet1.EncryptFromString(Common.ConfidentialDummyData); ICryptoNetRsa cryptoNet2 = ImportPemKey(pubKeyPem); - var encryptedData2 = cryptoNet2.EncryptFromString(ConfidentialData); + var encryptedData2 = cryptoNet2.EncryptFromString(Common.ConfidentialDummyData); ICryptoNetRsa cryptoNet3 = ImportPemKey(priKeyPem); var decryptedData1 = cryptoNet3.DecryptToString(encryptedData1); var decryptedData2 = cryptoNet3.DecryptToString(encryptedData2); // Assert - ConfidentialData.ShouldBe(decryptedData1); - ConfidentialData.ShouldBe(decryptedData2); + Common.ConfidentialDummyData.ShouldBe(decryptedData1); + Common.ConfidentialDummyData.ShouldBe(decryptedData2); } - private static char[] ExportPemKey(X509Certificate2 cert, bool privateKey = true) - { - AsymmetricAlgorithm rsa = cert.GetRSAPrivateKey()!; - - if (privateKey) - { - byte[] priKeyBytes = rsa.ExportPkcs8PrivateKey(); - return PemEncoding.Write("PRIVATE KEY", priKeyBytes); - } - - byte[] pubKeyBytes = rsa.ExportSubjectPublicKeyInfo(); - return PemEncoding.Write("PUBLIC KEY", pubKeyBytes); - } - - private static ICryptoNetRsa ImportPemKey(char[] key) + public static ICryptoNetRsa ImportPemKey(char[] key) { ICryptoNetRsa cryptoNet = new CryptoNetRsa(); cryptoNet.Info.RsaDetail!.Rsa?.ImportFromPem(key); return cryptoNet; } - private static byte[] ExportPemKeyWithPassword(X509Certificate2 cert, string password) - { - AsymmetricAlgorithm rsa = cert.GetRSAPrivateKey()!; - byte[] pass = Encoding.UTF8.GetBytes(password); - return rsa.ExportEncryptedPkcs8PrivateKey(pass, - new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, iterationCount: 100_000)); - } - - private static ICryptoNetRsa ImportPemKeyWithPassword(byte[] encryptedPrivateKey, string password) + public static ICryptoNetRsa ImportPemKeyWithPassword(byte[] encryptedPrivateKey, string password) { ICryptoNetRsa cryptoNet = new CryptoNetRsa(); cryptoNet.Info.RsaDetail?.Rsa?.ImportEncryptedPkcs8PrivateKey(password, encryptedPrivateKey, out _); return cryptoNet; } - }