Encryptor.ClearText and Hasher.SHA1 implemented

master
Inga 🏳‍🌈 7 years ago
parent 197d8a9b93
commit 630c4f7007
  1. 30
      EternalArrowBackup.sln
  2. 70
      Source/Encryptor.ClearText/ClearTextContentEncryptor.cs
  3. 11
      Source/Encryptor.ClearText/EternalArrowBackup.Encryptor.ClearText.csproj
  4. 11
      Source/Hasher.SHA1/EternalArrowBackup.Hasher.SHA1.csproj
  5. 21
      Source/Hasher.SHA1/SHA1ContentHasher.cs
  6. 35
      Tests/Encryptor.ClearText/EncryptorAndHasherTests.cs
  7. 22
      Tests/Encryptor.ClearText/EternalArrowBackup.Encryptor.ClearText.Tests.csproj
  8. 21
      Tests/Hasher.SHA1/EternalArrowBackup.Hasher.SHA1.Tests.csproj
  9. 51
      Tests/Hasher.SHA1/HasherTests.cs

@ -7,6 +7,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{A79A48
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EternalArrowBackup.Contracts", "Source\Contracts\EternalArrowBackup.Contracts.csproj", "{9A363462-23E2-49FB-A65C-7B1CA1400046}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{884B8E01-303A-40CF-8884-D62115F98683}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EternalArrowBackup.Hasher.SHA1", "Source\Hasher.SHA1\EternalArrowBackup.Hasher.SHA1.csproj", "{623151DA-A4E0-4A7F-B600-A51ABCDE7038}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EternalArrowBackup.Encryptor.ClearText", "Source\Encryptor.ClearText\EternalArrowBackup.Encryptor.ClearText.csproj", "{E8D0BBF5-8DA6-49FA-AC86-9F766C203D99}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EternalArrowBackup.Hasher.SHA1.Tests", "Tests\Hasher.SHA1\EternalArrowBackup.Hasher.SHA1.Tests.csproj", "{92AF4CAA-64AF-4A43-A637-CD10FFEB2FEC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EternalArrowBackup.Encryptor.ClearText.Tests", "Tests\Encryptor.ClearText\EternalArrowBackup.Encryptor.ClearText.Tests.csproj", "{0F91FC45-54B3-4BC0-BB3D-83E963EBD00D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -17,11 +27,31 @@ Global
{9A363462-23E2-49FB-A65C-7B1CA1400046}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A363462-23E2-49FB-A65C-7B1CA1400046}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A363462-23E2-49FB-A65C-7B1CA1400046}.Release|Any CPU.Build.0 = Release|Any CPU
{623151DA-A4E0-4A7F-B600-A51ABCDE7038}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{623151DA-A4E0-4A7F-B600-A51ABCDE7038}.Debug|Any CPU.Build.0 = Debug|Any CPU
{623151DA-A4E0-4A7F-B600-A51ABCDE7038}.Release|Any CPU.ActiveCfg = Release|Any CPU
{623151DA-A4E0-4A7F-B600-A51ABCDE7038}.Release|Any CPU.Build.0 = Release|Any CPU
{E8D0BBF5-8DA6-49FA-AC86-9F766C203D99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8D0BBF5-8DA6-49FA-AC86-9F766C203D99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8D0BBF5-8DA6-49FA-AC86-9F766C203D99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8D0BBF5-8DA6-49FA-AC86-9F766C203D99}.Release|Any CPU.Build.0 = Release|Any CPU
{92AF4CAA-64AF-4A43-A637-CD10FFEB2FEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92AF4CAA-64AF-4A43-A637-CD10FFEB2FEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92AF4CAA-64AF-4A43-A637-CD10FFEB2FEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92AF4CAA-64AF-4A43-A637-CD10FFEB2FEC}.Release|Any CPU.Build.0 = Release|Any CPU
{0F91FC45-54B3-4BC0-BB3D-83E963EBD00D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F91FC45-54B3-4BC0-BB3D-83E963EBD00D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F91FC45-54B3-4BC0-BB3D-83E963EBD00D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F91FC45-54B3-4BC0-BB3D-83E963EBD00D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9A363462-23E2-49FB-A65C-7B1CA1400046} = {A79A4872-4289-4429-B616-3E8CEC71ECB8}
{623151DA-A4E0-4A7F-B600-A51ABCDE7038} = {A79A4872-4289-4429-B616-3E8CEC71ECB8}
{E8D0BBF5-8DA6-49FA-AC86-9F766C203D99} = {A79A4872-4289-4429-B616-3E8CEC71ECB8}
{92AF4CAA-64AF-4A43-A637-CD10FFEB2FEC} = {884B8E01-303A-40CF-8884-D62115F98683}
{0F91FC45-54B3-4BC0-BB3D-83E963EBD00D} = {884B8E01-303A-40CF-8884-D62115F98683}
EndGlobalSection
EndGlobal

@ -0,0 +1,70 @@
namespace EternalArrowBackup.Encryptor.ClearText
{
using System;
using System.Text;
using System.Threading.Tasks;
using Contracts.ContentTransformations;
public class ClearTextContentEncryptor : IContentEncryptor
{
public ClearTextContentEncryptor(IContentHasher hasher)
{
this.Hasher = hasher;
}
private IContentHasher Hasher { get; }
public async Task<IDecryptionResult> Decrypt(byte[] encryptedData)
{
var hashLength = encryptedData[encryptedData.Length - 1];
var originalData = new byte[encryptedData.Length - hashLength - 1];
var hashBytes = new byte[hashLength];
Buffer.BlockCopy(encryptedData, 0, originalData, 0, originalData.Length);
Buffer.BlockCopy(encryptedData, originalData.Length, hashBytes, 0, hashBytes.Length);
var expectedHash = Encoding.UTF8.GetString(hashBytes);
var actualHash = await this.Hasher.ComputeHash(originalData);
if (expectedHash != actualHash)
{
return new FailedDecryptionResult();
}
return new SuccessfulDecryptionResult(originalData);
}
public async Task<byte[]> Encrypt(byte[] originalData)
{
var hash = await this.Hasher.ComputeHash(originalData);
var hashBytes = Encoding.UTF8.GetBytes(hash);
if (hashBytes.Length >= 256)
{
throw new Exception("Hash should be shorter than 256 bytes");
}
var result = new byte[originalData.Length + hashBytes.Length + 1];
Buffer.BlockCopy(originalData, 0, result, 0, originalData.Length);
Buffer.BlockCopy(hashBytes, 0, result, originalData.Length, hashBytes.Length);
result[result.Length - 1] = (byte)hashBytes.Length;
return result;
}
private class FailedDecryptionResult : IDecryptionResult
{
public bool IsSuccessful => false;
public byte[] Data => throw new NotImplementedException();
}
private class SuccessfulDecryptionResult : IDecryptionResult
{
public SuccessfulDecryptionResult(byte[] data) => this.Data = data;
public bool IsSuccessful => true;
public byte[] Data { get; }
}
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Contracts\EternalArrowBackup.Contracts.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Contracts\EternalArrowBackup.Contracts.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,21 @@
namespace EternalArrowBackup.Hasher.SHA1
{
using System.Linq;
using System.Threading.Tasks;
using Contracts.ContentTransformations;
public class SHA1ContentHasher : IContentHasher
{
public Task<string> ComputeHash(byte[] content)
{
return Task.Run(() =>
{
using (var sha1 = System.Security.Cryptography.SHA1.Create())
{
var hash = sha1.ComputeHash(content);
return string.Concat(hash.Select(b => b.ToString("x2")));
}
});
}
}
}

@ -0,0 +1,35 @@
namespace EternalArrowBackup.Encryptor.ClearText.Tests
{
using System.Text;
using System.Threading.Tasks;
using EternalArrowBackup.Hasher.SHA1;
using Xunit;
public static class EncryptorAndHasherTests
{
[Theory]
[InlineData("")]
[InlineData("abc")]
[InlineData("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")]
public static async Task TestCorrectDecryption(string message)
{
var messageBytes = Encoding.ASCII.GetBytes(message);
var hasher = new SHA1ContentHasher();
var encryptor = new ClearTextContentEncryptor(hasher);
var encrypted = await encryptor.Encrypt(messageBytes);
var decryptionResult = await encryptor.Decrypt(encrypted);
Assert.True(decryptionResult.IsSuccessful);
Assert.Equal(messageBytes, decryptionResult.Data);
encrypted[0]++;
decryptionResult = await encryptor.Decrypt(encrypted);
Assert.False(decryptionResult.IsSuccessful);
encrypted[0]--;
encrypted[encrypted.Length - 1]--;
decryptionResult = await encryptor.Decrypt(encrypted);
Assert.False(decryptionResult.IsSuccessful);
}
}
}

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Source\Encryptor.ClearText\EternalArrowBackup.Encryptor.ClearText.csproj" />
<ProjectReference Include="..\..\Source\Hasher.SHA1\EternalArrowBackup.Hasher.SHA1.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Source\Hasher.SHA1\EternalArrowBackup.Hasher.SHA1.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

@ -0,0 +1,51 @@
namespace EternalArrowBackup.Hasher.SHA1
{
using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using Xunit;
public static class HasherTests
{
private const int MegabytesPerSecond = 500;
// Test vectors taken from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
[Theory]
[InlineData("A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", "abc")]
[InlineData("84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")]
public static async Task TestHashes(string expectedHash, string inputMessage)
{
var expectedHashFormatted = expectedHash.Replace(" ", string.Empty).ToLowerInvariant();
var hasher = new SHA1ContentHasher();
var messageBytes = Encoding.ASCII.GetBytes(inputMessage);
var actualHash = await hasher.ComputeHash(messageBytes);
Assert.Equal(expectedHashFormatted, actualHash);
}
// Single-threaded SHA1 performance on i5-6500 is around 500MB/s
[Theory]
[InlineData(1, 0, 1)]
[InlineData(1000, 0, 1)]
[InlineData(1000000, 0.5 * 1000 / MegabytesPerSecond, 2 * 1000 / MegabytesPerSecond)]
[InlineData(10000000, 0.5 * 10000 / MegabytesPerSecond, 2 * 10000 / MegabytesPerSecond)]
[InlineData(100000000, 0.5 * 100000 / MegabytesPerSecond, 2 * 100000 / MegabytesPerSecond)]
[InlineData(1000000000, 0.5 * 1000000 / MegabytesPerSecond, 2 * 1000000 / MegabytesPerSecond)]
public static async Task TestPerformance(int length, int minMilliseconds, int maxMilliseconds)
{
var messageBytes = new byte[length];
for (var i = 0; i < length; i++)
{
messageBytes[i] = (byte)((int)(Math.E * length + Math.PI * i) % 256);
}
var hasher = new SHA1ContentHasher();
var stopwatch = new Stopwatch();
stopwatch.Start();
await hasher.ComputeHash(messageBytes);
stopwatch.Stop();
Assert.InRange(stopwatch.ElapsedMilliseconds, minMilliseconds, maxMilliseconds);
}
}
}
Loading…
Cancel
Save