mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-21 00:29:29 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d20e5bd308 | |||
| c9d1ba8773 | |||
| ce3cac9fa2 | |||
| a2d23ed716 | |||
| 7660893087 | |||
| 68ec8f983d | |||
| 1711dd2ec2 | |||
| 3b67e45e64 | |||
| 22fa8eccf7 | |||
| 9609b2912c | |||
| a2e99cb263 | |||
| f9088a5aef | |||
| d67ee95916 | |||
| 8bfb8f1757 | |||
| a6572a1d15 | |||
| 646b6dc253 | |||
| 0b2a76143b | |||
| 019d7e240d |
@@ -4,10 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@@ -51,14 +48,23 @@ jobs:
|
|||||||
- name: Build SystemExtensions.NetStandard.DependencyInjection project
|
- name: Build SystemExtensions.NetStandard.DependencyInjection project
|
||||||
run: dotnet build SystemExtensions.NetStandard.DependencyInjection -c $env:Configuration
|
run: dotnet build SystemExtensions.NetStandard.DependencyInjection -c $env:Configuration
|
||||||
|
|
||||||
- name: Push nuget package
|
- name: Build SystemExtensions.NetStandard.Security project
|
||||||
|
run: dotnet build SystemExtensions.NetStandard.Security -c $env:Configuration
|
||||||
|
|
||||||
|
- name: Push SystemExtensions.NetStandard nuget package
|
||||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||||
with:
|
with:
|
||||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
PROJECT_FILE_PATH: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||||
|
|
||||||
- name: Push nuget package
|
- name: Push SystemExtensions.NetStandard.DependencyInjection nuget package
|
||||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||||
with:
|
with:
|
||||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
|
PROJECT_FILE_PATH: SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
|
||||||
|
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||||
|
|
||||||
|
- name: Push SystemExtensions.NetStandard.Security nuget package
|
||||||
|
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||||
|
with:
|
||||||
|
PROJECT_FILE_PATH: SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj
|
||||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||||
@@ -22,6 +22,7 @@ jobs:
|
|||||||
Solution_Path: SystemExtensions.sln
|
Solution_Path: SystemExtensions.sln
|
||||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
|
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
|
||||||
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
|
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
|
||||||
|
Sec_Test_Project_Path: SystemExtensions.NetStandard.Security.Tests\SystemExtensions.NetStandard.Security.Tests.csproj
|
||||||
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||||
Actions_Allow_Unsecure_Commands: true
|
Actions_Allow_Unsecure_Commands: true
|
||||||
|
|
||||||
@@ -45,6 +46,9 @@ jobs:
|
|||||||
- name: Execute DI Unit Tests
|
- name: Execute DI Unit Tests
|
||||||
run: dotnet test $env:DI_Test_Project_Path
|
run: dotnet test $env:DI_Test_Project_Path
|
||||||
|
|
||||||
|
- name: Execute Security Unit Tests
|
||||||
|
run: dotnet test $env:Sec_Test_Project_Path
|
||||||
|
|
||||||
- name: Restore Project
|
- name: Restore Project
|
||||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||||
env:
|
env:
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using System.Extensions.Configuration;
|
using System.Configuration;
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Extensions.Configuration;
|
using System.Configuration;
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Extensions.Configuration;
|
using System.Configuration;
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System.Extensions.Configuration;
|
using System.Configuration;
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using Microsoft.Extensions.Options;
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Extensions.Configuration;
|
using System.Configuration;
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Extensions.Configuration;
|
using System.Configuration;
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Configuration;
|
||||||
using System.Extensions.Configuration;
|
using System.Extensions.Configuration;
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
namespace SystemExtensions.DependencyInjection.Tests.Configuration
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Logging;
|
using System.Logging;
|
||||||
using System.Windows.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
namespace SystemExtensions.DependencyInjection.Tests.Logging
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public sealed class DefaultOptionsManager : IOptionsManager
|
public sealed class DefaultOptionsManager : IOptionsManager
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public interface ILiveOptions<T> : IOptions<T>
|
public interface ILiveOptions<T> : IOptions<T>
|
||||||
where T : class
|
where T : class
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
|
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
|
||||||
where T : class
|
where T : class
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public interface IOptionsManager
|
public interface IOptionsManager
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public interface IUpdateableOptions<out T> : IOptions<T>
|
public interface IUpdateableOptions<out T> : IOptions<T>
|
||||||
where T : class
|
where T : class
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Slim.Resolvers;
|
using Slim.Resolvers;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public sealed class LiveOptionsResolver : IDependencyResolver
|
public sealed class LiveOptionsResolver : IDependencyResolver
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using Slim.Resolvers;
|
using Slim.Resolvers;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
|
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
using System.Extensions;
|
using System.Extensions;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
|
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
|
||||||
where T : class
|
where T : class
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Slim.Resolvers;
|
using Slim.Resolvers;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public sealed class OptionsResolver : IDependencyResolver
|
public sealed class OptionsResolver : IDependencyResolver
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
using Slim.Resolvers;
|
using Slim.Resolvers;
|
||||||
|
using System.Extensions.Configuration;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Configuration
|
||||||
{
|
{
|
||||||
public sealed class UpdateableOptionsResolver : IDependencyResolver
|
public sealed class UpdateableOptionsResolver : IDependencyResolver
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
using System.Extensions;
|
using System.Configuration;
|
||||||
|
|
||||||
namespace System.Extensions.Configuration
|
namespace System.Extensions.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-2
@@ -1,8 +1,7 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Slim;
|
using Slim;
|
||||||
using System.Extensions;
|
using System.Configuration;
|
||||||
using System.Extensions.Configuration;
|
|
||||||
using System.Http;
|
using System.Http;
|
||||||
using System.Logging;
|
using System.Logging;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace System.Logging
|
|||||||
public sealed class CVLoggerProvider : ICVLoggerProvider
|
public sealed class CVLoggerProvider : ICVLoggerProvider
|
||||||
{
|
{
|
||||||
private readonly ILogsWriter logsManager;
|
private readonly ILogsWriter logsManager;
|
||||||
private CorrelationVector correlationVector;
|
private readonly CorrelationVector correlationVector;
|
||||||
|
|
||||||
public CVLoggerProvider(ILogsWriter logsWriter)
|
public CVLoggerProvider(ILogsWriter logsWriter)
|
||||||
{
|
{
|
||||||
@@ -28,11 +28,6 @@ namespace System.Logging
|
|||||||
|
|
||||||
public ILogger CreateLogger(string categoryName)
|
public ILogger CreateLogger(string categoryName)
|
||||||
{
|
{
|
||||||
if (this.correlationVector is not null)
|
|
||||||
{
|
|
||||||
this.correlationVector = CorrelationVector.Extend(this.correlationVector.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CVLogger(categoryName, this);
|
return new CVLogger(categoryName, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
using Slim.Resolvers;
|
using Slim.Resolvers;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace System.Windows.Extensions.Logging
|
namespace System.Logging
|
||||||
{
|
{
|
||||||
public sealed class LoggerResolver : IDependencyResolver
|
public sealed class LoggerResolver : IDependencyResolver
|
||||||
{
|
{
|
||||||
@@ -25,7 +25,7 @@ namespace System.Windows.Extensions.Logging
|
|||||||
}
|
}
|
||||||
else if (type == typeof(ILogger))
|
else if (type == typeof(ILogger))
|
||||||
{
|
{
|
||||||
return ResolveLogger(serviceProvider, type);
|
return ResolveLogger(serviceProvider);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ namespace System.Windows.Extensions.Logging
|
|||||||
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
|
return createLoggerMethod.MakeGenericMethod(categoryTypes.First()).Invoke(null, new object[] { loggerFactory });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object ResolveLogger(Slim.IServiceProvider serviceProvider, Type type)
|
private static object ResolveLogger(Slim.IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
|
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
|
||||||
return loggerFactory.CreateLogger(string.Empty);
|
return loggerFactory.CreateLogger(string.Empty);
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Version>1.0.0</Version>
|
<Version>1.1.2</Version>
|
||||||
<Authors>Alexandru Macocian</Authors>
|
<Authors>Alexandru Macocian</Authors>
|
||||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using SystemExtensions.NetStandard.Security.Encryption;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class AesEncrypterTests
|
||||||
|
{
|
||||||
|
private ISymmetricEncrypter symmetricEncrypter;
|
||||||
|
private string keyString;
|
||||||
|
private byte[] keyBytes;
|
||||||
|
private byte[] ivBytes;
|
||||||
|
private string ivString;
|
||||||
|
private string toEncryptString;
|
||||||
|
private byte[] toEncryptBytes;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void TestInitialize()
|
||||||
|
{
|
||||||
|
this.symmetricEncrypter = new AesEncrypter();
|
||||||
|
this.keyBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
|
||||||
|
this.keyString = Convert.ToBase64String(this.keyBytes);
|
||||||
|
this.ivBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
|
||||||
|
this.ivString = Convert.ToBase64String(this.ivBytes);
|
||||||
|
this.toEncryptBytes = Encoding.UTF8.GetBytes("toEncrypt");
|
||||||
|
this.toEncryptString = Convert.ToBase64String(this.toEncryptBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EncryptDecryptStringWithStringKeyStringIv()
|
||||||
|
{
|
||||||
|
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptString).ConfigureAwait(false);
|
||||||
|
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
|
||||||
|
|
||||||
|
this.toEncryptString.Should().Be(decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EncryptDecryptStringWithByteKeyByteIv()
|
||||||
|
{
|
||||||
|
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptString).ConfigureAwait(false);
|
||||||
|
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
|
||||||
|
|
||||||
|
this.toEncryptString.Should().Be(decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EncryptDecryptByteWithStringKeyStringIv()
|
||||||
|
{
|
||||||
|
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptBytes).ConfigureAwait(false);
|
||||||
|
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
|
||||||
|
|
||||||
|
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EncryptDecryptByteWithByteKeyByteIv()
|
||||||
|
{
|
||||||
|
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptBytes).ConfigureAwait(false);
|
||||||
|
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
|
||||||
|
|
||||||
|
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EncryptDecryptStreamWithStringKeyStringIv()
|
||||||
|
{
|
||||||
|
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
|
||||||
|
encrypted.Position = 0;
|
||||||
|
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
|
||||||
|
|
||||||
|
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task EncryptDecryptStreamWithByteKeyByteIv()
|
||||||
|
{
|
||||||
|
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
|
||||||
|
encrypted.Position = 0;
|
||||||
|
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
|
||||||
|
|
||||||
|
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetEncryptionStreamReturnsCryptoStream()
|
||||||
|
{
|
||||||
|
var encryptionStream = this.symmetricEncrypter.GetEncryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
|
||||||
|
encryptionStream.Should().BeAssignableTo<CryptoStream>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetDecryptionStreamReturnsCryptoStream()
|
||||||
|
{
|
||||||
|
var encryptionStream = this.symmetricEncrypter.GetDecryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
|
||||||
|
encryptionStream.Should().BeAssignableTo<CryptoStream>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Rng;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CryptoRngProviderTests
|
||||||
|
{
|
||||||
|
private CryptoRngProvider cryptoRngProvider;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void TestInitialize()
|
||||||
|
{
|
||||||
|
this.cryptoRngProvider = new CryptoRngProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetBytes_ShouldSetValues()
|
||||||
|
{
|
||||||
|
var bytes = new byte[100];
|
||||||
|
|
||||||
|
this.cryptoRngProvider.GetBytes(bytes);
|
||||||
|
|
||||||
|
bytes.All(b => b == 0).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetNonZeroBytes_ShouldSetNonZeroValues()
|
||||||
|
{
|
||||||
|
var bytes = new byte[100];
|
||||||
|
|
||||||
|
this.cryptoRngProvider.GetNonZeroBytes(bytes);
|
||||||
|
|
||||||
|
bytes.All(b => b != 0).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetBytes_ShouldReturnBytes()
|
||||||
|
{
|
||||||
|
var bytes = this.cryptoRngProvider.GetBytes(10);
|
||||||
|
|
||||||
|
bytes.Length.Should().Be(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetNonZeroBytes_ShouldReturnBytes()
|
||||||
|
{
|
||||||
|
var bytes = this.cryptoRngProvider.GetNonZeroBytes(10);
|
||||||
|
|
||||||
|
bytes.Length.Should().Be(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.Encryption;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class SecureStringTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureString_NewSecureString_ReturnsValue()
|
||||||
|
{
|
||||||
|
var str = new SecureString("hello");
|
||||||
|
|
||||||
|
str.Value.Should().Be("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureStringEmpty_AreEqual()
|
||||||
|
{
|
||||||
|
var str = SecureString.Empty;
|
||||||
|
str.Should().Be(SecureString.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureStringEmpty_Equals_StringEmpty()
|
||||||
|
{
|
||||||
|
var ss = SecureString.Empty;
|
||||||
|
var s = string.Empty;
|
||||||
|
|
||||||
|
ss.Should().Be(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureString_Equals_OtherSecureString()
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString("Hello");
|
||||||
|
var ss2 = new SecureString("Hello");
|
||||||
|
|
||||||
|
ss1.Equals(ss2).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("hello", "hello", true)]
|
||||||
|
[DataRow("hello", "henlo", false)]
|
||||||
|
public void SecureString_EqualOperator_OtherSecureString(string str1, string str2, bool isEqual)
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString(str1);
|
||||||
|
var ss2 = new SecureString(str2);
|
||||||
|
|
||||||
|
(ss1 == ss2).Should().Be(isEqual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("hello", "hello", false)]
|
||||||
|
[DataRow("hello", "henlo", true)]
|
||||||
|
public void SecureString_DifferentOperator_OtherSecureString(string str1, string str2, bool isDifferent)
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString(str1);
|
||||||
|
var ss2 = new SecureString(str2);
|
||||||
|
|
||||||
|
(ss1 != ss2).Should().Be(isDifferent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("hello", "hello", true)]
|
||||||
|
[DataRow("hello", "henlo", false)]
|
||||||
|
public void SecureString_EqualOperator_String(string str1, string str2, bool isEqual)
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString(str1);
|
||||||
|
|
||||||
|
(ss1 == str2).Should().Be(isEqual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow("hello", "hello", false)]
|
||||||
|
[DataRow("hello", "henlo", true)]
|
||||||
|
public void SecureString_DifferentOperator_String(string str1, string str2, bool isDifferent)
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString(str1);
|
||||||
|
|
||||||
|
(ss1 != str2).Should().Be(isDifferent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureString_PlusOperator_SecureString()
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString("Hello ");
|
||||||
|
var ss2 = new SecureString("World");
|
||||||
|
|
||||||
|
(ss1 + ss2).Should().Be("Hello World");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureString_PlusOperator_String()
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString("Hello ");
|
||||||
|
var ss2 = "World";
|
||||||
|
|
||||||
|
(ss1 + ss2).Should().Be("Hello World");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureString_PlusOperator_Char()
|
||||||
|
{
|
||||||
|
var ss1 = new SecureString("Hello ");
|
||||||
|
var c = 'W';
|
||||||
|
|
||||||
|
(ss1 + c).Should().Be("Hello W");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SecureString_WithOptionalEntropy_Matches()
|
||||||
|
{
|
||||||
|
SecureString.AddOptionalEntropy(new byte[] { 10, 20, 25, 34, 56, 12, 10, 81, 200, 155, 123, 144, 123, 192, 122, 1 });
|
||||||
|
var ss1 = new SecureString("Hello");
|
||||||
|
var ss2 = new SecureString("Hello");
|
||||||
|
|
||||||
|
ss1.Should().Be(ss2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using SystemExtensions.NetStandard.Security.Hashing;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public sealed class Sha256HashingServiceTests
|
||||||
|
{
|
||||||
|
private readonly IHashingService hashingService = new Sha256HashingService();
|
||||||
|
private string toHashtString;
|
||||||
|
private byte[] toHashtBytes;
|
||||||
|
private Stream toHashStream;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void TestInitialize()
|
||||||
|
{
|
||||||
|
this.toHashtBytes = Encoding.UTF8.GetBytes("toEncrypt");
|
||||||
|
this.toHashtString = Convert.ToBase64String(this.toHashtBytes);
|
||||||
|
this.toHashStream = new MemoryStream(this.toHashtBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task HashString()
|
||||||
|
{
|
||||||
|
var hash = await this.hashingService.Hash(this.toHashtString).ConfigureAwait(false);
|
||||||
|
hash.Should().BeOfType<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task HashBytes()
|
||||||
|
{
|
||||||
|
var hash = await this.hashingService.Hash(this.toHashtBytes).ConfigureAwait(false);
|
||||||
|
hash.Should().BeOfType<byte[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task HashStream()
|
||||||
|
{
|
||||||
|
var hash = await this.hashingService.Hash(this.toHashStream).ConfigureAwait(false);
|
||||||
|
hash.Should().BeAssignableTo<Stream>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using SystemExtensions.NetStandard.Security.Utilities;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Encryption
|
||||||
|
{
|
||||||
|
public sealed class AesEncrypter : ISymmetricEncrypter
|
||||||
|
{
|
||||||
|
public async Task<string> Decrypt(string key, string iv, string value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(StringToBytes(value));
|
||||||
|
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToString(decryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> Decrypt(byte[] key, byte[] iv, string value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(StringToBytes(value));
|
||||||
|
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToString(decryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<byte[]> Decrypt(string key, string iv, byte[] value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(value);
|
||||||
|
using var decryptedStream = await DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToBytes(decryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(value);
|
||||||
|
using var decryptedStream = await DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToBytes(decryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> Decrypt(string key, string iv, Stream value)
|
||||||
|
{
|
||||||
|
return await DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value)
|
||||||
|
{
|
||||||
|
return await DecryptInternal(key, iv, value).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> Encrypt(string key, string iv, string value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(StringToBytes(value));
|
||||||
|
using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToString(encryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> Encrypt(byte[] key, byte[] iv, string value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(StringToBytes(value));
|
||||||
|
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToString(encryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<byte[]> Encrypt(string key, string iv, byte[] value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(value);
|
||||||
|
using var encryptedStream = await EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToBytes(encryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value)
|
||||||
|
{
|
||||||
|
using var valueStream = BytesToStream(value);
|
||||||
|
using var encryptedStream = await EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||||
|
return StreamToBytes(encryptedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> Encrypt(string key, string iv, Stream value)
|
||||||
|
{
|
||||||
|
if (value is null) throw new ArgumentNullException(nameof(value));
|
||||||
|
|
||||||
|
return await EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value)
|
||||||
|
{
|
||||||
|
if (value is null) throw new ArgumentNullException(nameof(value));
|
||||||
|
|
||||||
|
return await EncryptInternal(key, iv, value).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetEncryptionStream(string key, string iv, Stream outStream)
|
||||||
|
{
|
||||||
|
return GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream)
|
||||||
|
{
|
||||||
|
return GetEncryptionStreamInternal(key, iv, outStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetDecryptionStream(string key, string iv, Stream inStream)
|
||||||
|
{
|
||||||
|
return GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream)
|
||||||
|
{
|
||||||
|
return GetDecryptionStreamInternal(key, iv, inStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] StreamToBytes(Stream value)
|
||||||
|
{
|
||||||
|
value.Position = 0;
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
int read = -1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
read = value.Read(buffer, 0, buffer.Length);
|
||||||
|
ms.Write(buffer, 0, read);
|
||||||
|
} while (read > 0);
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string StreamToString(Stream value)
|
||||||
|
{
|
||||||
|
return Convert.ToBase64String(StreamToBytes(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] StringToBytes(string value)
|
||||||
|
{
|
||||||
|
return Convert.FromBase64String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream BytesToStream(byte[] value)
|
||||||
|
{
|
||||||
|
return new MemoryStream(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<Stream> EncryptInternal(byte[] key, byte[] iv, Stream toEncryptStream)
|
||||||
|
{
|
||||||
|
if (key.Length < 32)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{nameof(key)} must be at least 32 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv.Length < 16)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
key = key.Take(32).ToArray();
|
||||||
|
iv = iv.Take(16).ToArray();
|
||||||
|
|
||||||
|
|
||||||
|
var encryptedMemoryStream = new MemoryStream();
|
||||||
|
using var cryptoStream = GetEncryptionStreamInternal(key, iv, encryptedMemoryStream);
|
||||||
|
await toEncryptStream.CopyToAsync(cryptoStream).ConfigureAwait(false);
|
||||||
|
if (!cryptoStream.HasFlushedFinalBlock)
|
||||||
|
{
|
||||||
|
cryptoStream.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedMemoryStream.Position = 0;
|
||||||
|
return encryptedMemoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<Stream> DecryptInternal(byte[] key, byte[] iv, Stream toDecryptStream)
|
||||||
|
{
|
||||||
|
if (key.Length < 32)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{nameof(key)} must be at least 32 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv.Length < 16)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
key = key.Take(32).ToArray();
|
||||||
|
iv = iv.Take(16).ToArray();
|
||||||
|
|
||||||
|
|
||||||
|
var decryptedMemoryStream = new MemoryStream();
|
||||||
|
using var cryptoStream = GetDecryptionStreamInternal(key, iv, toDecryptStream);
|
||||||
|
await cryptoStream.CopyToAsync(decryptedMemoryStream).ConfigureAwait(false);
|
||||||
|
if (!cryptoStream.HasFlushedFinalBlock)
|
||||||
|
{
|
||||||
|
cryptoStream.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptedMemoryStream.Position = 0;
|
||||||
|
return decryptedMemoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CryptoStream GetEncryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
|
||||||
|
{
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
|
var crypto = aes.CreateEncryptor(key, iv);
|
||||||
|
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Write);
|
||||||
|
return cryptoStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CryptoStream GetDecryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
|
||||||
|
{
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
|
var crypto = aes.CreateDecryptor(key, iv);
|
||||||
|
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Read);
|
||||||
|
return cryptoStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Encryption
|
||||||
|
{
|
||||||
|
public interface ISymmetricEncrypter
|
||||||
|
{
|
||||||
|
Stream GetEncryptionStream(string key, string iv, Stream outStream);
|
||||||
|
Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream);
|
||||||
|
Stream GetDecryptionStream(string key, string iv, Stream inStream);
|
||||||
|
Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream);
|
||||||
|
Task<string> Encrypt(string key, string iv, string value);
|
||||||
|
Task<string> Encrypt(byte[] key, byte[] iv, string value);
|
||||||
|
Task<byte[]> Encrypt(string key, string iv, byte[] value);
|
||||||
|
Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value);
|
||||||
|
Task<Stream> Encrypt(string key, string iv, Stream value);
|
||||||
|
Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value);
|
||||||
|
Task<string> Decrypt(string key, string iv, string value);
|
||||||
|
Task<string> Decrypt(byte[] key, byte[] iv, string value);
|
||||||
|
Task<byte[]> Decrypt(string key, string iv, byte[] value);
|
||||||
|
Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value);
|
||||||
|
Task<Stream> Decrypt(string key, string iv, Stream value);
|
||||||
|
Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace System.Encryption
|
||||||
|
{
|
||||||
|
public sealed class SecureString
|
||||||
|
{
|
||||||
|
private static byte[] optionalEntropy;
|
||||||
|
private byte[] encryptedValue;
|
||||||
|
|
||||||
|
public string Value {
|
||||||
|
get => this.encryptedValue is not null ? Encoding.UTF8.GetString(ProtectedData.Unprotect(this.encryptedValue, optionalEntropy, DataProtectionScope.CurrentUser)) : null;
|
||||||
|
private set => this.encryptedValue = ProtectedData.Protect(Encoding.UTF8.GetBytes(value), optionalEntropy, DataProtectionScope.CurrentUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecureString(string value)
|
||||||
|
{
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is string)
|
||||||
|
{
|
||||||
|
return this == (obj as string);
|
||||||
|
}
|
||||||
|
else if (obj is SecureString)
|
||||||
|
{
|
||||||
|
return this == (obj as SecureString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return base.Equals(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return this.Value.GetHashCode();
|
||||||
|
}
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return this.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly SecureString Empty = new(string.Empty);
|
||||||
|
public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value;
|
||||||
|
public static implicit operator SecureString(string s) => new(s);
|
||||||
|
public static SecureString operator +(SecureString ss1, SecureString ss2)
|
||||||
|
{
|
||||||
|
if (ss1 is null) throw new ArgumentNullException(nameof(ss1));
|
||||||
|
if (ss2 is null) throw new ArgumentNullException(nameof(ss2));
|
||||||
|
|
||||||
|
return new SecureString(ss1.Value + ss2.Value);
|
||||||
|
}
|
||||||
|
public static SecureString operator +(SecureString ss1, string s2)
|
||||||
|
{
|
||||||
|
if (ss1 is null) throw new ArgumentNullException(nameof(ss1));
|
||||||
|
|
||||||
|
return new SecureString(ss1.Value + s2);
|
||||||
|
}
|
||||||
|
public static SecureString operator +(SecureString ss1, char c)
|
||||||
|
{
|
||||||
|
if (ss1 is null) throw new ArgumentNullException(nameof(ss1));
|
||||||
|
|
||||||
|
return new SecureString(ss1.Value + c);
|
||||||
|
}
|
||||||
|
public static bool operator ==(SecureString ss1, SecureString ss2)
|
||||||
|
{
|
||||||
|
return ss1?.Value == ss2?.Value;
|
||||||
|
}
|
||||||
|
public static bool operator !=(SecureString ss1, SecureString ss2)
|
||||||
|
{
|
||||||
|
return !(ss1 == ss2);
|
||||||
|
}
|
||||||
|
public static bool operator ==(SecureString ss1, string s2)
|
||||||
|
{
|
||||||
|
return ss1?.Value == s2;
|
||||||
|
}
|
||||||
|
public static bool operator !=(SecureString ss1, string s2)
|
||||||
|
{
|
||||||
|
return !(ss1?.Value == s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddOptionalEntropy(byte[] entropy)
|
||||||
|
{
|
||||||
|
optionalEntropy = entropy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Hashing
|
||||||
|
{
|
||||||
|
public interface IHashingService
|
||||||
|
{
|
||||||
|
Task<string> Hash(string raw);
|
||||||
|
Task<byte[]> Hash(byte[] raw);
|
||||||
|
Task<Stream> Hash(Stream raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Hashing
|
||||||
|
{
|
||||||
|
public sealed class Sha256HashingService : IHashingService
|
||||||
|
{
|
||||||
|
public async Task<string> Hash(string raw)
|
||||||
|
{
|
||||||
|
using var rawStream = BytesToStream(StringToBytes(raw));
|
||||||
|
using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false);
|
||||||
|
return StreamToString(hashedStream);
|
||||||
|
}
|
||||||
|
public async Task<byte[]> Hash(byte[] raw)
|
||||||
|
{
|
||||||
|
using var rawStream = BytesToStream(raw);
|
||||||
|
using var hashedStream = await HashInternal(rawStream).ConfigureAwait(false);
|
||||||
|
return StreamToBytes(hashedStream);
|
||||||
|
}
|
||||||
|
public async Task<Stream> Hash(Stream raw)
|
||||||
|
{
|
||||||
|
return await HashInternal(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] StreamToBytes(Stream value)
|
||||||
|
{
|
||||||
|
value.Position = 0;
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
int read = -1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
read = value.Read(buffer, 0, buffer.Length);
|
||||||
|
ms.Write(buffer, 0, read);
|
||||||
|
} while (read > 0);
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
private static string StreamToString(Stream value)
|
||||||
|
{
|
||||||
|
return Convert.ToBase64String(StreamToBytes(value));
|
||||||
|
}
|
||||||
|
private static byte[] StringToBytes(string value)
|
||||||
|
{
|
||||||
|
return Convert.FromBase64String(value);
|
||||||
|
}
|
||||||
|
private static Stream BytesToStream(byte[] value)
|
||||||
|
{
|
||||||
|
return new MemoryStream(value);
|
||||||
|
}
|
||||||
|
private static async Task<Stream> HashInternal(Stream raw)
|
||||||
|
{
|
||||||
|
if (raw is null) throw new ArgumentNullException(nameof(raw));
|
||||||
|
|
||||||
|
using var sha256 = SHA256.Create();
|
||||||
|
return await Task.Run(() => new MemoryStream(sha256.ComputeHash(raw)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Macocian Alexandru Victor
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace System.Rng
|
||||||
|
{
|
||||||
|
public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable
|
||||||
|
{
|
||||||
|
private readonly RNGCryptoServiceProvider rngProvider;
|
||||||
|
private bool disposedValue;
|
||||||
|
|
||||||
|
public CryptoRngProvider()
|
||||||
|
{
|
||||||
|
this.rngProvider = new RNGCryptoServiceProvider();
|
||||||
|
}
|
||||||
|
public CryptoRngProvider(CspParameters cspParams)
|
||||||
|
{
|
||||||
|
this.rngProvider = new RNGCryptoServiceProvider(cspParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void GetBytes(byte[] data)
|
||||||
|
{
|
||||||
|
this.rngProvider.GetBytes(data);
|
||||||
|
}
|
||||||
|
public void GetNonZeroBytes(byte[] data)
|
||||||
|
{
|
||||||
|
this.rngProvider.GetNonZeroBytes(data);
|
||||||
|
}
|
||||||
|
public byte[] GetBytes(int byteCount)
|
||||||
|
{
|
||||||
|
var bytes = new byte[byteCount];
|
||||||
|
this.GetBytes(bytes);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
public byte[] GetNonZeroBytes(int byteCount)
|
||||||
|
{
|
||||||
|
var bytes = new byte[byteCount];
|
||||||
|
this.GetNonZeroBytes(bytes);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!this.disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
this.rngProvider.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace System.Rng
|
||||||
|
{
|
||||||
|
public interface ICryptoRngProvider
|
||||||
|
{
|
||||||
|
public void GetBytes(byte[] data);
|
||||||
|
public byte[] GetBytes(int byteCount);
|
||||||
|
public void GetNonZeroBytes(byte[] data);
|
||||||
|
public byte[] GetNonZeroBytes(int byteCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
|
<RootNamespace>System</RootNamespace>
|
||||||
|
<Version>1.1.1</Version>
|
||||||
|
<Authors>Alexandru Macocian</Authors>
|
||||||
|
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="../LICENSE">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath></PackagePath>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace SystemExtensions.NetStandard.Security.Utilities
|
||||||
|
{
|
||||||
|
internal sealed class NotClosingCryptoStream : CryptoStream
|
||||||
|
{
|
||||||
|
public NotClosingCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
|
||||||
|
: base(stream, transform, mode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!this.HasFlushedFinalBlock)
|
||||||
|
this.FlushFinalBlock();
|
||||||
|
|
||||||
|
base.Dispose(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,25 @@
|
|||||||
namespace System.Extensions
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace System.Extensions
|
||||||
{
|
{
|
||||||
public static class ObjectExtensions
|
public static class ObjectExtensions
|
||||||
{
|
{
|
||||||
|
public static T Deserialize<T>(this string serialized)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
if (serialized.IsNullOrWhiteSpace()) throw new ArgumentException("Provided serialized string cannot be null or whitespace", nameof(serialized));
|
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject<T>(serialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Serialize<T>(this T obj)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
if (obj is null) throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
|
return JsonConvert.SerializeObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
public static T Cast<T>(this object obj)
|
public static T Cast<T>(this object obj)
|
||||||
{
|
{
|
||||||
return (T)obj;
|
return (T)obj;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<RootNamespace>System</RootNamespace>
|
<RootNamespace>System</RootNamespace>
|
||||||
<Version>1.3.0</Version>
|
<Version>1.3.1</Version>
|
||||||
<Authors>Alexandru Macocian</Authors>
|
<Authors>Alexandru Macocian</Authors>
|
||||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -18,4 +18,8 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandar
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.DependencyInjection.Tests", "SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj", "{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemExtensions.NetStandard.DependencyInjection.Tests", "SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj", "{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemExtensions.NetStandard.Security", "SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj", "{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemExtensions.NetStandard.Security.Tests", "SystemExtensions.NetStandard.Security.Tests\SystemExtensions.NetStandard.Security.Tests.csproj", "{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -36,6 +40,14 @@ Global
|
|||||||
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
{1AFA1EEF-CEBA-4046-8466-C9B52979B7DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BFC5BEE7-2569-45EA-9713-CDB32EED57AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{341ECE0F-A8DD-49A0-AE3D-B28D72E85130}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Reference in New Issue
Block a user