diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5c5618..3e2352e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,3 +33,5 @@ jobs: run: dotnet test --configuration Release --no-build - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/CryptoNet.Cli/CryptoNet.Cli.csproj b/CryptoNet.Cli/CryptoNet.Cli.csproj index 757acc1..1e1da6a 100644 --- a/CryptoNet.Cli/CryptoNet.Cli.csproj +++ b/CryptoNet.Cli/CryptoNet.Cli.csproj @@ -1,8 +1,8 @@ - + Exe - net6.0 + net7.0 enable enable @@ -11,4 +11,19 @@ + + + Always + + + Always + + + Always + + + Always + + + diff --git a/CryptoNet.Cli/ExampleAes.cs b/CryptoNet.Cli/ExampleAes.cs index bbe07f4..328c737 100644 --- a/CryptoNet.Cli/ExampleAes.cs +++ b/CryptoNet.Cli/ExampleAes.cs @@ -9,111 +9,127 @@ using System.Security.Cryptography; using System.Text; using CryptoNet.Models; +using CryptoNet.Utils; -namespace CryptoNet.Cli; - -public class ExampleAes +namespace CryptoNet.Cli { - private const string ConfidentialDummyData = @"Some Secret Data"; - - private static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory; - private static readonly string SymmetricKeyFile = Path.Combine(BaseFolder, $"{KeyType.SymmetricKey}.xml"); - public static void Test() + public class ExampleAes { - Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_SymmetricKey(); - Example_2_SelfGenerated_And_Save_SymmetricKey(); - Example_3_Encrypt_Decrypt_Content_With_Own_SymmetricKey(); - Example_4_Encrypt_Decrypt_Content_With_Human_Readable_Key_Secret_SymmetricKey(); - } + protected ExampleAes() { } - public static void Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_SymmetricKey() - { - ICryptoNet cryptoNet = new CryptoNetAes(); - var key = cryptoNet.ExportKey(); + private const string ConfidentialDummyData = @"Some Secret Data"; - ICryptoNet encryptClient = new CryptoNetAes(key); - var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); + private static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory; + private readonly static string SymmetricKeyFile = Path.Combine(BaseFolder, $"{KeyType.SymmetricKey}.xml"); - ICryptoNet decryptClient = new CryptoNetAes(key); - var decrypt = decryptClient.DecryptToString(encrypt); + public static void Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_SymmetricKey() + { + ICryptoNet cryptoNet = new CryptoNetAes(); + var key = cryptoNet.ExportKey(); - Debug.Assert(ConfidentialDummyData == decrypt); - } + ICryptoNet encryptClient = new CryptoNetAes(key); + var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); - public static void Example_2_SelfGenerated_And_Save_SymmetricKey() - { - ICryptoNet cryptoNet = new CryptoNetAes(); - var file = new FileInfo(SymmetricKeyFile); - cryptoNet.ExportKeyAndSave(file); + ICryptoNet decryptClient = new CryptoNetAes(key); + var decrypt = decryptClient.DecryptToString(encrypt); - Debug.Assert(File.Exists(file.FullName)); + Debug.Assert(ConfidentialDummyData == decrypt); + } - var encrypt = cryptoNet.EncryptFromString(ConfidentialDummyData); - - ICryptoNet cryptoNetKeyImport = new CryptoNetAes(file); - var decrypt = cryptoNetKeyImport.DecryptToString(encrypt); + public static void Example_2_SelfGenerated_And_Save_SymmetricKey() + { + ICryptoNet cryptoNet = new CryptoNetAes(); + var file = new FileInfo(SymmetricKeyFile); + cryptoNet.ExportKeyAndSave(file); - Debug.Assert(ConfidentialDummyData == decrypt); - } + Debug.Assert(File.Exists(file.FullName)); - public static void Example_3_Encrypt_Decrypt_Content_With_Own_SymmetricKey() - { - var symmetricKey = "12345678901234567890123456789012"; - if (symmetricKey.Length != 32) - { - Console.WriteLine("key should be 32 character long"); - Environment.Exit(0); + var encrypt = cryptoNet.EncryptFromString(ConfidentialDummyData); + + ICryptoNet cryptoNetKeyImport = new CryptoNetAes(file); + var decrypt = cryptoNetKeyImport.DecryptToString(encrypt); + + Debug.Assert(ConfidentialDummyData == decrypt); } - var secret = "1234567890123456"; - if (secret.Length != 16) + public static void Example_3_Encrypt_Decrypt_Content_With_Own_SymmetricKey() { - Console.WriteLine("key should be 16 character long"); - Environment.Exit(1); + var symmetricKey = "12345678901234567890123456789012"; + if (symmetricKey.Length != 32) + { + Console.WriteLine("key should be 32 character long"); + Environment.Exit(0); + } + + var secret = "1234567890123456"; + if (secret.Length != 16) + { + Console.WriteLine("key should be 16 character long"); + Environment.Exit(1); + } + + var key = Encoding.UTF8.GetBytes(symmetricKey); + var iv = Encoding.UTF8.GetBytes(secret); + + ICryptoNet encryptClient = new CryptoNetAes(key, iv); + var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); + + ICryptoNet decryptClient = new CryptoNetAes(key, iv); + var decrypt = decryptClient.DecryptToString(encrypt); + + Debug.Assert(ConfidentialDummyData == decrypt); } - var key = Encoding.UTF8.GetBytes(symmetricKey); - var iv = Encoding.UTF8.GetBytes(secret); + public static void Example_4_Encrypt_Decrypt_Content_With_Human_Readable_Key_Secret_SymmetricKey() + { + var symmetricKey = UniqueKeyGenerator("symmetricKey"); + var secret = new string(UniqueKeyGenerator("password").Take(16).ToArray()); - ICryptoNet encryptClient = new CryptoNetAes(key, iv); - var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); + var key = Encoding.UTF8.GetBytes(symmetricKey); + var iv = Encoding.UTF8.GetBytes(secret); - ICryptoNet decryptClient = new CryptoNetAes(key, iv); - var decrypt = decryptClient.DecryptToString(encrypt); + ICryptoNet encryptClient = new CryptoNetAes(key, iv); + var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); - Debug.Assert(ConfidentialDummyData == decrypt); - } + ICryptoNet decryptClient = new CryptoNetAes(key, iv); + var decrypt = decryptClient.DecryptToString(encrypt); - public static void Example_4_Encrypt_Decrypt_Content_With_Human_Readable_Key_Secret_SymmetricKey() - { - var symmetricKey = UniqueKeyGenerator("symmetricKey"); - var secret = new string(UniqueKeyGenerator("password").Take(16).ToArray()); + Debug.Assert(ConfidentialDummyData == decrypt); + } - var key = Encoding.UTF8.GetBytes(symmetricKey); - var iv = Encoding.UTF8.GetBytes(secret); + public static void Example_5_Encrypt_And_Decrypt_PdfFile_With_SymmetricKey_Test(string filename) + { + ICryptoNet cryptoNet = new CryptoNetAes(); + var key = cryptoNet.ExportKey(); - ICryptoNet encryptClient = new CryptoNetAes(key, iv); - var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); + FileInfo fi = new FileInfo(filename); - ICryptoNet decryptClient = new CryptoNetAes(key, iv); - var decrypt = decryptClient.DecryptToString(encrypt); + ICryptoNet encryptClient = new CryptoNetAes(key); + string pdfFilePath = Path.Combine(BaseFolder, filename); + byte[] pdfFileBytes = File.ReadAllBytes(pdfFilePath); + var encrypt = encryptClient.EncryptFromBytes(pdfFileBytes); - Debug.Assert(ConfidentialDummyData == decrypt); - } + ICryptoNet decryptClient = new CryptoNetAes(key); + var decrypt = decryptClient.DecryptToBytes(encrypt); + string pdfDecryptedFilePath = $"TestFiles\\{Path.GetFileNameWithoutExtension(fi.Name)}-decrypted.{fi.Extension}"; + File.WriteAllBytes(pdfDecryptedFilePath, decrypt); - public static string UniqueKeyGenerator(string input) - { - MD5 md5 = MD5.Create(); - byte[] inputBytes = Encoding.ASCII.GetBytes(input); - byte[] hash = md5.ComputeHash(inputBytes); + var isIdenticalFile = CryptoNetUtils.ByteArrayCompare(pdfFileBytes, decrypt); + Debug.Assert(isIdenticalFile); + } - StringBuilder sb = new StringBuilder(); - foreach (var t in hash) + public static string UniqueKeyGenerator(string input) { - sb.Append(t.ToString("X2")); + byte[] inputBytes = Encoding.ASCII.GetBytes(input); + byte[] hash = MD5.HashData(inputBytes); + + StringBuilder sb = new StringBuilder(); + foreach (var t in hash) + { + sb.Append(t.ToString("X2")); + } + return sb.ToString(); } - return sb.ToString(); } - -} +} \ No newline at end of file diff --git a/CryptoNet.Cli/ExampleRsa.cs b/CryptoNet.Cli/ExampleRsa.cs index 9b2fcb5..2a0c031 100644 --- a/CryptoNet.Cli/ExampleRsa.cs +++ b/CryptoNet.Cli/ExampleRsa.cs @@ -12,170 +12,164 @@ using CryptoNet.Models; using CryptoNet.Utils; -namespace CryptoNet.Cli; - -public class ExampleRsa +namespace CryptoNet.Cli { - private const string ConfidentialDummyData = @"Some Secret Data"; - private static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory; + public class ExampleRsa + { + protected ExampleRsa() { } - internal static string PrivateKeyFile = Path.Combine(BaseFolder, "privateKey"); - internal static string PublicKeyFile = Path.Combine(BaseFolder, "publicKey.pub"); + private const string ConfidentialDummyData = @"Some Secret Data"; - public static void Test() - { - Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey(); - Example_2_SelfGenerated_And_Save_AsymmetricKey(); - Example_3_Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Of_Content(); - Example_4_Using_X509_Certificate(); - Example_5_Export_Public_Key_For_X509_Certificate(); - //Example_7_Customize(); - } + private static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory; - public static void Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey() - { - ICryptoNet cryptoNet = new CryptoNetRsa(); + internal static readonly string PrivateKeyFile = Path.Combine(BaseFolder, "privateKey"); + internal static readonly string PublicKeyFile = Path.Combine(BaseFolder, "publicKey.pub"); - var privateKey = cryptoNet.ExportKey(true); - var publicKey = cryptoNet.ExportKey(false); + public static void Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey() + { + ICryptoNet cryptoNet = new CryptoNetRsa(); - ICryptoNet encryptClient = new CryptoNetRsa(publicKey); - var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); + var privateKey = cryptoNet.ExportKey(true); + var publicKey = cryptoNet.ExportKey(false); - ICryptoNet decryptClient = new CryptoNetRsa(privateKey); - var decrypt = decryptClient.DecryptToString(encrypt); + ICryptoNet encryptClient = new CryptoNetRsa(publicKey); + var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); - Debug.Assert(ConfidentialDummyData == decrypt); - } + ICryptoNet decryptClient = new CryptoNetRsa(privateKey); + var decrypt = decryptClient.DecryptToString(encrypt); - public static void Example_2_SelfGenerated_And_Save_AsymmetricKey() - { - ICryptoNet cryptoNet = new CryptoNetRsa(); + Debug.Assert(ConfidentialDummyData == decrypt); + } - cryptoNet.ExportKeyAndSave(new FileInfo(PrivateKeyFile), true); - cryptoNet.ExportKeyAndSave(new FileInfo(PublicKeyFile), false); + public static void Example_2_SelfGenerated_And_Save_AsymmetricKey() + { + ICryptoNet cryptoNet = new CryptoNetRsa(); - Debug.Assert(File.Exists(new FileInfo(PrivateKeyFile).FullName)); - Debug.Assert(File.Exists(new FileInfo(PublicKeyFile).FullName)); + cryptoNet.ExportKeyAndSave(new FileInfo(PrivateKeyFile), true); + cryptoNet.ExportKeyAndSave(new FileInfo(PublicKeyFile), false); - ICryptoNet cryptoNetPubKey = new CryptoNetRsa(new FileInfo(PublicKeyFile)); - var encrypt = cryptoNetPubKey.EncryptFromString(ConfidentialDummyData); + Debug.Assert(File.Exists(new FileInfo(PrivateKeyFile).FullName)); + Debug.Assert(File.Exists(new FileInfo(PublicKeyFile).FullName)); - ICryptoNet cryptoNetPriKey = new CryptoNetRsa(new FileInfo(PrivateKeyFile)); - var decrypt = cryptoNetPriKey.DecryptToString(encrypt); + ICryptoNet cryptoNetPubKey = new CryptoNetRsa(new FileInfo(PublicKeyFile)); + var encrypt = cryptoNetPubKey.EncryptFromString(ConfidentialDummyData); - Debug.Assert(ConfidentialDummyData == decrypt); - } + ICryptoNet cryptoNetPriKey = new CryptoNetRsa(new FileInfo(PrivateKeyFile)); + var decrypt = cryptoNetPriKey.DecryptToString(encrypt); - public static void Example_3_Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Of_Content() - { - ICryptoNet cryptoNetWithPublicKey = new CryptoNetRsa(new FileInfo(PublicKeyFile)); - var encryptWithPublicKey = cryptoNetWithPublicKey.EncryptFromString(ConfidentialDummyData); + Debug.Assert(ConfidentialDummyData == decrypt); + } - ICryptoNet cryptoNetWithPrivateKey = new CryptoNetRsa(new FileInfo(PrivateKeyFile)); - var decryptWithPrivateKey = cryptoNetWithPrivateKey.DecryptToString(encryptWithPublicKey); + public static void Example_3_Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Of_Content() + { + ICryptoNet cryptoNetWithPublicKey = new CryptoNetRsa(new FileInfo(PublicKeyFile)); + var encryptWithPublicKey = cryptoNetWithPublicKey.EncryptFromString(ConfidentialDummyData); - Debug.Assert(ConfidentialDummyData == decryptWithPrivateKey); - } + ICryptoNet cryptoNetWithPrivateKey = new CryptoNetRsa(new FileInfo(PrivateKeyFile)); + var decryptWithPrivateKey = cryptoNetWithPrivateKey.DecryptToString(encryptWithPublicKey); - public static void Example_4_Using_X509_Certificate() - { - // Find and replace CN=Maytham with your own certificate - X509Certificate2? certificate = CryptoNetUtils.GetCertificateFromStore("CN=Maytham"); + Debug.Assert(ConfidentialDummyData == decryptWithPrivateKey); + } - ICryptoNet cryptoNetWithPublicKey = new CryptoNetRsa(certificate, KeyType.PublicKey); - var encryptWithPublicKey = cryptoNetWithPublicKey.EncryptFromString(ConfidentialDummyData); + public static void Example_4_Using_X509_Certificate() + { + // Find and replace CN=Maytham with your own certificate + X509Certificate2? certificate = CryptoNetUtils.GetCertificateFromStore("CN=Maytham"); - ICryptoNet cryptoNetWithPrivateKey = new CryptoNetRsa(certificate, KeyType.PrivateKey); - var decryptWithPrivateKey = cryptoNetWithPrivateKey.DecryptToString(encryptWithPublicKey); + ICryptoNet cryptoNetWithPublicKey = new CryptoNetRsa(certificate, KeyType.PublicKey); + var encryptWithPublicKey = cryptoNetWithPublicKey.EncryptFromString(ConfidentialDummyData); - Debug.Assert(ConfidentialDummyData == decryptWithPrivateKey); - } + ICryptoNet cryptoNetWithPrivateKey = new CryptoNetRsa(certificate, KeyType.PrivateKey); + var decryptWithPrivateKey = cryptoNetWithPrivateKey.DecryptToString(encryptWithPublicKey); - public static void Example_5_Export_Public_Key_For_X509_Certificate() - { - // Find and replace CN=Maytham with your own certificate - X509Certificate2? certificate = CryptoNetUtils.GetCertificateFromStore("CN=Maytham"); + Debug.Assert(ConfidentialDummyData == decryptWithPrivateKey); + } - ICryptoNet cryptoNetWithPublicKey = new CryptoNetRsa(certificate, KeyType.PublicKey); - var publicKey = cryptoNetWithPublicKey.ExportKey(false); + public static void Example_5_Export_Public_Key_For_X509_Certificate() + { + // Find and replace CN=Maytham with your own certificate + X509Certificate2? certificate = CryptoNetUtils.GetCertificateFromStore("CN=Maytham"); - Debug.Assert(!string.IsNullOrEmpty(publicKey)); - } + ICryptoNet cryptoNetWithPublicKey = new CryptoNetRsa(certificate, KeyType.PublicKey); + var publicKey = cryptoNetWithPublicKey.ExportKey(false); - /// - /// CryptoNet interact with .net 5/6 for customization, like import/export PEM - /// Work in Progress, not finished - /// - public static void Example_7_Customize() - { - X509Certificate2? cert = CryptoNetUtils.GetCertificateFromStore("CN=Maytham"); + Debug.Assert(!string.IsNullOrEmpty(publicKey)); + } - var pubKeyPem = ExportPemKey(cert!, false); - var priKeyPem = ExportPemKey(cert!); + /// + /// CryptoNet interact with .net 5/6 for customization, like import/export PEM + /// Work in Progress, not finished + /// + public static void Example_7_Customize() + { + X509Certificate2? cert = CryptoNetUtils.GetCertificateFromStore("CN=Maytham"); - var password = "password"; - var encryptedPriKeyBytes = ExportPemKeyWithPassword(cert!, password); + var pubKeyPem = ExportPemKey(cert!, false); + var priKeyPem = ExportPemKey(cert!); - ICryptoNet cryptoNet1 = ImportPemKeyWithPassword(encryptedPriKeyBytes, password); - var encrypt1 = cryptoNet1.EncryptFromString(ConfidentialDummyData); + var password = "password"; + var encryptedPriKeyBytes = ExportPemKeyWithPassword(cert!, password); - ICryptoNet cryptoNet2 = ImportPemKey(pubKeyPem); - var encrypt2 = cryptoNet2.EncryptFromString(ConfidentialDummyData); + ICryptoNet cryptoNet1 = ImportPemKeyWithPassword(encryptedPriKeyBytes, password); + var encrypt1 = cryptoNet1.EncryptFromString(ConfidentialDummyData); - ICryptoNet cryptoNet3 = ImportPemKey(priKeyPem); - var decrypt2 = cryptoNet3.DecryptToString(encrypt2); + ICryptoNet cryptoNet2 = ImportPemKey(pubKeyPem); + var encrypt2 = cryptoNet2.EncryptFromString(ConfidentialDummyData); - Debug.Assert(ConfidentialDummyData == decrypt2); + ICryptoNet cryptoNet3 = ImportPemKey(priKeyPem); + var decrypt2 = cryptoNet3.DecryptToString(encrypt2); - var decrypt1 = cryptoNet3.DecryptToString(encrypt1); + Debug.Assert(ConfidentialDummyData == decrypt2); - Debug.Assert(ConfidentialDummyData == decrypt1); - } + var decrypt1 = cryptoNet3.DecryptToString(encrypt1); - public static char[] ExportPemCertificate(X509Certificate2 cert) - { - byte[] certBytes = cert!.RawData; - char[] certPem = PemEncoding.Write("CERTIFICATE", certBytes); - return certPem; - } + Debug.Assert(ConfidentialDummyData == decrypt1); + } - public static char[] ExportPemKey(X509Certificate2 cert, bool privateKey = true) - { - AsymmetricAlgorithm rsa = cert.GetRSAPrivateKey()!; + public static char[] ExportPemCertificate(X509Certificate2 cert) + { + byte[] certBytes = cert!.RawData; + char[] certPem = PemEncoding.Write("CERTIFICATE", certBytes); + return certPem; + } - if (privateKey) + public static char[] ExportPemKey(X509Certificate2 cert, bool privateKey = true) { - byte[] priKeyBytes = rsa.ExportPkcs8PrivateKey(); - return PemEncoding.Write("PRIVATE KEY", priKeyBytes); + 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); } - byte[] pubKeyBytes = rsa.ExportSubjectPublicKeyInfo(); - return PemEncoding.Write("PUBLIC KEY", pubKeyBytes); - } + public static ICryptoNet ImportPemKey(char[] key) + { + ICryptoNet cryptoNet = new CryptoNetRsa(); + cryptoNet.Info.RsaDetail!.Rsa?.ImportFromPem(key); + return cryptoNet; + } - public static ICryptoNet ImportPemKey(char[] key) - { - ICryptoNet cryptoNet = new CryptoNetRsa(); - cryptoNet.Info.RsaDetail!.Rsa?.ImportFromPem(key); - return cryptoNet; - } + public static byte[] ExportPemKeyWithPassword(X509Certificate2 cert, string password) + { + AsymmetricAlgorithm rsa = cert.GetRSAPrivateKey()!; + byte[] pass = Encoding.UTF8.GetBytes(password); + byte[] encryptedPrivateKey = rsa.ExportEncryptedPkcs8PrivateKey(pass, + new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, iterationCount: 100_000)); + return encryptedPrivateKey; + } - public static byte[] ExportPemKeyWithPassword(X509Certificate2 cert, string password) - { - AsymmetricAlgorithm rsa = cert.GetRSAPrivateKey()!; - byte[] pass = Encoding.UTF8.GetBytes(password); - byte[] encryptedPrivateKey = rsa.ExportEncryptedPkcs8PrivateKey(pass, - new PbeParameters(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, iterationCount: 100_000)); - return encryptedPrivateKey; - } + public static ICryptoNet ImportPemKeyWithPassword(byte[] encryptedPrivateKey, string password) + { + ICryptoNet cryptoNet = new CryptoNetRsa(); + cryptoNet.Info.RsaDetail?.Rsa?.ImportEncryptedPkcs8PrivateKey(password, encryptedPrivateKey, out _); + return cryptoNet; + } - public static ICryptoNet ImportPemKeyWithPassword(byte[] encryptedPrivateKey, string password) - { - ICryptoNet cryptoNet = new CryptoNetRsa(); - cryptoNet.Info.RsaDetail?.Rsa?.ImportEncryptedPkcs8PrivateKey(password, encryptedPrivateKey, out _); - return cryptoNet; } - -} +} \ No newline at end of file diff --git a/CryptoNet.Cli/Program.cs b/CryptoNet.Cli/Program.cs index 28d9640..525351e 100644 --- a/CryptoNet.Cli/Program.cs +++ b/CryptoNet.Cli/Program.cs @@ -9,10 +9,22 @@ namespace CryptoNet.Cli { internal class Program { + protected Program() { } + public static void Main() { - ExampleAes.Test(); - ExampleRsa.Test(); + ExampleAes.Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_SymmetricKey(); + ExampleAes.Example_2_SelfGenerated_And_Save_SymmetricKey(); + ExampleAes.Example_3_Encrypt_Decrypt_Content_With_Own_SymmetricKey(); + ExampleAes.Example_4_Encrypt_Decrypt_Content_With_Human_Readable_Key_Secret_SymmetricKey(); + ExampleAes.Example_5_Encrypt_And_Decrypt_PdfFile_With_SymmetricKey_Test("TestFiles\\test.docx"); + ExampleAes.Example_5_Encrypt_And_Decrypt_PdfFile_With_SymmetricKey_Test("TestFiles\\test.xlsx"); + ExampleAes.Example_5_Encrypt_And_Decrypt_PdfFile_With_SymmetricKey_Test("TestFiles\\test.pdf"); + ExampleAes.Example_5_Encrypt_And_Decrypt_PdfFile_With_SymmetricKey_Test("TestFiles\\test.png"); + + ExampleRsa.Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey(); + ExampleRsa.Example_2_SelfGenerated_And_Save_AsymmetricKey(); + ExampleRsa.Example_3_Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Of_Content(); } } } diff --git a/CryptoNet.Cli/TestFiles/test.docx b/CryptoNet.Cli/TestFiles/test.docx new file mode 100644 index 0000000..4852773 Binary files /dev/null and b/CryptoNet.Cli/TestFiles/test.docx differ diff --git a/CryptoNet.Cli/TestFiles/test.pdf b/CryptoNet.Cli/TestFiles/test.pdf new file mode 100644 index 0000000..9b88b35 Binary files /dev/null and b/CryptoNet.Cli/TestFiles/test.pdf differ diff --git a/CryptoNet.UnitTests/Resources/TestFiles/Image.png b/CryptoNet.Cli/TestFiles/test.png similarity index 100% rename from CryptoNet.UnitTests/Resources/TestFiles/Image.png rename to CryptoNet.Cli/TestFiles/test.png diff --git a/CryptoNet.UnitTests/Resources/TestFiles/ExcelDocument.xlsx b/CryptoNet.Cli/TestFiles/test.xlsx similarity index 100% rename from CryptoNet.UnitTests/Resources/TestFiles/ExcelDocument.xlsx rename to CryptoNet.Cli/TestFiles/test.xlsx diff --git a/CryptoNet.UnitTests/Common.cs b/CryptoNet.UnitTests/Common.cs new file mode 100644 index 0000000..9bbe593 --- /dev/null +++ b/CryptoNet.UnitTests/Common.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Threading; + +namespace CryptoNet.UnitTests +{ + internal static class Common + { + public const string ConfidentialDummyData = @"Some Secret Data"; + + public static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory; + public static string RsaStoredKeyPair = Path.Combine(BaseFolder, @"Resources/RsaKeys/RsaKeys"); + public static string TestFilesFolder = Path.Combine(BaseFolder, @"Resources/TestFiles/"); + + public static string EncryptedContentFile = Path.Combine(BaseFolder, "encrypted.txt"); + public static string PrivateKeyFile = Path.Combine(BaseFolder, "privateKey"); + public static string PublicKeyFile = Path.Combine(BaseFolder, "publicKey.pub"); + public static string[] DummyFiles = new string[] + { + EncryptedContentFile, + PublicKeyFile, + PrivateKeyFile + }; + + #region Private methods + public static void DeleteTestFiles(string[] files) + { + try + { + Thread.Sleep(500); + foreach (string file in files) + { + File.Delete(file); + } + } + catch (Exception) + { + throw; + } + } + + public static bool CheckContent(string originalContent, string decryptedContent) + { + return CalculateMd5(originalContent).Equals(CalculateMd5(decryptedContent)); + } + + public static string CalculateMd5(string content) + { + var hash = MD5.HashData(Encoding.UTF8.GetBytes(content)); + return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); + } + #endregion + } +} diff --git a/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj b/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj index b30cc03..edeac8e 100644 --- a/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj +++ b/CryptoNet.UnitTests/CryptoNet.UnitTests.csproj @@ -8,14 +8,14 @@ - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -32,6 +32,18 @@ Always + + Always + + + Always + + + Always + + + Always + Always diff --git a/CryptoNet.UnitTests/CryptoNetAesTests.cs b/CryptoNet.UnitTests/CryptoNetAesTests.cs new file mode 100644 index 0000000..5363c11 --- /dev/null +++ b/CryptoNet.UnitTests/CryptoNetAesTests.cs @@ -0,0 +1,99 @@ +// +// Copyright (c) 2021 All Rights Reserved +// +// Maytham Fahmi +// 17-12-2021 12:18:44 +// part of CryptoNet project + +using System; +using System.IO; +using System.Text; +using CryptoNet.Models; +using CryptoNet.Utils; +using NUnit.Framework; +using Shouldly; + +// ReSharper disable All + +namespace CryptoNet.UnitTests +{ + [TestFixture] + public class CryptoNetAesTests + { + [Test] + public void Encrypt_And_Decrypt_With_SymmetricKey_Test() + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + // arrange + var key = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315a1916"); + var iv = new byte[16]; + + ICryptoNet encryptClient = new CryptoNetAes(key, iv); + ICryptoNet decryptClient = new CryptoNetAes(key, iv); + + // act + var encryptData = encryptClient.EncryptFromString(Common.ConfidentialDummyData); + var decryptData = decryptClient.DecryptToString(encryptData); + + // assert + Common.ConfidentialDummyData.ShouldBe(decryptData); + encryptClient.Info.KeyType.ShouldBe(KeyType.SymmetricKey); + encryptClient.Info.KeyType.ShouldNotBe(KeyType.PublicKey); + encryptClient.Info.KeyType.ShouldNotBe(KeyType.PrivateKey); + encryptClient.Info.KeyType.ShouldNotBe(KeyType.NotSet); + } + } + + [Test] + public void Encrypt_And_Decrypt_With_Wrong_SymmetricKey_Test() + { + var key = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315a1916"); + var keyWrong = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315b1916"); + var iv = new byte[16]; + + // arrange + ICryptoNet encryptClient = new CryptoNetAes(key, iv); + ICryptoNet decryptClient = new CryptoNetAes(keyWrong, iv); + + // act + var encryptData = encryptClient.EncryptFromString(Common.ConfidentialDummyData); + try + { + decryptClient.DecryptToString(encryptData); + } + catch (Exception e) + { + // assert + e.Message.ShouldBe("Padding is invalid and cannot be removed."); + } + } + + [TestCase("test.docx")] + [TestCase("test.xlsx")] + [TestCase("test.png")] + [TestCase("test.pdf")] + public void Validate_Decrypted_File_Against_The_Original_File_By_Comparing_Bytes_Test(string filename) + { + // arrange + var key = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315a1916"); + var iv = new byte[16]; + + ICryptoNet encryptClient = new CryptoNetAes(key, iv); + ICryptoNet decryptClient = new CryptoNetAes(key, iv); + + // act + var filePath = Path.Combine(Common.TestFilesFolder, filename); + byte[] originalFileBytes = File.ReadAllBytes(filePath); + byte[] encrypted = encryptClient.EncryptFromBytes(originalFileBytes); + byte[] decrypted = decryptClient.DecryptToBytes(encrypted); + + var isIdenticalFile = CryptoNetUtils.ByteArrayCompare(originalFileBytes, decrypted); + + // assert + isIdenticalFile.ShouldBeTrue(); + } + + } + +} diff --git a/CryptoNet.UnitTests/CryptoNetRsaTests.cs b/CryptoNet.UnitTests/CryptoNetRsaTests.cs new file mode 100644 index 0000000..3231ad7 --- /dev/null +++ b/CryptoNet.UnitTests/CryptoNetRsaTests.cs @@ -0,0 +1,187 @@ +// +// Copyright (c) 2021 All Rights Reserved +// +// Maytham Fahmi +// 17-12-2021 12:18:44 +// part of CryptoNet project + +using System; +using System.IO; +using System.Text; +using CryptoNet.Models; +using CryptoNet.Utils; +using NUnit.Framework; +using Shouldly; + +// ReSharper disable All + +namespace CryptoNet.UnitTests +{ + [TestFixture] + public class CryptoNetRsaTests + { + [Test] + public void SelfGenerated_AsymmetricKey_And_TypeValidation_Test() + { + // arrange + ICryptoNet cryptoNet = new CryptoNetRsa(); + + // act + cryptoNet.ExportKeyAndSave(new FileInfo(Common.PrivateKeyFile), true); + cryptoNet.ExportKeyAndSave(new FileInfo(Common.PublicKeyFile), false); + + // assert + new CryptoNetRsa(new FileInfo(Common.PrivateKeyFile)).Info.KeyType.ShouldBe(KeyType.PrivateKey); + new CryptoNetRsa(new FileInfo(Common.PublicKeyFile)).Info.KeyType.ShouldBe(KeyType.PublicKey); + } + + [Test] + public void Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey_Test() + { + ICryptoNet cryptoNet = new CryptoNetRsa(); + var privateKey = cryptoNet.ExportKey(true); + var publicKey = cryptoNet.ExportKey(false); + + // arrange + ICryptoNet encryptClient = new CryptoNetRsa(publicKey); + var encrypt = encryptClient.EncryptFromString(Common.ConfidentialDummyData); + + // act + ICryptoNet decryptClient = new CryptoNetRsa(privateKey); + var decrypt = decryptClient.DecryptToString(encrypt); + + // assert + Common.CheckContent(Common.ConfidentialDummyData, decrypt).ShouldBeTrue(); + } + + [Test] + public void Encrypt_Decrypt_Content_With_Invalid_AsymmetricKey_Test() + { + // arrange + ICryptoNet encryptClient = new CryptoNetRsa(); + var encrypt = encryptClient.EncryptFromString(Common.ConfidentialDummyData); + + // act + const string invalidKey = "invalid-key"; + string decrypt = string.Empty; + try + { + ICryptoNet decryptClient = new CryptoNetRsa(invalidKey); + decrypt = decryptClient.DecryptToString(encrypt); + } + catch (Exception e) + { + // assert + Common.CheckContent(Common.ConfidentialDummyData, decrypt).ShouldBeFalse(); + e.Message.ShouldContain("The provided XML could not be read."); + } + } + + [Test] + public void Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test() + { + // arrange + ICryptoNet 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(); + + // finalize + Common.DeleteTestFiles(Common.DummyFiles); + } + + [TestCase("test.docx"), Order(5)] + [TestCase("test.xlsx")] + [TestCase("test.png")] + [TestCase("test.pdf")] + public void Encrypt_Decrypt_Documents_With_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test(string filename) + { + var testDocument = File.ReadAllBytes(Path.Combine(Common.TestFilesFolder, filename)); + + ICryptoNet cryptoNet = new CryptoNetRsa(); + cryptoNet.ExportKeyAndSave(new FileInfo(Common.PrivateKeyFile), true); + cryptoNet.ExportKeyAndSave(new FileInfo(Common.PublicKeyFile), false); + + // arrange + ICryptoNet encryptClient = new CryptoNetRsa(new FileInfo(Common.PublicKeyFile)); + var encrypt = encryptClient.EncryptFromBytes(testDocument); + + // act + ICryptoNet decryptClient = new CryptoNetRsa(new FileInfo(Common.PrivateKeyFile)); + var decrypt = decryptClient.DecryptToBytes(encrypt); + + // assert + Assert.AreEqual(testDocument, decrypt); + } + + [Test] + public void Encrypt_Decrypt_Content_With_PreStored_SelfGenerated_AsymmetricKey_Test() + { + // arrange + ICryptoNet cryptoNet = new CryptoNetRsa(new FileInfo(Common.RsaStoredKeyPair)); + + // act + var encrypt = cryptoNet.EncryptFromString(Common.ConfidentialDummyData); + var content = cryptoNet.DecryptToString(encrypt); + + // assert + Common.CheckContent(Common.ConfidentialDummyData, content); + } + + [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); + // Export public key + ICryptoNet cryptoNet = new CryptoNetRsa(certificate); + cryptoNet.ExportKeyAndSave(new FileInfo(Common.PublicKeyFile), false); + + // Import public key and encrypt + var importPublicKey = new FileInfo(Common.PublicKeyFile); + ICryptoNet cryptoNetEncryptWithPublicKey = new CryptoNetRsa(importPublicKey); + var encryptWithPublicKey = cryptoNetEncryptWithPublicKey.EncryptFromString(Common.ConfidentialDummyData); + + // act + ICryptoNet cryptoNetDecryptWithPublicKey = new CryptoNetRsa(certificate); + var decryptWithPrivateKey = cryptoNetDecryptWithPublicKey.DecryptToString(encryptWithPublicKey); + + // assert + Common.CheckContent(Common.ConfidentialDummyData, decryptWithPrivateKey); + + // finalize + Common.DeleteTestFiles(Common.DummyFiles); + } + + [TestCase("test.docx")] + [TestCase("test.xlsx")] + [TestCase("test.png")] + [TestCase("test.pdf")] + public void Validate_Decrypted_File_Against_The_Original_File_By_Comparing_Bytes_Test(string filename) + { + // arrange + var certificate = new FileInfo(Common.RsaStoredKeyPair); + // Export public key + ICryptoNet cryptoNet = new CryptoNetRsa(certificate); + + // act + var filePath = Path.Combine(Common.TestFilesFolder, filename); + byte[] originalFileBytes = File.ReadAllBytes(filePath); + byte[] encrypted = cryptoNet.EncryptFromBytes(originalFileBytes); + byte[] decrypted = cryptoNet.DecryptToBytes(encrypted); + + var isIdenticalFile = CryptoNetUtils.ByteArrayCompare(originalFileBytes, decrypted); + + // assert + isIdenticalFile.ShouldBeTrue(); + } + + } + +} diff --git a/CryptoNet.UnitTests/CryptoNetTests.cs b/CryptoNet.UnitTests/CryptoNetTests.cs deleted file mode 100644 index cfb58c4..0000000 --- a/CryptoNet.UnitTests/CryptoNetTests.cs +++ /dev/null @@ -1,255 +0,0 @@ -// -// Copyright (c) 2021 All Rights Reserved -// -// Maytham Fahmi -// 17-12-2021 12:18:44 -// part of CryptoNet project - -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using CryptoNet.Models; -using NUnit.Framework; -using Shouldly; - -// ReSharper disable All - -namespace CryptoNet.UnitTests -{ - [TestFixture] - public class CryptoNetTests - { - private const string ConfidentialDummyData = @"Some Secret Data"; - - private static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory; - private readonly string _rsaStoredKeyPair = Path.Combine(BaseFolder, @"Resources/RsaKeys/RsaKeys"); - private readonly string _testFilesFolder = Path.Combine(BaseFolder, @"Resources/TestFiles/"); - - internal static string EncryptedContentFile = Path.Combine(BaseFolder, "encrypted.txt"); - internal static string PrivateKeyFile = Path.Combine(BaseFolder, "privateKey"); - internal static string PublicKeyFile = Path.Combine(BaseFolder, "publicKey.pub"); - - [Test] - public void Encrypt_And_Decrypt_With_SymmetricKey_Test() - { - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - // arrange - var key = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315a1916"); - var iv = new byte[16]; - - ICryptoNet encryptClient = new CryptoNetAes(key, iv); - ICryptoNet decryptClient = new CryptoNetAes(key, iv); - - // act - var encryptData = encryptClient.EncryptFromString(ConfidentialDummyData); - var decryptData = decryptClient.DecryptToString(encryptData); - - // assert - ConfidentialDummyData.ShouldBe(decryptData); - encryptClient.Info.KeyType.ShouldBe(KeyType.SymmetricKey); - encryptClient.Info.KeyType.ShouldNotBe(KeyType.PublicKey); - encryptClient.Info.KeyType.ShouldNotBe(KeyType.PrivateKey); - encryptClient.Info.KeyType.ShouldNotBe(KeyType.NotSet); - } - } - - [Test] - public void Encrypt_And_Decrypt_With_Wrong_SymmetricKey_Test() - { - var key = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315a1916"); - var keyWrong = Encoding.UTF8.GetBytes("b14ca5898a4e4133bbce2ea2315b1916"); - var iv = new byte[16]; - - // arrange - ICryptoNet encryptClient = new CryptoNetAes(key, iv); - ICryptoNet decryptClient = new CryptoNetAes(keyWrong, iv); - - // act - var encryptData = encryptClient.EncryptFromString(ConfidentialDummyData); - try - { - var decryptData = decryptClient.DecryptToString(encryptData); - } - catch (Exception e) - { - // assert - e.Message.ShouldBe("Padding is invalid and cannot be removed."); - } - } - - [Test] - public void SelfGenerated_AsymmetricKey_And_TypeValidation_Test() - { - // arrange - ICryptoNet cryptoNet = new CryptoNetRsa(); - - // act - cryptoNet.ExportKeyAndSave(new FileInfo(PrivateKeyFile), true); - cryptoNet.ExportKeyAndSave(new FileInfo(PublicKeyFile), false); - - // assert - new CryptoNetRsa(new FileInfo(PrivateKeyFile)).Info.KeyType.ShouldBe(KeyType.PrivateKey); - new CryptoNetRsa(new FileInfo(PublicKeyFile)).Info.KeyType.ShouldBe(KeyType.PublicKey); - } - - [Test] - public void Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey_Test() - { - ICryptoNet cryptoNet = new CryptoNetRsa(); - var privateKey = cryptoNet.ExportKey(true); - var publicKey = cryptoNet.ExportKey(false); - - // arrange - ICryptoNet encryptClient = new CryptoNetRsa(publicKey); - var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); - - // act - ICryptoNet decryptClient = new CryptoNetRsa(privateKey); - var decrypt = decryptClient.DecryptToString(encrypt); - - // assert - CheckContent(ConfidentialDummyData, decrypt).ShouldBeTrue(); - } - - [Test] - public void Encrypt_Decrypt_Content_With_Invalid_AsymmetricKey_Test() - { - // arrange - ICryptoNet encryptClient = new CryptoNetRsa(); - var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData); - - // act - const string invalidKey = "invalid-key"; - string decrypt = string.Empty; - try - { - ICryptoNet decryptClient = new CryptoNetRsa(invalidKey); - decrypt = decryptClient.DecryptToString(encrypt); - } - catch (Exception e) - { - // assert - CheckContent(ConfidentialDummyData, decrypt).ShouldBeFalse(); - e.Message.ShouldContain("The provided XML could not be read."); - } - } - - [Test] - public void Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test() - { - // arrange - ICryptoNet cryptoNet = new CryptoNetRsa(); - var encrypt = cryptoNet.EncryptFromString(ConfidentialDummyData); - File.WriteAllBytes(EncryptedContentFile, encrypt); - - // act - var encryptFile = File.ReadAllBytes(EncryptedContentFile); - var content = cryptoNet.DecryptToString(encryptFile); - - // assert - CheckContent(ConfidentialDummyData, content).ShouldBeTrue(); - - // finalize - Delete_Test_Files(); - } - - [TestCase("WordDocument.docx"), Order(5)] - [TestCase("ExcelDocument.xlsx")] - [TestCase("Image.png")] - public void Encrypt_Decrypt_Documents_With_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test(string filename) - { - var testDocument = File.ReadAllBytes(Path.Combine(_testFilesFolder, filename)); - - ICryptoNet cryptoNet = new CryptoNetRsa(); - cryptoNet.ExportKeyAndSave(new FileInfo(PrivateKeyFile), true); - cryptoNet.ExportKeyAndSave(new FileInfo(PublicKeyFile), false); - - // arrange - ICryptoNet encryptClient = new CryptoNetRsa(new FileInfo(PublicKeyFile)); - var encrypt = encryptClient.EncryptFromBytes(testDocument); - - // act - ICryptoNet decryptClient = new CryptoNetRsa(new FileInfo(PrivateKeyFile)); - var decrypt = decryptClient.DecryptToBytes(encrypt); - - // assert - Assert.AreEqual(testDocument, decrypt); - } - - [Test] - public void Encrypt_Decrypt_Content_With_PreStored_SelfGenerated_AsymmetricKey_Test() - { - // arrange - ICryptoNet cryptoNet = new CryptoNetRsa(new FileInfo(_rsaStoredKeyPair)); - - // act - var encrypt = cryptoNet.EncryptFromString(ConfidentialDummyData); - var content = cryptoNet.DecryptToString(encrypt); - - // assert - CheckContent(ConfidentialDummyData, content); - } - - [Test] - public void Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Using_SelfGenerated_AsymmetricKey_That_Is_Stored_And_Loaded_Test() - { - // arrange - var certificate = new FileInfo(_rsaStoredKeyPair); - // Export public key - ICryptoNet cryptoNet = new CryptoNetRsa(certificate); - cryptoNet.ExportKeyAndSave(new FileInfo(PublicKeyFile), false); - - // Import public key and encrypt - var importPublicKey = new FileInfo(PublicKeyFile); - ICryptoNet cryptoNetEncryptWithPublicKey = new CryptoNetRsa(importPublicKey); - var encryptWithPublicKey = cryptoNetEncryptWithPublicKey.EncryptFromString(ConfidentialDummyData); - - // act - ICryptoNet cryptoNetDecryptWithPublicKey = new CryptoNetRsa(certificate); - var decryptWithPrivateKey = cryptoNetDecryptWithPublicKey.DecryptToString(encryptWithPublicKey); - - // assert - CheckContent(ConfidentialDummyData, decryptWithPrivateKey); - - // finalize - Delete_Test_Files(); - } - - #region Private methods - private static void Delete_Test_Files() - { - try - { - Thread.Sleep(500); - File.Delete(EncryptedContentFile); - File.Delete(PublicKeyFile); - File.Delete(PrivateKeyFile); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - - private static bool CheckContent(string originalContent, string decryptedContent) - { - return CalculateMd5(originalContent).Equals(CalculateMd5(decryptedContent)); - } - - private static string CalculateMd5(string content) - { - using (var md5 = MD5.Create()) - { - var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(content)); - return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); - } - } - #endregion - - } - -} diff --git a/CryptoNet.UnitTests/Resources/TestFiles/WordDocument.docx b/CryptoNet.UnitTests/Resources/TestFiles/WordDocument.docx deleted file mode 100644 index 5311b4d..0000000 Binary files a/CryptoNet.UnitTests/Resources/TestFiles/WordDocument.docx and /dev/null differ diff --git a/CryptoNet.UnitTests/Resources/TestFiles/test.docx b/CryptoNet.UnitTests/Resources/TestFiles/test.docx new file mode 100644 index 0000000..4852773 Binary files /dev/null and b/CryptoNet.UnitTests/Resources/TestFiles/test.docx differ diff --git a/CryptoNet.UnitTests/Resources/TestFiles/test.pdf b/CryptoNet.UnitTests/Resources/TestFiles/test.pdf new file mode 100644 index 0000000..9b88b35 Binary files /dev/null and b/CryptoNet.UnitTests/Resources/TestFiles/test.pdf differ diff --git a/CryptoNet.UnitTests/Resources/TestFiles/test.png b/CryptoNet.UnitTests/Resources/TestFiles/test.png new file mode 100644 index 0000000..29c6eb4 Binary files /dev/null and b/CryptoNet.UnitTests/Resources/TestFiles/test.png differ diff --git a/CryptoNet.UnitTests/Resources/TestFiles/test.xlsx b/CryptoNet.UnitTests/Resources/TestFiles/test.xlsx new file mode 100644 index 0000000..9575466 Binary files /dev/null and b/CryptoNet.UnitTests/Resources/TestFiles/test.xlsx differ diff --git a/CryptoNet/CryptoNet.csproj b/CryptoNet/CryptoNet.csproj index 03bcb0b..73a10c4 100644 --- a/CryptoNet/CryptoNet.csproj +++ b/CryptoNet/CryptoNet.csproj @@ -43,7 +43,7 @@ Never - + diff --git a/CryptoNet/CryptoNetAes.cs b/CryptoNet/CryptoNetAes.cs index e1d85da..24164dd 100644 --- a/CryptoNet/CryptoNetAes.cs +++ b/CryptoNet/CryptoNetAes.cs @@ -76,21 +76,21 @@ public string ExportKey(bool? privateKey = null) return CryptoNetUtils.ExportAndSaveAesKey(Aes); } - public void ExportKeyAndSave(FileInfo fileInfo, bool? privateKey = null) + public void ExportKeyAndSave(FileInfo fileInfo, bool? privateKey = false) { var key = CryptoNetUtils.ExportAndSaveAesKey(Aes); CryptoNetUtils.SaveKey(fileInfo.FullName, key); } #region encryption logic - public byte[] EncryptFromString(string bytes) + public byte[] EncryptFromString(string content) { - return EncryptContent(bytes); + return EncryptContent(content); } public byte[] EncryptFromBytes(byte[] bytes) { - return EncryptContent(CryptoNetUtils.BytesToString(bytes)); + return EncryptContent(CryptoNetUtils.Base64BytesToString(bytes)); } public string DecryptToString(byte[] bytes) @@ -100,14 +100,14 @@ public string DecryptToString(byte[] bytes) public byte[] DecryptToBytes(byte[] bytes) { - return CryptoNetUtils.StringToBytes(DecryptContent(bytes)); + return CryptoNetUtils.Base64StringToBytes(DecryptContent(bytes)); } private byte[] EncryptContent(string content) { if (content == null || content.Length <= 0) { - throw new ArgumentNullException("content"); + throw new ArgumentNullException(nameof(content)); } byte[] encrypted; @@ -133,20 +133,20 @@ private string DecryptContent(byte[] bytes) { if (bytes == null || bytes.Length <= 0) { - throw new ArgumentNullException("bytes"); + throw new ArgumentNullException(nameof(bytes)); } string? plaintext; ICryptoTransform decryptor = Aes.CreateDecryptor(Aes.Key, Aes.IV); - using (MemoryStream msDecrypt = new MemoryStream(bytes)) + using (MemoryStream ms = new MemoryStream(bytes)) { - using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) + using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) { - using (StreamReader srDecrypt = new StreamReader(csDecrypt)) + using (StreamReader sr = new StreamReader(cs)) { - plaintext = srDecrypt.ReadToEnd(); + plaintext = sr.ReadToEnd(); } } } diff --git a/CryptoNet/CryptoNetRsa.cs b/CryptoNet/CryptoNetRsa.cs index ef1868e..0aceb7f 100644 --- a/CryptoNet/CryptoNetRsa.cs +++ b/CryptoNet/CryptoNetRsa.cs @@ -132,12 +132,12 @@ private CryptoNetInfo CreateDetails() }; } - public string ExportKey(bool? privateKey) + public string ExportKey(bool? privateKey = null) { return privateKey!.Value ? ExportKey(KeyType.PrivateKey) : ExportKey(KeyType.PublicKey); } - public void ExportKeyAndSave(FileInfo fileInfo, bool? privateKey) + public void ExportKeyAndSave(FileInfo fileInfo, bool? privateKey = false) { string key = privateKey!.Value ? ExportKey(KeyType.PrivateKey) : ExportKey(KeyType.PublicKey); if (!string.IsNullOrEmpty(key)) @@ -148,10 +148,15 @@ public void ExportKeyAndSave(FileInfo fileInfo, bool? privateKey) private string ExportKey(KeyType keyType) { - return keyType == KeyType.PrivateKey ? Rsa.ToXmlString(true) : - keyType == KeyType.PublicKey ? Rsa.ToXmlString(false) : - keyType == KeyType.NotSet ? string.Empty : - throw new ArgumentOutOfRangeException(nameof(keyType), keyType, null); + string result = keyType switch + { + KeyType.NotSet => string.Empty, + KeyType.PublicKey => Rsa.ToXmlString(false), + KeyType.PrivateKey => Rsa.ToXmlString(true), + _ => throw new ArgumentOutOfRangeException(nameof(keyType), keyType, null) + }; + + return result; } #region encryption logic @@ -160,19 +165,19 @@ public byte[] EncryptFromString(string content) return EncryptContent(CryptoNetUtils.StringToBytes(content)); } - public byte[] EncryptFromBytes(byte[] content) + public byte[] EncryptFromBytes(byte[] bytes) { - return EncryptContent(content); + return EncryptContent(bytes); } - public string DecryptToString(byte[] content) + public string DecryptToString(byte[] bytes) { - return CryptoNetUtils.BytesToString(DecryptContent(content)); + return CryptoNetUtils.BytesToString(DecryptContent(bytes)); } - public byte[] DecryptToBytes(byte[] content) + public byte[] DecryptToBytes(byte[] bytes) { - return DecryptContent(content); + return DecryptContent(bytes); } private byte[] EncryptContent(byte[] content) diff --git a/CryptoNet/Utils/CryptoNetUtils.cs b/CryptoNet/Utils/CryptoNetUtils.cs index 16d473c..38dae44 100644 --- a/CryptoNet/Utils/CryptoNetUtils.cs +++ b/CryptoNet/Utils/CryptoNetUtils.cs @@ -8,6 +8,8 @@ using System; using System.ComponentModel; using System.IO; +using System.Linq; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; @@ -74,6 +76,26 @@ public static byte[] StringToBytes(string content) { return Encoding.ASCII.GetBytes(content); } + + public static string Base64BytesToString(byte[] bytes) + { + return Convert.ToBase64String(bytes); + } + + public static byte[] Base64StringToBytes(string content) + { + return Convert.FromBase64String(content); + } + + public static bool ByteArrayCompare(byte[] b1, byte[] b2) + { + if (b1.Length != b2.Length) + { + return false; + } + + return (b1.Length - b2.Length) == 0 && b1.SequenceEqual(b2); + } #endregion #region Internal methods diff --git a/README.md b/README.md index ecec033..ed88259 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Generic badge](https://img.shields.io/badge/support-.NET%20Standard%202.0-blue.svg)](https://github.com/maythamfahmi/CryptoNet) # Introduction -:rocket: CryptoNet is simple, fast, and a lightweight asymmetric and symmetric encryption NuGet library supporting .NET Standard 2.0 and C# 8.0 for cross platforms Windows, Linux, iOS. +:rocket: CryptoNet is simple, fast, and a lightweight asymmetric and symmetric encryption NuGet library supporting .NET Standard 2.0 and C# 8.0 for cross platforms Windows, Linux, and iOS. It is a 100% native C# implementation based on [Microsoft](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography?view=net-6.0) cryptography. It does not depend on other libraries. @@ -22,36 +22,13 @@ https://maythamfahmi.github.io/CryptoNet [![Nuget](https://img.shields.io/nuget/v/cryptonet?style=social)](https://www.nuget.org/packages/CryptoNet/) is latest version and are maintained. -#### [![Nuget](https://img.shields.io/badge/nuget-v2.2.0-blue?style=social)](https://www.nuget.org/packages/CryptoNet/2.2.0) [![Release%20Code](https://img.shields.io/badge/release%20code-v2.2.0-blue?style=social)](https://github.com/maythamfahmi/CryptoNet/releases/tag/v2.2.0) -- Minor updates -- Corrected texts - -#### [![Nuget](https://img.shields.io/badge/nuget-v2.1.0-blue?style=social)](https://www.nuget.org/packages/CryptoNet/2.1.0) [![Release%20Code](https://img.shields.io/badge/release%20code-v2.1.0-blue?style=social)](https://github.com/maythamfahmi/CryptoNet/releases/tag/v2.1.0) -- !!!Breaking change!!! -- Refactoring RSA asymmetric encryption. -- Introducing AES symmetric encryption. -- Adapt RSA PEM exporting and importing helpers with examples. -- Windows symmetric encryption from v.1.6 is no longer available. - -#### [![Nuget](https://img.shields.io/badge/nuget-v1.6.0-blue?style=social)](https://www.nuget.org/packages/CryptoNet/1.6.0) [![Release%20Code](https://img.shields.io/badge/release%20code-v1.6.0-blue?style=social)](https://github.com/maythamfahmi/CryptoNet/releases/tag/v1.6.0) -- Adapt RSA instance for customization. -- Adapt RSA customization example for PEM exporting and importing. - -#### [![Nuget](https://img.shields.io/badge/nuget-v1.5.0-blue?style=social)](https://www.nuget.org/packages/CryptoNet/1.5.0) [![Release%20Code](https://img.shields.io/badge/release%20code-v1.5.0-blue?style=social)](https://github.com/maythamfahmi/CryptoNet/releases/tag/v1.5.0) -- Reintroducing symmetric encryption only for Windows OS. -- Adding Source Link, Deterministic, and Compiler Flags to the NuGet package. -- Readme enhancement. - -#### [![Nuget](https://img.shields.io/badge/nuget-v1.2.0-blue?style=social)](https://www.nuget.org/packages/CryptoNet/1.2.0) [![Release%20Code](https://img.shields.io/badge/release%20code-v1.2.0-blue?style=social)](https://github.com/maythamfahmi/CryptoNet/releases/tag/v1.2.0) -- Change from RSACryptoServiceProvider to RSA factory that supports cross platforms (Windows, Linux, iOS). -- No longer support symmetric encryption from version 1.0.0. -- Console examples and Unit testing refactored. +List of features: +- RSA asymmetric encryption. +- AES symmetric encryption. +- RSA PEM exporting and importing. - Support for X509Certificate2. - -#### [![Nuget](https://img.shields.io/badge/nuget-v1.0.0-blue?style=social)](https://www.nuget.org/packages/CryptoNet/1.0.0) [![Release%20Code](https://img.shields.io/badge/release%20code-v1.0.0-blue?style=social)](https://github.com/maythamfahmi/CryptoNet/releases/tag/v1.0.0) - -- Ability to encrypt and decrypt files like, images, word, excel, etc. -- Improvement documentation +- Ability to encrypt and decrypt text, files like images, word, excel, etc. +- Cross-platform compatible Windows, Linux, and iOS. ## Issues @@ -170,7 +147,7 @@ docker build . --file .\Dockerfile --tag cryptonet-service:latest You are more than welcome to contribute in one of the following ways: 1. Basic: Give input, and suggestions for improvement by creating an issue and labeling it https://github.com/maythamfahmi/CryptoNet/issues -2. Advance: if you have good knowledge of C# and Cryptography just grab one of the issues, features, or refactoring and add a pull request. +2. Advance: if you have good knowledge of C# and Cryptography just grab one of the issues, or features, or create a new one and refactor and add a pull request. 3. Documentation: Add, update, or improve documentation, by making a pull request. ### How to contribute: