Skip to content

Commit

Permalink
Feature/cross platform compatibility (#12)
Browse files Browse the repository at this point in the history
* Breaking Refactoring
* Update documentation
* Include and Update X509 feature
* Fix pipeline, adding feature branch ci
* Dockerfile

Co-authored-by: Maytham Fahmi <maythamfahmi@nextbix.dk>
  • Loading branch information
Maytham Fahmi and maythamfahmi authored Jan 1, 2022
1 parent e642b17 commit 0c0ce49
Show file tree
Hide file tree
Showing 14 changed files with 321 additions and 245 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ on:
push:
branches:
- main
- "feature/*"
pull_request:
branches:
- main

jobs:
build:
runs-on: windows-latest
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
Expand Down
10 changes: 5 additions & 5 deletions CryptoNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CryptoNetLib", "CryptoNetLi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CryptoNetUnitTests", "CryptoNetUnitTests\CryptoNetUnitTests.csproj", "{C824A7F2-9A20-45EA-820B-F809E8067CA2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rsa", "Rsa", "{BD3A9D34-CDA6-4478-8FC3-97E099B6F3BB}"
ProjectSection(SolutionItems) = preProject
test.certificate = test.certificate
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pipelines", "Pipelines", "{0632D18D-1916-4AB3-9459-46A65AA72837}"
ProjectSection(SolutionItems) = preProject
.github\workflows\ci.yml = .github\workflows\ci.yml
Expand All @@ -26,6 +21,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{7FEF6D01-1
README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{ECD15561-5F6C-471D-B113-A467278DAF8A}"
ProjectSection(SolutionItems) = preProject
Dockerfile = Dockerfile
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
113 changes: 58 additions & 55 deletions CryptoNetCmd/Example.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,95 +5,98 @@
// <date>17-12-2021 12:18:44</date>
// <summary>part of CryptoNetCmd project</summary>

using System.Security.Cryptography.X509Certificates;
using CryptoNetLib;
using CryptoNetLib.helpers;

namespace CryptoNetCmd;

public class Example
{
private const string SymmetricKey = "any-secret-key-that-should-be-the-same-for-encrypting-and-decrypting";
private const string ConfidentialDummyData = @"Some Secret Data";

private static readonly string BaseFolder = AppDomain.CurrentDomain.BaseDirectory;
private static readonly string? Root = Directory.GetParent(Directory.GetCurrentDirectory())?.Parent?.Parent?.Parent?.FullName;
private static readonly string RsaKeyPair = Path.Combine(Root ?? string.Empty, "test.certificate");

internal static string PrivateKeyFile = Path.Combine(BaseFolder, "privateKey");
internal static string PublicKeyFile = Path.Combine(BaseFolder, "publicKey.pub");

public static void Main(string[] args)
public static void Main()
{
Example_1_With_SymmetricKey();
Example_2_With_SelfGenerated_RsaKeyPair_AsymmetricKey();
Example_3_SelfGenerated_RsaKeyPair_AsymmetricKey();
Example_4_With_Encrypt_With_Public_Key_Decrypt_With_SelfGenerated_RsaKeyPair_AsymmetricKey();
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();
}

public static void Example_1_With_SymmetricKey()
public static void Example_1_Encrypt_Decrypt_Content_With_SelfGenerated_AsymmetricKey()
{
ICryptoNet encryptClient = new CryptoNet(SymmetricKey);
Console.WriteLine($"1- We will encrypt following: \n {ConfidentialDummyData} \n");
Console.WriteLine("Example 1");

var encrypted = encryptClient.EncryptFromString(ConfidentialDummyData);
Console.WriteLine($"2- To: \n {CryptoNetUtils.BytesToString(encrypted)} \n");
ICryptoNet cryptoNet = new CryptoNet();

ICryptoNet decryptClient = new CryptoNet(SymmetricKey);
var decrypted = decryptClient.DecryptToString(encrypted);
Console.WriteLine($"3- And we will decrypt it back with correct key: \n {decrypted} \n");
var privateKey = cryptoNet.ExportPrivateKey();
var publicKey = cryptoNet.ExportPublicKey();

ICryptoNet decryptClientWithWrongKey = new CryptoNet("wrong key");
var decryptWithWrongKey = decryptClientWithWrongKey.DecryptToString(encrypted);
Console.WriteLine($"4- And we will not be able decrypt it back with wrong key: \n {decryptWithWrongKey} \n");
}
ICryptoNet encryptClient = new CryptoNet(publicKey);
var encrypt = encryptClient.EncryptFromString(ConfidentialDummyData);
Console.WriteLine($"1- We will encrypt following text:\n{ConfidentialDummyData}\n");
Console.WriteLine($"2- To:\n{CryptoNetUtils.BytesToString(encrypt)}\n");

public static void Example_2_With_SelfGenerated_RsaKeyPair_AsymmetricKey()
{
ICryptoNet cryptoNet = new CryptoNet(CryptoNetUtils.LoadFileToString(RsaKeyPair), true);
var encryptClient = cryptoNet.EncryptFromString(ConfidentialDummyData);
Console.WriteLine("1- This time we use a certificate to encrypt");
Console.WriteLine(CryptoNetUtils.BytesToString(encryptClient));

ICryptoNet decryptClient = new CryptoNet(CryptoNetUtils.LoadFileToString(RsaKeyPair), true);
var encrypted4 = decryptClient.DecryptToString(encryptClient);
Console.WriteLine("6- And use the same certificate to decrypt");
Console.WriteLine(encrypted4);
ICryptoNet decryptClient = new CryptoNet(privateKey);
var decrypt = decryptClient.DecryptToString(encrypt);
Console.WriteLine($"3- And we will decrypt it back to:\n{decrypt}\n");
Console.WriteLine();
}

public static void Example_3_SelfGenerated_RsaKeyPair_AsymmetricKey()
public static void Example_2_SelfGenerated_And_Save_AsymmetricKey()
{
ICryptoNet cryptoNet = new CryptoNet("My-Secret-Key");
Console.WriteLine("Example 2");

ICryptoNet cryptoNet = new CryptoNet();

CryptoNetUtils.SaveKey(PrivateKeyFile, cryptoNet.ExportPrivateKey());
CryptoNetUtils.SaveKey(PublicKeyFile, cryptoNet.ExportPublicKey());

var certificate = CryptoNetUtils.LoadFileToString(PrivateKeyFile);
var publicKey = CryptoNetUtils.LoadFileToString(PublicKeyFile);
var privateKey = CryptoNetUtils.LoadFileToString(PrivateKeyFile);
Console.WriteLine($"The private key generated and saved to file {PrivateKeyFile}");
Console.WriteLine(privateKey);

Console.WriteLine(certificate);
Console.WriteLine();
var publicKey = CryptoNetUtils.LoadFileToString(PublicKeyFile);
Console.WriteLine($"\nThe public key generated and saved to file {PublicKeyFile}");
Console.WriteLine(publicKey);
Console.WriteLine();
}

public static void Example_4_With_Encrypt_With_Public_Key_Decrypt_With_SelfGenerated_RsaKeyPair_AsymmetricKey()
// This example depending on example 2
public static void Example_3_Encrypt_With_PublicKey_Decrypt_With_PrivateKey_Of_Content()
{
var certificate = CryptoNetUtils.LoadFileToString(RsaKeyPair);
// Export public key
ICryptoNet cryptoNet = new CryptoNet(certificate, true);
var publicKey = cryptoNet.ExportPublicKey();
CryptoNetUtils.SaveKey(PublicKeyFile, publicKey);

// Import public key and encrypt
var importPublicKey = CryptoNetUtils.LoadFileToString(PublicKeyFile);
ICryptoNet cryptoNetEncryptWithPublicKey = new CryptoNet(importPublicKey, true);
var encryptWithPublicKey = cryptoNetEncryptWithPublicKey.EncryptFromString(ConfidentialDummyData);
Console.WriteLine("1- This time we use a certificate public key to encrypt");
Console.WriteLine(CryptoNetUtils.BytesToString(encryptWithPublicKey));

ICryptoNet cryptoNetDecryptWithPublicKey = new CryptoNet(certificate, true);
var decryptWithPrivateKey = cryptoNetDecryptWithPublicKey.DecryptToString(encryptWithPublicKey);
Console.WriteLine("6- And use the same certificate to decrypt");
Console.WriteLine(decryptWithPrivateKey);
Console.WriteLine("Example 3");

ICryptoNet cryptoNetWithPublicKey = new CryptoNet(CryptoNetUtils.LoadFileToString(PublicKeyFile));
var encryptWithPublicKey = cryptoNetWithPublicKey.EncryptFromString(ConfidentialDummyData);
Console.WriteLine($"1- We load public key to encrypt following text:\n{ConfidentialDummyData}\n");
Console.WriteLine($"2- To:\n{CryptoNetUtils.BytesToString(encryptWithPublicKey)}\n");

ICryptoNet cryptoNetWithPrivateKey = new CryptoNet(CryptoNetUtils.LoadFileToString(PrivateKeyFile));
var decryptWithPrivateKey = cryptoNetWithPrivateKey.DecryptToString(encryptWithPublicKey);
Console.WriteLine($"3- And we load private key to decrypt it back to:\n{decryptWithPrivateKey}");
}

public static void Example_4_Using_X509_Certificate()
{
Console.WriteLine("Example 4");

// Find and replace CN=Maytham with your own certificate
X509Certificate2? certificate = CryptoNetUtils.GetCertificateFromStore("CN=Maytham");

ICryptoNet cryptoNetWithPublicKey = new CryptoNet(certificate, KeyHelper.KeyType.PublicKey);
var encryptWithPublicKey = cryptoNetWithPublicKey.EncryptFromString(ConfidentialDummyData);
Console.WriteLine($"1- We get public key from Certificate to encrypt following text:\n{ConfidentialDummyData}\n");
Console.WriteLine($"2- To:\n{CryptoNetUtils.BytesToString(encryptWithPublicKey)}\n");

ICryptoNet cryptoNetWithPrivateKey = new CryptoNet(certificate, KeyHelper.KeyType.PrivateKey);
var decryptWithPrivateKey = cryptoNetWithPrivateKey.DecryptToString(encryptWithPublicKey);
Console.WriteLine($"3- And we get private key from Certificate to decrypt it back to:\n{decryptWithPrivateKey}");
}

}
118 changes: 88 additions & 30 deletions CryptoNetLib/CryptoNet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,47 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using CryptoNetLib.helpers;
using static CryptoNetLib.helpers.KeyHelper;

namespace CryptoNetLib
{
public class CryptoNet : ICryptoNet
{
private readonly RSACryptoServiceProvider _rsa;
private readonly RSA _rsa;

/// <summary>
/// There are 2 way to encrypt and decrypt
/// 1. Symmetric way (By default)
/// Same key is used to encrypt and decrypt with.
/// 2. Asymmetric way
/// You have 2 keys, Private and Public key.
/// Use Public key to encrypt with and rasKey should set to true
/// Use Private key to decrypt with and rasKey should set to true
/// You need to generate RSA key pair first (Private/Public key).
/// You can pass 2 type of keys, Private and Public key.
/// Use Public key to encrypt with.
/// Use Private key to decrypt with.
/// You need to generate RSA key pair first
/// use ExportPrivateKey method for generating Private key.
/// use ExportPublicKey method for generating Public key.
/// </summary>
/// <param name="symmetricKeyOrAsymmetricKey"></param>
/// <param name="rsaKey"></param>
public CryptoNet(string symmetricKeyOrAsymmetricKey, bool rsaKey = false)
/// <param name="asymmetricKey"></param>
public CryptoNet(string? asymmetricKey = null)
{
if (string.IsNullOrWhiteSpace(symmetricKeyOrAsymmetricKey))
throw new Exception("Missing symmetric key Or asymmetric key");

var parameters = new CspParameters();
if (!rsaKey)
parameters.KeyContainerName = symmetricKeyOrAsymmetricKey;

_rsa = new RSACryptoServiceProvider(parameters);
_rsa.PersistKeyInCsp = true;
_rsa = RSA.Create();
_rsa.KeySize = 2048;
if (!string.IsNullOrEmpty(asymmetricKey))
{
_rsa.FromXmlString(asymmetricKey);
}
}

if (rsaKey)
_rsa.FromXmlString(symmetricKeyOrAsymmetricKey);
/// <summary>
/// Import certificate from your computer
/// You can use helper method like:
/// X509Certificate2 certificate = CryptoNetUtils.GetCertificateFromStore("CN=CERTIFICATE_NAME");
/// </summary>
/// <param name="certificate"></param>
public CryptoNet(X509Certificate2? certificate, KeyHelper.KeyType keyType)
{
RSAParameters @params = CryptoNetUtils.GetParameters(certificate, keyType);
_rsa = RSA.Create();
_rsa.KeySize = 2048;
_rsa.ImportParameters(@params);
}

/// <summary>
Expand All @@ -51,25 +57,77 @@ public CryptoNet(string symmetricKeyOrAsymmetricKey, bool rsaKey = false)
/// <returns></returns>
public KeyType GetKeyType()
{
return _rsa.GetKeyType();
var privateKey = this.ExportPrivateKey();
if (
privateKey.Contains("RSAKeyValue") &&
privateKey.Contains("Modulus") &&
privateKey.Contains("Exponent") &&
privateKey.Contains("<P>") &&
privateKey.Contains("<DP>") &&
privateKey.Contains("<DQ>") &&
privateKey.Contains("<InverseQ>") &&
privateKey.Contains("<D>")
)
{
return KeyType.PrivateKey;
}

var publicKey = this.ExportPublicKey();
if (
publicKey.Contains("RSAKeyValue") &&
publicKey.Contains("Modulus") &&
publicKey.Contains("Exponent") &&
!publicKey.Contains("<P>") &&
!publicKey.Contains("<DP>") &&
!publicKey.Contains("<DQ>") &&
!publicKey.Contains("<InverseQ>") &&
!publicKey.Contains("<D>")
)
{
return KeyType.PublicKey;
}

return KeyType.NotSet;
}

/// <summary>
/// Export Public Key
/// Generate and Export Public Key
/// </summary>
/// <returns></returns>
public string ExportPublicKey()
{
return _rsa.ToXmlString(false);
try
{
return _rsa.ToXmlString(false);
}
catch (CryptographicException e)
{
return e.Message;
}
catch (Exception e)
{
return e.Message;
}
}

/// <summary>
/// Export Private Key (RSA Pair key)
/// Generate and Export Private Key (RSA Pairs both Private and Public key)
/// </summary>
/// <returns></returns>
public string ExportPrivateKey()
{
return _rsa.ToXmlString(true);
try
{
return _rsa.ToXmlString(true);
}
catch (CryptographicException e)
{
return e.Message;
}
catch (Exception e)
{
return e.Message;
}
}

/// <summary>
Expand Down Expand Up @@ -105,7 +163,7 @@ private byte[] EncryptContent(byte[] content)
};
var transform = rjndl.CreateEncryptor();

var keyEncrypted = _rsa.Encrypt(rjndl.Key, false);
var keyEncrypted = _rsa.Encrypt(rjndl.Key, RSAEncryptionPadding.OaepSHA1);

var lKey = keyEncrypted.Length;
var lenK = BitConverter.GetBytes(lKey);
Expand Down Expand Up @@ -204,7 +262,7 @@ private byte[] DecryptContent(byte[] bytes)
inMs.Seek(8 + lenK, SeekOrigin.Begin);
inMs.Read(iv, 0, lenIv);

var keyDecrypted = _rsa.Decrypt(keyEncrypted, false);
var keyDecrypted = _rsa.Decrypt(keyEncrypted, RSAEncryptionPadding.OaepSHA1);

var transform = rjndl.CreateDecryptor(keyDecrypted, iv);

Expand Down
Loading

0 comments on commit 0c0ce49

Please sign in to comment.