Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

Commit

Permalink
Add Initial project (#1)
Browse files Browse the repository at this point in the history
* Add Initial project

Motivations
----
Create an initial project for an easy to use and maintain Cryptography library

Modifications
----
* Initial Cryptography related services for dependency injection, encryption, decryption, signing, and verifying signatures
* Initial Security Keys:
  * Rsa
  * Aes
* Unit Tests
* github workflows

Result
----
Open source Cryptography library with easy to use interfaces and Security keys and maintainability

* workflow adjustmemts

* more

* more

* Update publishPackage

* concurrency

* Typos..

* Remove unnecessary test
  • Loading branch information
BlankDev117 authored Jul 25, 2023
1 parent 0ba6836 commit 00cc736
Show file tree
Hide file tree
Showing 47 changed files with 2,080 additions and 1 deletion.
33 changes: 33 additions & 0 deletions .github/workflows/cd-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: .NET CD Automation

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:

build:
runs-on: windows-latest
strategy:
matrix:
dotnet-version: [ '6.0.x' ]

steps:
- uses: actions/checkout@v2
- name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
uses: actions/[email protected]
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Restore dependencies
run: >-
dotnet restore ./src/${{ github.event.repository.name }}.sln
- name: Build
run: dotnet build --no-restore ./src/${{ github.event.repository.name }}.sln
- name: Test
run: dotnet test --no-build --verbosity normal ./src/${{ github.event.repository.name }}.sln
28 changes: 28 additions & 0 deletions .github/workflows/publishPackage-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Upload dotnet package

on:
workflow_dispatch:
release:
types: [created]

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Get the version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x' # SDK Version to use.
env:
NUGET_AUTH_TOKEN: ${{secrets.NUGET_TOKEN}}
- run: dotnet build --configuration Release ./src /p:Version=${{ steps.get_version.outputs.VERSION }}
- name: Create the package
run: dotnet pack --configuration Release ./src -o . /p:Version=${{ steps.get_version.outputs.VERSION }}
- name: Publish the package to GPR
run: dotnet nuget push ./*.nupkg --api-key ${{secrets.NUGET_TOKEN}} --source https://api.nuget.org/v3/index.json
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,35 @@
# Common.Security.Cryptography
Easy to use Cryptography
-----
Cryptography should be easy to use and access and provide this capability in a way that is extensible and updatable. Rather than needing to handle and manage resources around the various cryptography implementations, this library provides an alternative to the normal patterns for using cryptographic functions and allows the use of the async/await and dependency injection patterns.

# Security Keys
-----
A `security key` is an entity that is able to provide the requirements of encyption, decryption, signing, and validating signatures. These are backed by strong cryptographic functions such as AES, RSA, and others.

The security key domain is made up of subdomains of many types of security key. Each subdomain will include the following objects and entities:

`Models`:
* KeyGenerationParameters
* KeyExchangeInformation
* KeyInformation

`Services`:
* SecurityKeyGenerator
* SecurityKey

`Dependency Injection`:
* SecurityKeyDescriptor

The model objects are used by the `SecurityKeyDescriptor`, `ISecurityKeyProvider`, and `SecurityKeyGenerator` to create the security through the points of entry into the library. They act as the gatway to the subdomain and allows the subdomain to be implemented as needed without adding major complexity to the base library. Additionally, generator and allows for clear separation of any necessary initialization tasks from the underlying security key itself.

`KeyInformation` is the central data component that allows the security key to operate, containing the necessary data to construct the key. `KeyExchangeInformation` is the publicly transmittable data that can be sent across the network and then used to reconstruct the required security key on the partner's connection. This provides the ease of use for a consumer of the library by not needing to know what data can/can not be transmitted for secure data transmission.

Additionally, this design should allow the ease of creating and experimenting with new cryptographic algorithms by allowing a simple set of core interfaces and parent models to integrate new security keys into the library for other projects, without needing updates to the main repository -- though updates to strong cryptographic functions or security enhancements to the library in general are welcome!

# Cryptography
----
The main point of entry into the APIs is via the `ICryptographyService`. In this way, the usage of a broad number of different cryptographic algorithms and related hash functions can be consolidated to one place, providing ease of access. Simply providing the necessary model parameters will generate a usable key for cryptographic purposes. All that should be required to construct the desired security key is simply the parameters desired for the function to operate.

# Contributions
----
Cryptography and data security are important for network and other data management. Feel free to create issues and updates to the library to help it grow and gain access to further security keys.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Common.Security.Cryptography\Common.Security.Cryptography.csproj" />
</ItemGroup>

</Project>
47 changes: 47 additions & 0 deletions src/Common.Security.Cryptography.UnitTests/IntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Common.Security.Cryptography.Keys.Rsa.Models;
using Common.Security.Cryptography.Ports;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace Common.Security.Cryptography.UnitTests
{
public class IntegrationTests
{
#region End to End

[Fact]
public async Task EndToEnd_Testing()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddCryptography();
var serviceProvider = serviceCollection.BuildServiceProvider();

var cryptographyService = serviceProvider.GetRequiredService<ICryptographyService>();
var personalKey = cryptographyService.CreateKey(1024, new RsaKeyGenerationParameters());
var otherKey = cryptographyService.CreateKey(1024, new RsaKeyGenerationParameters());

var personalExchangeKeyInformation = personalKey.KeyInformation.GetKeyExhangeInformation() as RsaKeyExchangeInformation;
var otherExchangeKeyInformation = otherKey.KeyInformation.GetKeyExhangeInformation() as RsaKeyExchangeInformation;

var personalExchangeKey = cryptographyService.CreateKey(personalKey.KeyInformation.RawKey, otherExchangeKeyInformation);
var otherExchangeKey = cryptographyService.CreateKey(otherKey.KeyInformation.RawKey, personalExchangeKeyInformation);

var text = "Hello world, to a new wonderful day!";
var bytes = Encoding.UTF8.GetBytes(text);
var message = await cryptographyService.SignAndEncryptMessageAsync(bytes, personalExchangeKey, HashAlgorithmName.SHA1);

Assert.False(bytes.SequenceEqual(message.EncryptedData));

var decrypted = await cryptographyService.ValidateAndDecryptMessageAsync(message, otherExchangeKey, HashAlgorithmName.SHA1);
var decryptedText = Encoding.UTF8.GetString(decrypted);

Assert.Equal(text, decryptedText);
}

#endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
using Common.Security.Cryptography.Exceptions;
using Common.Security.Cryptography.Internal.Services;
using Common.Security.Cryptography.Model;
using Common.Security.Cryptography.Ports;
using Common.Security.Cryptography.UnitTests.TestData;
using Moq;
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace Common.Security.Cryptography.UnitTests.Internal.Services
{
public class CryptographyServiceTests
{
#region Variables

private readonly Mock<ISecurityKeyProvider> _mockSecurityKeyProvider;

private readonly CryptographyService _cryptographyService;

#endregion

#region Constructors

public CryptographyServiceTests()
{
_mockSecurityKeyProvider = new Mock<ISecurityKeyProvider>();

_cryptographyService = new CryptographyService(_mockSecurityKeyProvider.Object);
}

#endregion

#region CreateKey (int, KeyGenerationParameters)

[Fact]
public void Create_KeyGenerationParameters_ReturnsSecurityKey()
{
// Arrange
var mockKey = new Mock<ISecurityKey>();
_mockSecurityKeyProvider.Setup(m => m.GetNew(It.IsAny<int>(), It.IsAny<SecurityKeyGenerationParameters>()))
.Returns(mockKey.Object);

// Act
var key = _cryptographyService.CreateKey(1, new TestGenerationParameters());

// Assert
Assert.Equal(mockKey.Object, key);
}

#endregion

#region CreateKey (byte[], SecurityKeyExchangeInformation)

[Fact]
public void Create_KeyExchangeInformation_ReturnsSecurityKey()
{
// Arrange
var mockKey = new Mock<ISecurityKey>();
_mockSecurityKeyProvider.Setup(m => m.GetFrom(It.IsAny<byte[]>(), It.IsAny<SecurityKeyExchangeInformation>()))
.Returns(mockKey.Object);

// Act
var key = _cryptographyService.CreateKey(new byte[0], new TestKeyExchangeInformation());

// Assert
Assert.Equal(mockKey.Object, key);
}

#endregion

#region CreateKey (KeyInformation)

[Fact]
public void Create_KeyInformation_ReturnsSecurityKey()
{
// Arrange
var mockKey = new Mock<ISecurityKey>();
_mockSecurityKeyProvider.Setup(m => m.GetFrom(It.IsAny<SecurityKeyInformation>()))
.Returns(mockKey.Object);

// Act
var key = _cryptographyService.CreateKey(new TestKeyInformation());

// Assert
Assert.Equal(mockKey.Object, key);
}

#endregion

#region SignAndEncryptMessageAsync

[Fact]
public async Task SignAndEncryptMessageAsync_NullData_ThrowsArgumentNullException()
{
// Arrange/Act/Assert
await Assert.ThrowsAsync<ArgumentNullException>(() => _cryptographyService.SignAndEncryptMessageAsync(null, new Mock<ISecurityKey>().Object, HashAlgorithmName.MD5));
}

[Fact]
public async Task SignAndEncryptMessageAsync_NullSecurityKey_ThrowsArgumentNullException()
{
// Arrange/Act/Assert
await Assert.ThrowsAsync<ArgumentNullException>(() => _cryptographyService.SignAndEncryptMessageAsync(new byte[0], null, HashAlgorithmName.MD5));
}

[Fact]
public async Task SignAndEncryptMessageAsync_Valid_ReturnsSuccessfully()
{
// Arrange
var expectedData = new byte[]
{
0, 1, 0, 1, 1, 1, 0
};
var expectedSignature = new byte[]
{
1, 1, 0, 0, 1, 0, 1
};

var mockSecurityKey = new Mock<ISecurityKey>();
mockSecurityKey.Setup(m => m.EncryptAsync(It.IsAny<byte[]>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedData);
mockSecurityKey.Setup(m => m.SignAsync(It.IsAny<byte[]>(), It.IsAny<HashAlgorithmName>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedSignature);

// Act
var result = await _cryptographyService.SignAndEncryptMessageAsync(new byte[0], mockSecurityKey.Object, HashAlgorithmName.SHA256);

// Assert
Assert.True(expectedData.SequenceEqual(result.EncryptedData));
Assert.True(expectedSignature.SequenceEqual(result.Signature));
}

#endregion

#region ValidateAndDecryptMessageAsync

[Fact]
public async Task ValidateAndDecryptMessageAsync_NullData_ThrowsArgumentNullException()
{
// Arrange/Act/Assert
await Assert.ThrowsAsync<ArgumentNullException>(() => _cryptographyService.ValidateAndDecryptMessageAsync(null, new Mock<ISecurityKey>().Object, HashAlgorithmName.MD5));
}

[Fact]
public async Task ValidateAndDecryptMessageAsync_NullSecurityKey_ThrowsArgumentNullException()
{
// Arrange/Act/Assert
await Assert.ThrowsAsync<ArgumentNullException>(() => _cryptographyService.ValidateAndDecryptMessageAsync(new SignedMessage(), null, HashAlgorithmName.MD5));
}

[Fact]
public async Task ValidateAndDecryptMessageAsync_InvalidSignature_ThrowsSignedMessageValidationException()
{
// Arrange
var mockSecurityKey = new Mock<ISecurityKey>();
mockSecurityKey.Setup(m => m.ValidateSignatureAsync(It.IsAny<byte[]>(), It.IsAny<byte[]>(),
It.IsAny<HashAlgorithmName>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(false);

// Act/Assert
await Assert.ThrowsAsync<SignedMessageValidationException>(() => _cryptographyService.ValidateAndDecryptMessageAsync(new SignedMessage(), mockSecurityKey.Object,HashAlgorithmName.MD5));
}

[Fact]
public async Task ValidateAndDecryptMessageAsync_ValidSignature_ReturnsSuccessfully()
{
// Arrange
var expectedData = new byte[]
{
0, 1, 1, 0, 0, 1, 0
};

var mockSecurityKey = new Mock<ISecurityKey>();
mockSecurityKey.Setup(m => m.ValidateSignatureAsync(It.IsAny<byte[]>(), It.IsAny<byte[]>(),
It.IsAny<HashAlgorithmName>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
mockSecurityKey.Setup(m => m.DecryptAsync(It.IsAny<byte[]>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedData);

// Act
var result = await _cryptographyService.ValidateAndDecryptMessageAsync(new SignedMessage(), mockSecurityKey.Object,
HashAlgorithmName.MD5);

// Result

}


#endregion
}
}
Loading

0 comments on commit 00cc736

Please sign in to comment.