mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Made AesStream handle syncing with the counter of the cipher.
This commit is contained in:
parent
38bcfd9fc1
commit
72e5f4b62e
@ -168,7 +168,7 @@ namespace ServerMaint
|
|||||||
byte[] keyBytes = Encoding.UTF8.GetBytes(upload.Key);
|
byte[] keyBytes = Encoding.UTF8.GetBytes(upload.Key);
|
||||||
byte[] ivBytes = Encoding.UTF8.GetBytes(upload.IV);
|
byte[] ivBytes = Encoding.UTF8.GetBytes(upload.IV);
|
||||||
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||||
AESCryptoStream aesStream = new AESCryptoStream(fs, false, keyBytes, ivBytes, "CTR", "NoPadding", 0);
|
AESCryptoStream aesStream = new AESCryptoStream(fs, false, keyBytes, ivBytes, "CTR", "NoPadding");
|
||||||
|
|
||||||
// We have the data, let's scan it
|
// We have the data, let's scan it
|
||||||
ClamScanResult scanResult = clam.SendAndScanFile(aesStream);
|
ClamScanResult scanResult = clam.SendAndScanFile(aesStream);
|
||||||
|
10
Teknik.sln
10
Teknik.sln
@ -26,8 +26,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Configuration", "Utilities\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeknikStreaming", "TeknikStreaming\TeknikStreaming.csproj", "{7695CE9A-A0DB-4D73-BC9B-2206481F0254}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeknikStreaming", "TeknikStreaming\TeknikStreaming.csproj", "{7695CE9A-A0DB-4D73-BC9B-2206481F0254}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Security", "Utilities\Security\Security.csproj", "{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -93,14 +91,6 @@ Global
|
|||||||
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|Any CPU.Build.0 = Release|Any CPU
|
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|x64.ActiveCfg = Release|Any CPU
|
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|x64.Build.0 = Release|Any CPU
|
{7695CE9A-A0DB-4D73-BC9B-2206481F0254}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -292,12 +292,9 @@ namespace Teknik.Areas.Upload.Controllers
|
|||||||
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
|
||||||
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);
|
||||||
|
|
||||||
// Calculate the block offset needed for the counter
|
|
||||||
int counterOffset = (int)Math.Floor(startByte / 16.0);
|
|
||||||
|
|
||||||
return new FileGenerateResult(url,
|
return new FileGenerateResult(url,
|
||||||
contentType,
|
contentType,
|
||||||
(response) => ResponseHelper.StreamToOutput(response, true, new AESCryptoStream(fs, false, keyBytes, ivBytes, "CTR", "NoPadding", counterOffset), (int)length, Config.UploadConfig.ChunkSize),
|
(response) => ResponseHelper.StreamToOutput(response, true, new AESCryptoStream(fs, false, keyBytes, ivBytes, "CTR", "NoPadding"), (int)length, Config.UploadConfig.ChunkSize),
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
else // Otherwise just send it
|
else // Otherwise just send it
|
||||||
|
@ -802,10 +802,6 @@
|
|||||||
<Project>{c492c2c6-d45a-498b-84a2-6d4c8bf9de77}</Project>
|
<Project>{c492c2c6-d45a-498b-84a2-6d4c8bf9de77}</Project>
|
||||||
<Name>Piwik</Name>
|
<Name>Piwik</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\Utilities\Security\Security.csproj">
|
|
||||||
<Project>{2bb2f552-b80f-41f2-937d-5d73f15c6dc4}</Project>
|
|
||||||
<Name>Security</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\Utilities\Utilities\Utilities.csproj">
|
<ProjectReference Include="..\Utilities\Utilities\Utilities.csproj">
|
||||||
<Project>{f45de6fc-3754-4954-a20a-4277362cc6c1}</Project>
|
<Project>{f45de6fc-3754-4954-a20a-4277362cc6c1}</Project>
|
||||||
<Name>Utilities</Name>
|
<Name>Utilities</Name>
|
||||||
|
@ -1,137 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Teknik.Security.Cryptography
|
|
||||||
{
|
|
||||||
public class AesCounterMode : SymmetricAlgorithm
|
|
||||||
{
|
|
||||||
private const int _blockSize = 16;
|
|
||||||
private readonly byte[] _counter;
|
|
||||||
private readonly AesManaged _aes;
|
|
||||||
|
|
||||||
public AesCounterMode(byte[] counter)
|
|
||||||
{
|
|
||||||
if (counter == null) throw new ArgumentNullException("counter");
|
|
||||||
if (counter.Length != _blockSize)
|
|
||||||
throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})",
|
|
||||||
counter.Length, _blockSize));
|
|
||||||
|
|
||||||
_aes = new AesManaged
|
|
||||||
{
|
|
||||||
Mode = CipherMode.ECB,
|
|
||||||
Padding = PaddingMode.None
|
|
||||||
};
|
|
||||||
|
|
||||||
_counter = counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ICryptoTransform CreateEncryptor(byte[] key, byte[] iv)
|
|
||||||
{
|
|
||||||
return new CounterModeCryptoTransform(_aes, key, iv, _counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ICryptoTransform CreateDecryptor(byte[] key, byte[] iv)
|
|
||||||
{
|
|
||||||
return new CounterModeCryptoTransform(_aes, key, iv, _counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateKey()
|
|
||||||
{
|
|
||||||
_aes.GenerateKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateIV()
|
|
||||||
{
|
|
||||||
// IV not needed in Counter Mode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CounterModeCryptoTransform : ICryptoTransform
|
|
||||||
{
|
|
||||||
private readonly byte[] _iv;
|
|
||||||
private readonly byte[] _counter;
|
|
||||||
private readonly ICryptoTransform _counterEncryptor;
|
|
||||||
private readonly Queue<byte> _xorMask = new Queue<byte>();
|
|
||||||
private readonly SymmetricAlgorithm _symmetricAlgorithm;
|
|
||||||
|
|
||||||
public CounterModeCryptoTransform(SymmetricAlgorithm symmetricAlgorithm, byte[] key, byte[] iv, byte[] counter)
|
|
||||||
{
|
|
||||||
if (symmetricAlgorithm == null) throw new ArgumentNullException("symmetricAlgorithm");
|
|
||||||
if (key == null) throw new ArgumentNullException("key");
|
|
||||||
if (iv == null) throw new ArgumentNullException("counter");
|
|
||||||
if (iv.Length != symmetricAlgorithm.BlockSize / 8)
|
|
||||||
throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})",
|
|
||||||
iv.Length, symmetricAlgorithm.BlockSize / 8));
|
|
||||||
|
|
||||||
_symmetricAlgorithm = symmetricAlgorithm;
|
|
||||||
_counter = counter;
|
|
||||||
_iv = iv;
|
|
||||||
|
|
||||||
_counterEncryptor = symmetricAlgorithm.CreateEncryptor(key, iv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
|
|
||||||
{
|
|
||||||
var output = new byte[inputCount];
|
|
||||||
TransformBlock(inputBuffer, inputOffset, inputCount, output, 0);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < inputCount; i++)
|
|
||||||
{
|
|
||||||
if (NeedMoreXorMaskBytes()) EncryptCounterThenIncrement();
|
|
||||||
|
|
||||||
var mask = _xorMask.Dequeue();
|
|
||||||
outputBuffer[outputOffset + i] = (byte)(mask ^ inputBuffer[inputOffset + i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool NeedMoreXorMaskBytes()
|
|
||||||
{
|
|
||||||
return _xorMask.Count == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EncryptCounterThenIncrement()
|
|
||||||
{
|
|
||||||
var counterModeBlock = new byte[_symmetricAlgorithm.BlockSize / 8];
|
|
||||||
|
|
||||||
_counterEncryptor.TransformBlock(_counter, 0, _counter.Length, counterModeBlock, 0);
|
|
||||||
IncrementCounter();
|
|
||||||
|
|
||||||
foreach (var b in counterModeBlock)
|
|
||||||
{
|
|
||||||
_xorMask.Enqueue(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void IncrementCounter()
|
|
||||||
{
|
|
||||||
int j = _counter.Length;
|
|
||||||
while (--j >= 0 && ++_counter[j] == 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
//for (var i = _counter.Length - 1; i >= 0; i--)
|
|
||||||
//{
|
|
||||||
// if (++_counter[i] != 0)
|
|
||||||
// break;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int InputBlockSize { get { return _symmetricAlgorithm.BlockSize / 8; } }
|
|
||||||
public int OutputBlockSize { get { return _symmetricAlgorithm.BlockSize / 8; } }
|
|
||||||
public bool CanTransformMultipleBlocks { get { return true; } }
|
|
||||||
public bool CanReuseTransform { get { return false; } }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Teknik Security Utilities")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Teknik")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("2bb2f552-b80f-41f2-937d-5d73f15c6dc4")]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,55 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{2BB2F552-B80F-41F2-937D-5D73F15C6DC4}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>Teknik.Security</RootNamespace>
|
|
||||||
<AssemblyName>Teknik.Security</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Cryptography\AesCounterMode.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
</Project>
|
|
187
Utilities/Utilities/Cryptography/AesCounterMode.cs
Normal file
187
Utilities/Utilities/Cryptography/AesCounterMode.cs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Teknik.Utilities.Cryptography
|
||||||
|
{
|
||||||
|
public class AesCounterMode : SymmetricAlgorithm
|
||||||
|
{
|
||||||
|
// Internal Variables
|
||||||
|
private const int _BlockSize = 16;
|
||||||
|
private readonly byte[] _Counter;
|
||||||
|
private readonly AesManaged _Algo;
|
||||||
|
|
||||||
|
public AesCounterMode() : this(new byte[_BlockSize]) { }
|
||||||
|
|
||||||
|
public AesCounterMode(byte[] counter)
|
||||||
|
{
|
||||||
|
if (counter == null) throw new ArgumentNullException("counter");
|
||||||
|
if (counter.Length != _BlockSize)
|
||||||
|
throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})",
|
||||||
|
counter.Length, _BlockSize));
|
||||||
|
|
||||||
|
// Generate a new instance of the Aes Algorithm in ECB mode with no padding
|
||||||
|
_Algo = new AesManaged
|
||||||
|
{
|
||||||
|
Mode = CipherMode.ECB,
|
||||||
|
Padding = PaddingMode.None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the internal variables
|
||||||
|
_Counter = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ICryptoTransform CreateEncryptor(byte[] key, byte[] iv)
|
||||||
|
{
|
||||||
|
return new CounterModeCryptoTransform(_Algo, key, iv, _Counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ICryptoTransform CreateDecryptor(byte[] key, byte[] iv)
|
||||||
|
{
|
||||||
|
return new CounterModeCryptoTransform(_Algo, key, iv, _Counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateKey()
|
||||||
|
{
|
||||||
|
_Algo.GenerateKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GenerateIV()
|
||||||
|
{
|
||||||
|
_Algo.GenerateIV();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CounterModeCryptoTransform : ICryptoTransform
|
||||||
|
{
|
||||||
|
private readonly byte[] _IV;
|
||||||
|
private readonly byte[] _Counter;
|
||||||
|
private readonly ICryptoTransform _CounterEncryptor;
|
||||||
|
private readonly SymmetricAlgorithm _SymmetricAlgorithm;
|
||||||
|
|
||||||
|
// Stateful Fields
|
||||||
|
private byte[] _EncryptedCounter;
|
||||||
|
|
||||||
|
private int _Iterations;
|
||||||
|
public int Iterations
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Iterations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _CounterPosition;
|
||||||
|
public int CounterPosition
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _CounterPosition;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value > 0 && value < _EncryptedCounter.Length)
|
||||||
|
{
|
||||||
|
_CounterPosition = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CounterModeCryptoTransform(SymmetricAlgorithm symmetricAlgorithm, byte[] key, byte[] iv, byte[] counter)
|
||||||
|
{
|
||||||
|
if (symmetricAlgorithm == null) throw new ArgumentNullException("symmetricAlgorithm");
|
||||||
|
if (key == null) throw new ArgumentNullException("key");
|
||||||
|
if (iv == null) throw new ArgumentNullException("iv");
|
||||||
|
if (counter == null) throw new ArgumentNullException("counter");
|
||||||
|
|
||||||
|
// Check lengths
|
||||||
|
if (counter.Length != symmetricAlgorithm.BlockSize / 8)
|
||||||
|
throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})",
|
||||||
|
counter.Length, symmetricAlgorithm.BlockSize / 8));
|
||||||
|
|
||||||
|
_SymmetricAlgorithm = symmetricAlgorithm;
|
||||||
|
_IV = iv;
|
||||||
|
_Counter = counter;
|
||||||
|
|
||||||
|
_CounterEncryptor = symmetricAlgorithm.CreateEncryptor(key, iv);
|
||||||
|
|
||||||
|
// Initialize State
|
||||||
|
_CounterPosition = 0;
|
||||||
|
_Iterations = 0;
|
||||||
|
|
||||||
|
// Encrypt the counter
|
||||||
|
EncryptCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
|
||||||
|
{
|
||||||
|
var output = new byte[inputCount];
|
||||||
|
TransformBlock(inputBuffer, inputOffset, inputCount, output, 0);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < inputCount; i++)
|
||||||
|
{
|
||||||
|
// Encrypt the counter if we have reached the end, or
|
||||||
|
if (_CounterPosition >= _EncryptedCounter.Length)
|
||||||
|
{
|
||||||
|
// Encrypt the counter
|
||||||
|
EncryptCounter();
|
||||||
|
|
||||||
|
//Reset current counter position
|
||||||
|
_CounterPosition = 0;
|
||||||
|
|
||||||
|
// Increment the counter for the next run
|
||||||
|
IncrementCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR the encrypted counter with the input plain text
|
||||||
|
outputBuffer[outputOffset + i] = (byte)(_EncryptedCounter[_CounterPosition] ^ inputBuffer[inputOffset + i]);
|
||||||
|
|
||||||
|
// Move the counter position
|
||||||
|
_CounterPosition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EncryptCounter()
|
||||||
|
{
|
||||||
|
// Clear the encrypted counter
|
||||||
|
_EncryptedCounter = new byte[_SymmetricAlgorithm.BlockSize / 8];
|
||||||
|
|
||||||
|
// Encrypt the current counter to the encrypted counter
|
||||||
|
_CounterEncryptor.TransformBlock(_Counter, 0, _Counter.Length, _EncryptedCounter, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetCounter()
|
||||||
|
{
|
||||||
|
Array.Clear(_Counter, 0, _Counter.Length);
|
||||||
|
Array.Copy(_IV, 0, _Counter, 0, _IV.Length);
|
||||||
|
_Iterations = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IncrementCounter()
|
||||||
|
{
|
||||||
|
int j = _Counter.Length;
|
||||||
|
while (--j >= 0 && ++_Counter[j] == 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
_Iterations++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int InputBlockSize { get { return _SymmetricAlgorithm.BlockSize / 8; } }
|
||||||
|
public int OutputBlockSize { get { return _SymmetricAlgorithm.BlockSize / 8; } }
|
||||||
|
public bool CanTransformMultipleBlocks { get { return true; } }
|
||||||
|
public bool CanReuseTransform { get { return false; } }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,105 +5,59 @@ using System.Linq;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Teknik.Security.Cryptography;
|
using Teknik.Utilities.Cryptography;
|
||||||
|
|
||||||
namespace Teknik.Utilities
|
namespace Teknik.Utilities
|
||||||
{
|
{
|
||||||
public class AESCryptoStream : Stream
|
public class AESCryptoStream : Stream
|
||||||
{
|
{
|
||||||
private Stream _Inner;
|
private Stream _Inner;
|
||||||
//private IBufferedCipher _Cipher;
|
private CounterModeCryptoTransform _Cipher;
|
||||||
private ICryptoTransform _Cipher;
|
|
||||||
|
|
||||||
public AESCryptoStream(Stream stream, bool encrypt, byte[] key, byte[] iv, string mode, string padding, int initCounter)
|
public AESCryptoStream(Stream stream, bool encrypt, byte[] key, byte[] iv, string mode, string padding)
|
||||||
{
|
{
|
||||||
_Inner = stream;
|
_Inner = stream;
|
||||||
|
|
||||||
// Create initial counter value from IV
|
|
||||||
byte[] counter = new byte[iv.Length];
|
|
||||||
iv.CopyTo(counter, 0);
|
|
||||||
|
|
||||||
// Increment the counter depending on the init counter
|
|
||||||
for (int i = 0; i < initCounter; i++)
|
|
||||||
{
|
|
||||||
int j = counter.Length;
|
|
||||||
while (--j >= 0 && ++counter[j] == 0) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the Aes Cipher
|
// Create the Aes Cipher
|
||||||
AesCounterMode aes = new AesCounterMode(counter);
|
AesCounterMode aes = new AesCounterMode(iv);
|
||||||
if (encrypt)
|
if (encrypt)
|
||||||
{
|
{
|
||||||
_Cipher = aes.CreateEncryptor(key, iv); // Encrypt
|
_Cipher = (CounterModeCryptoTransform)aes.CreateEncryptor(key, iv); // Encrypt
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_Cipher = aes.CreateDecryptor(key, iv); // Decrypt
|
_Cipher = (CounterModeCryptoTransform)aes.CreateDecryptor(key, iv); // Decrypt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync the counter
|
||||||
|
SyncCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
if (_Inner != null && CanRead)
|
if (_Inner != null && CanRead)
|
||||||
{
|
{
|
||||||
int bytesRead = 0;
|
byte[] readBuf = new byte[count];
|
||||||
int totalBytesRead = 0;
|
int processed = 0;
|
||||||
int bytesProcessed = 0;
|
|
||||||
long startPosition = _Inner.Position;
|
|
||||||
int blockSize = _Cipher.InputBlockSize;
|
|
||||||
long byteOffset = (startPosition % blockSize);
|
|
||||||
int initialOffset = (int)byteOffset;
|
|
||||||
int blockOffset = (byteOffset == 0) ? 0 : 1;
|
|
||||||
int blocksToProcess = (int)Math.Ceiling(count / (double)blockSize) + blockOffset;
|
|
||||||
|
|
||||||
// Determine if we are at the start of a block, or not
|
// Read the data from the stream
|
||||||
if (byteOffset != 0)
|
int bytesRead = _Inner.Read(readBuf, 0, count);
|
||||||
|
if (bytesRead > 0)
|
||||||
{
|
{
|
||||||
// We are not a multiple of the block size, so let's backup to get the current block
|
// Process the
|
||||||
_Inner.Seek(startPosition - byteOffset, SeekOrigin.Begin);
|
processed = _Cipher.TransformBlock(readBuf, 0, bytesRead, buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize buffers
|
// Do we have more?
|
||||||
byte[] readBuf = new byte[blockSize];
|
if (processed < bytesRead)
|
||||||
byte[] outBuf = new byte[blockSize];
|
|
||||||
|
|
||||||
// Iterate through each block of the ammount we want to read
|
|
||||||
for (int i = 0; i < blocksToProcess; i++)
|
|
||||||
{
|
|
||||||
// Read the next block of data
|
|
||||||
totalBytesRead += bytesRead = _Inner.Read(readBuf, 0, blockSize);
|
|
||||||
if (bytesRead > 0)
|
|
||||||
{
|
|
||||||
// process the cipher for the read block and add it to the output
|
|
||||||
int processed = _Cipher.TransformBlock(readBuf, 0, bytesRead, outBuf, 0);
|
|
||||||
|
|
||||||
// copy the values to the output
|
|
||||||
outBuf.Skip(initialOffset).ToArray().CopyTo(buffer, bytesProcessed + offset);
|
|
||||||
|
|
||||||
// Reset initial offset and calibrate
|
|
||||||
bytesProcessed += processed - initialOffset;
|
|
||||||
|
|
||||||
// Reset initial offset
|
|
||||||
initialOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the read buffer
|
|
||||||
Array.Clear(readBuf, 0, blockSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust bytes read by the block offset
|
|
||||||
totalBytesRead -= (int)byteOffset;
|
|
||||||
bytesProcessed -= (int)byteOffset;
|
|
||||||
|
|
||||||
if (bytesProcessed < count)
|
|
||||||
{
|
{
|
||||||
// Finalize the cipher
|
// Finalize the cipher
|
||||||
byte[] finalBuf = _Cipher.TransformFinalBlock(readBuf, bytesProcessed, bytesRead);
|
byte[] finalBuf = _Cipher.TransformFinalBlock(readBuf, processed, bytesRead);
|
||||||
finalBuf.Take(count - bytesProcessed).ToArray().CopyTo(buffer, bytesProcessed);
|
finalBuf.CopyTo(buffer, processed);
|
||||||
bytesProcessed += count - bytesProcessed;
|
processed += finalBuf.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesProcessed;
|
return processed;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -187,6 +141,9 @@ namespace Teknik.Utilities
|
|||||||
if (_Inner != null)
|
if (_Inner != null)
|
||||||
{
|
{
|
||||||
_Inner.Position = value;
|
_Inner.Position = value;
|
||||||
|
|
||||||
|
// Sync the counter
|
||||||
|
SyncCounter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +160,12 @@ namespace Teknik.Utilities
|
|||||||
{
|
{
|
||||||
if (_Inner != null)
|
if (_Inner != null)
|
||||||
{
|
{
|
||||||
return _Inner.Seek(offset, origin);
|
long newPos = _Inner.Seek(offset, origin);
|
||||||
|
|
||||||
|
// Sync the counter
|
||||||
|
SyncCounter();
|
||||||
|
|
||||||
|
return newPos;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -215,5 +177,37 @@ namespace Teknik.Utilities
|
|||||||
_Inner.SetLength(value);
|
_Inner.SetLength(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SyncCounter()
|
||||||
|
{
|
||||||
|
if (_Cipher != null)
|
||||||
|
{
|
||||||
|
// Calculate the counter iterations and position needed
|
||||||
|
int iterations = (int)Math.Floor(_Inner.Position / (decimal)_Cipher.InputBlockSize);
|
||||||
|
int counterPos = (int)(_Inner.Position % _Cipher.InputBlockSize);
|
||||||
|
|
||||||
|
// Are we out of sync with the cipher?
|
||||||
|
if (_Cipher.Iterations != iterations || _Cipher.CounterPosition != counterPos)
|
||||||
|
{
|
||||||
|
// Reset the current counter
|
||||||
|
_Cipher.ResetCounter();
|
||||||
|
|
||||||
|
// Iterate the counter to the current position
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
_Cipher.IncrementCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the counter
|
||||||
|
_Cipher.EncryptCounter();
|
||||||
|
|
||||||
|
// Set the current position of the counter
|
||||||
|
_Cipher.CounterPosition = counterPos;
|
||||||
|
|
||||||
|
// Increment the counter for the next time
|
||||||
|
_Cipher.IncrementCounter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AccountType.cs" />
|
<Compile Include="AccountType.cs" />
|
||||||
|
<Compile Include="Cryptography\AesCounterMode.cs" />
|
||||||
<Compile Include="CurrencyHelper.cs" />
|
<Compile Include="CurrencyHelper.cs" />
|
||||||
<Compile Include="CurrencyType.cs" />
|
<Compile Include="CurrencyType.cs" />
|
||||||
<Compile Include="EntityExtensions.cs" />
|
<Compile Include="EntityExtensions.cs" />
|
||||||
@ -139,12 +140,6 @@
|
|||||||
<None Include="app.config" />
|
<None Include="app.config" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Security\Security.csproj">
|
|
||||||
<Project>{2bb2f552-b80f-41f2-937d-5d73f15c6dc4}</Project>
|
|
||||||
<Name>Security</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="..\..\packages\GitVersionTask.3.6.5\build\dotnet\GitVersionTask.targets" Condition="Exists('..\..\packages\GitVersionTask.3.6.5\build\dotnet\GitVersionTask.targets')" />
|
<Import Project="..\..\packages\GitVersionTask.3.6.5\build\dotnet\GitVersionTask.targets" Condition="Exists('..\..\packages\GitVersionTask.3.6.5\build\dotnet\GitVersionTask.targets')" />
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
Loading…
Reference in New Issue
Block a user