Commit 8ab956a7 authored by Michael Herndon's avatar Michael Herndon

PROTO: enhance composite key

- default to pbkdf2
- keep AESKDF around for KeePass compatability
parent 9ea08114

using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
......
......@@ -467,7 +467,6 @@ namespace NerdyMishka
Uri uri,
string path,
Action<Progress> updateProgress = null,
Options options = null,
CancellationToken token = default(CancellationToken))
{
......@@ -564,6 +563,7 @@ namespace NerdyMishka
var response = (HttpWebResponse)await request.GetResponseAsync();
string fileName = null, directory = path;
var ext = System.IO.Path.GetExtension(path);
if(ext != null)
{
fileName = System.IO.Path.GetFileName(path);
......@@ -595,7 +595,6 @@ namespace NerdyMishka
throw new System.Net.WebException($"Download Failed: ({response.StatusCode}) {response.StatusDescription}");
}
var destination = Path.Combine(directory, fileName);
long length = response.ContentLength, bytesWritten = 0;
var buffer = new byte[1048576];
......@@ -603,15 +602,14 @@ namespace NerdyMishka
using(var stream = response.GetResponseStream())
using(var writer = new System.IO.FileStream(destination, FileMode.Create))
{
do{
do
{
bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
await writer.WriteAsync(buffer, 0, bytesRead);
bytesWritten += bytesRead;
if(length > 0 && ++i % 10 == 0) {
if(length > 0 && ++i % 10 == 0)
{
var percentComplete = Math.Truncate((decimal)(bytesWritten/length)*100);
if(updateProgress != null)
{
......@@ -624,7 +622,8 @@ namespace NerdyMishka
}
if (bytesWritten == length && bytesRead == 0 && updateProgress != null) {
if (bytesWritten == length && bytesRead == 0 && updateProgress != null)
{
updateProgress(new Progress(){
BytesRead = bytesWritten,
PercentComplete = 100,
......
......@@ -23,6 +23,7 @@ namespace NerdyMishka
/// <param name="list">The list instance.</param>
/// <param name="random">(Optional) instance of <see cref="IRandom" /> used to shuffle items between indexes. </param>
/// <typeparam name="T">The item type.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Shuffle<T>(this IList<T> list, [AllowNull] IRandom random = null)
{
Check.NotNull(nameof(list), list);
......
......@@ -34,9 +34,6 @@ namespace NerdyMishka.Security.Cryptography
};
}
public static byte[] UnprotectAndConcatData(CompositeKey key, HashAlgorithm hash)
{
if (hash == null)
......@@ -62,8 +59,12 @@ namespace NerdyMishka.Security.Cryptography
ms.Flush();
ms.Position = 0;
var checksum = hash.ComputeHash(ms);
return checksum;
if(hash == null)
{
return ms.ToArray();
}
return hash.ComputeHash(ms);
}
}
......@@ -77,42 +78,58 @@ namespace NerdyMishka.Security.Cryptography
/// <param name="iterations">The number of iterations to use to generate the key.</param>
/// <param name="transform">Optional. The transform function used to generate the key.</param>
/// <returns>The composite key.</returns>
public byte[] AssembleKey()
public virtual byte[] AssembleKey()
{
const int size = 32;
// defaults to GenerateKey
var symmetricKey = this.options.SymmetricKey;
var transform = this.options.Transform ?? GenerateKey;
using(var hash = HashAlgorithm.Create(this.options.HashAlgorithm.ToString()))
var transform = this.options.ComputeHash ?? ComputePbkdf2Hash;
if(symmetricKey.Length != 32)
{
var temp = new byte[32];
Array.Copy(symmetricKey, temp, symmetricKey.Length);
symmetricKey = temp;
}
if(symmetricKey.Length != 32)
byte[] key = null;
if(this.options.HashAlgorithm != HashAlgorithmTypes.None)
{
using(var signer = HashAlgorithm.Create(this.options.HashAlgorithm.ToString()))
{
var temp = new byte[32];
Array.Copy(symmetricKey, temp, symmetricKey.Length);
symmetricKey = temp;
byte[] hashedKey = UnprotectAndConcatData(this, signer);
if (hashedKey == null || hashedKey.Length != signer.HashSize)
return null;
// key generator can be swapped out with a native implementation.
key = transform(hashedKey, symmetricKey, this.options.Iterations);
hashedKey.Clear();
var hash = signer.ComputeHash(key);
key.Clear();
return hash;
}
}
byte[] raw = UnprotectAndConcatData(this, hash);
if (raw == null || raw.Length != size)
return null;
byte[] rawKey = UnprotectAndConcatData(this, null);
// key generator can be swapped out with a native implementation.
key = transform(rawKey, symmetricKey, this.options.Iterations);
rawKey.Clear();
return key;
}
byte[] compositeKeyData = new byte[size];
//TODO: provide an argon2 method.
Array.Copy(raw, compositeKeyData, size);
raw.Clear();
public static byte[] ComputePbkdf2Hash(byte[] compositeKeyData, byte[] symmetricKey, long iterations)
{
var salt = new byte[32];
Array.Copy(symmetricKey, salt, salt.Length);
if(iterations > int.MaxValue)
iterations = int.MaxValue;
// key generator can be swapped out with a native implementation.
if (!transform(compositeKeyData, symmetricKey, this.options.Iterations))
return null;
var checksum = hash.ComputeHash(compositeKeyData);
return checksum;
}
}
return PasswordAuthenticator.Pbkdf2(compositeKeyData, salt, (int)iterations, compositeKeyData.Length);
}
private static bool GenerateKey(byte[] compositeKeyData, byte[] symmetricKey, long iterations)
public static byte[] ComputeAesKdfHash(byte[] compositeKeyData, byte[] symmetricKey, long iterations)
{
byte[] iv = new byte[16];
iv.Clear();
......@@ -129,19 +146,22 @@ namespace NerdyMishka.Security.Cryptography
aes.Key = symmetricKey;
ICryptoTransform transform = aes.CreateEncryptor();
var hash = new byte[compositeKeyData.Length];
Array.Copy(compositeKeyData, hash, compositeKeyData.Length);
if (transform == null || transform.InputBlockSize != 16 || transform.OutputBlockSize != 16)
{
// TODO: add logging to CompositeKey
return false;
return null;
}
for (long i = 0; i < iterations; ++i)
{
transform.TransformBlock(compositeKeyData, 0, 16, compositeKeyData, 0);
transform.TransformBlock(compositeKeyData, 16, 16, compositeKeyData, 16);
transform.TransformBlock(hash, 0, 16, hash, 0);
transform.TransformBlock(hash, 16, 16, hash, 16);
}
return true;
return hash;
}
public void Add(ICompositeKeyFragment fragment)
......
......@@ -6,7 +6,7 @@ namespace NerdyMishka.Security.Cryptography
{
public byte[] SymmetricKey { get; set; }
public Func<byte[], byte[], long, bool> Transform { get; set; }
public Func<byte[], byte[], long, byte[]> ComputeHash { get; set; }
public HashAlgorithmTypes HashAlgorithm { get; set; } = HashAlgorithmTypes.SHA256;
......
using System;
using System.Security.Cryptography;
using NerdyMishka.Validation;
namespace NerdyMishka.Security.Cryptography
{
......@@ -11,8 +12,7 @@ namespace NerdyMishka.Security.Cryptography
public RandomNumberGenerator(string rngName)
{
if(string.IsNullOrWhiteSpace(rngName))
throw new ArgumentNullException(nameof(rngName), "rngName must not be null or empty");
Check.NotNullOrWhiteSpace(nameof(rngName), rngName);
this.randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(rngName);
}
......@@ -71,12 +71,7 @@ namespace NerdyMishka.Security.Cryptography
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
GC.SuppressFinalize(this);
}
~RandomNumberGenerator()
{
this.Dispose(false);
// GC.SuppressFinalize(this);
}
#endregion
......
......@@ -16,12 +16,9 @@ namespace NerdyMishka
using(var writer = new System.IO.MemoryStream())
{
do{
bytesRead = stream.Read(buffer, 0, buffer.Length);
writer.Write(buffer, 0, bytesRead);
bytesWritten += bytesRead;
if(length > 0 && ++i % 10 == 0) {
var percentComplete = Math.Truncate((decimal)(bytesWritten/length)*100);
......@@ -33,7 +30,6 @@ namespace NerdyMishka
Length = length
});
}
}
if (bytesWritten == length && bytesRead == 0 && updateProgress != null) {
......
......@@ -96,7 +96,7 @@ function Enable-WindowsAutoLogon() {
}
function Disable-WindowsAutoLogon() {
Param(
param(
)
......@@ -130,7 +130,7 @@ function Disable-WindowsAutoLogon() {
}
function Invoke-WindowsReboot() {
Param(
param(
[Parameter(Position = 0)]
[Alias("Name")]
[String] $RunKeyName = "GainzReboot",
......@@ -151,7 +151,7 @@ function Invoke-WindowsReboot() {
}
function Invoke-WindowsUpdateScript() {
Param(
param(
[Parameter(Position = 0)]
[Uri] $Uri,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment