Password Stretch using Sha3
Make passwords more secure by increasing the time and space taken to test each password.
Example Code:
var b1 = new byte[0];
var b2 = new byte[0];
var salt = new byte[0];
using (var db = new PasswordStretch("1234567890".ToSecureString(), 16))
{
b1 = (byte[]) db.GetBytes(0, 64).Clone();
salt = db.Salt;
}
using (var db = new PasswordStretch("1234567891".ToSecureString(), salt))
{
b2 = (byte[]) db.GetBytes(0, 64).Clone();
}
Example Code:
var b1 = new byte[0];
var b2 = new byte[0];
var salt = new byte[0];
using (var db = new PasswordStretch("1234567890".ToSecureString(), 16))
{
b1 = (byte[]) db.GetBytes(0, 64).Clone();
salt = db.Salt;
}
using (var db = new PasswordStretch("1234567891".ToSecureString(), salt))
{
b2 = (byte[]) db.GetBytes(0, 64).Clone();
}
Example Code: var b1 = new byte[0]; var b2 = new byte[0]; var salt = new byte[0]; using (var db = new PasswordStretch("1234567890".ToSecureString(), 16)) { b1 = (byte[]) db.GetBytes(0, 64).Clone(); salt = db.Salt; } using (var db = new PasswordStretch("1234567891".ToSecureString(), salt)) { b2 = (byte[]) db.GetBytes(0, 64).Clone(); }
using System;
using System.Security;
using System.Security.Cryptography;
public class PasswordStretch : IDisposable
{
private const int PacketCount = 4;
private readonly byte[] _buffer;
private readonly byte[] _salt;
private readonly SHA3Managed _sha;
public PasswordStretch(SecureString password) : this(password, 0, 1000)
{
}
public PasswordStretch(SecureString password, int saltSize) : this(password, saltSize, 1000)
{
}
public PasswordStretch(SecureString password, int saltSize, int iterations)
{
Iterations = iterations;
var temp = new byte[0];
if (saltSize != 0)
{
var data = new byte[saltSize];
new RNGCryptoServiceProvider().GetBytes(data);
_salt = data;
_sha = new SHA3Managed(512);
_buffer = new byte[_sha.HashLength * PacketCount];
_sha.TransformBlock(_salt, 0, _salt.Length, null, 0);
var pwb = password.GetBytes();
_sha.TransformBlock(pwb, 0, pwb.Length, null, 0);
_sha.Finalize();
temp = _sha.HashValue;
}
else
{
_sha = new SHA3Managed(512);
_buffer = new byte[_sha.HashLength * PacketCount];
temp = _sha.ComputeHash(password.GetBytes());
}
for (var i = 0; i < PacketCount; i++)
{
for (var j = 0; j < Iterations; j++)
temp = _sha.ComputeHash(temp);
Buffer.BlockCopy(temp, 0, _buffer, i * _sha.HashLength, _sha.HashLength);
}
}
public PasswordStretch(SecureString password, byte[] salt) : this(password, salt, 1000)
{
}
public PasswordStretch(SecureString password, byte[] salt, int iterations = 1000)
{
Iterations = iterations;
_sha = new SHA3Managed(512);
_buffer = new byte[_sha.HashLength * PacketCount];
_sha.TransformBlock(salt, 0, salt.Length, null, 0);
var pwb = password.GetBytes();
_sha.TransformBlock(pwb, 0, pwb.Length, null, 0);
_sha.Finalize();
var temp = _sha.HashValue;
for (var i = 0; i < PacketCount; i++)
{
for (var j = 0; j < Iterations; j++)
temp = _sha.ComputeHash(temp);
Buffer.BlockCopy(temp, 0, _buffer, i * _sha.HashLength, _sha.HashLength);
}
}
public byte[] Salt
{
get
{
if (_salt != null)
return (byte[]) _salt.Clone();
return default;
}
}
public int Iterations
{
get;
} = 1000;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~PasswordStretch()
{
Dispose();
}
public byte[] GetBytes(int offset, int psize)
{
if (offset + psize > _buffer.Length)
throw new Exception("Offset and Size Exceed Buffer Length.");
var passpart = new byte[psize];
Buffer.BlockCopy(_buffer, offset, passpart, 0, passpart.Length);
return passpart;
}
private void Dispose(bool disposing)
{
if (!disposing)
return;
if (_sha != null)
_sha.Dispose();
if (_buffer != null)
Array.Clear(_buffer, 0, _buffer.Length);
if (_salt == null)
return;
Array.Clear(_salt, 0, _salt.Length);
}
}
using System;
using System.Security;
using System.Security.Cryptography;
public class PasswordStretch : IDisposable
{
private const int PacketCount = 4;
private readonly byte[] _buffer;
private readonly byte[] _salt;
private readonly SHA3Managed _sha;
public PasswordStretch(SecureString password) : this(password, 0, 1000)
{
}
public PasswordStretch(SecureString password, int saltSize) : this(password, saltSize, 1000)
{
}
public PasswordStretch(SecureString password, int saltSize, int iterations)
{
Iterations = iterations;
var temp = new byte[0];
if (saltSize != 0)
{
var data = new byte[saltSize];
new RNGCryptoServiceProvider().GetBytes(data);
_salt = data;
_sha = new SHA3Managed(512);
_buffer = new byte[_sha.HashLength * PacketCount];
_sha.TransformBlock(_salt, 0, _salt.Length, null, 0);
var pwb = password.GetBytes();
_sha.TransformBlock(pwb, 0, pwb.Length, null, 0);
_sha.Finalize();
temp = _sha.HashValue;
}
else
{
_sha = new SHA3Managed(512);
_buffer = new byte[_sha.HashLength * PacketCount];
temp = _sha.ComputeHash(password.GetBytes());
}
for (var i = 0; i < PacketCount; i++)
{
for (var j = 0; j < Iterations; j++)
temp = _sha.ComputeHash(temp);
Buffer.BlockCopy(temp, 0, _buffer, i * _sha.HashLength, _sha.HashLength);
}
}
public PasswordStretch(SecureString password, byte[] salt) : this(password, salt, 1000)
{
}
public PasswordStretch(SecureString password, byte[] salt, int iterations = 1000)
{
Iterations = iterations;
_sha = new SHA3Managed(512);
_buffer = new byte[_sha.HashLength * PacketCount];
_sha.TransformBlock(salt, 0, salt.Length, null, 0);
var pwb = password.GetBytes();
_sha.TransformBlock(pwb, 0, pwb.Length, null, 0);
_sha.Finalize();
var temp = _sha.HashValue;
for (var i = 0; i < PacketCount; i++)
{
for (var j = 0; j < Iterations; j++)
temp = _sha.ComputeHash(temp);
Buffer.BlockCopy(temp, 0, _buffer, i * _sha.HashLength, _sha.HashLength);
}
}
public byte[] Salt
{
get
{
if (_salt != null)
return (byte[]) _salt.Clone();
return default;
}
}
public int Iterations
{
get;
} = 1000;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~PasswordStretch()
{
Dispose();
}
public byte[] GetBytes(int offset, int psize)
{
if (offset + psize > _buffer.Length)
throw new Exception("Offset and Size Exceed Buffer Length.");
var passpart = new byte[psize];
Buffer.BlockCopy(_buffer, offset, passpart, 0, passpart.Length);
return passpart;
}
private void Dispose(bool disposing)
{
if (!disposing)
return;
if (_sha != null)
_sha.Dispose();
if (_buffer != null)
Array.Clear(_buffer, 0, _buffer.Length);
if (_salt == null)
return;
Array.Clear(_salt, 0, _salt.Length);
}
}
using System; using System.Security; using System.Security.Cryptography; public class PasswordStretch : IDisposable { private const int PacketCount = 4; private readonly byte[] _buffer; private readonly byte[] _salt; private readonly SHA3Managed _sha; public PasswordStretch(SecureString password) : this(password, 0, 1000) { } public PasswordStretch(SecureString password, int saltSize) : this(password, saltSize, 1000) { } public PasswordStretch(SecureString password, int saltSize, int iterations) { Iterations = iterations; var temp = new byte[0]; if (saltSize != 0) { var data = new byte[saltSize]; new RNGCryptoServiceProvider().GetBytes(data); _salt = data; _sha = new SHA3Managed(512); _buffer = new byte[_sha.HashLength * PacketCount]; _sha.TransformBlock(_salt, 0, _salt.Length, null, 0); var pwb = password.GetBytes(); _sha.TransformBlock(pwb, 0, pwb.Length, null, 0); _sha.Finalize(); temp = _sha.HashValue; } else { _sha = new SHA3Managed(512); _buffer = new byte[_sha.HashLength * PacketCount]; temp = _sha.ComputeHash(password.GetBytes()); } for (var i = 0; i < PacketCount; i++) { for (var j = 0; j < Iterations; j++) temp = _sha.ComputeHash(temp); Buffer.BlockCopy(temp, 0, _buffer, i * _sha.HashLength, _sha.HashLength); } } public PasswordStretch(SecureString password, byte[] salt) : this(password, salt, 1000) { } public PasswordStretch(SecureString password, byte[] salt, int iterations = 1000) { Iterations = iterations; _sha = new SHA3Managed(512); _buffer = new byte[_sha.HashLength * PacketCount]; _sha.TransformBlock(salt, 0, salt.Length, null, 0); var pwb = password.GetBytes(); _sha.TransformBlock(pwb, 0, pwb.Length, null, 0); _sha.Finalize(); var temp = _sha.HashValue; for (var i = 0; i < PacketCount; i++) { for (var j = 0; j < Iterations; j++) temp = _sha.ComputeHash(temp); Buffer.BlockCopy(temp, 0, _buffer, i * _sha.HashLength, _sha.HashLength); } } public byte[] Salt { get { if (_salt != null) return (byte[]) _salt.Clone(); return default; } } public int Iterations { get; } = 1000; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~PasswordStretch() { Dispose(); } public byte[] GetBytes(int offset, int psize) { if (offset + psize > _buffer.Length) throw new Exception("Offset and Size Exceed Buffer Length."); var passpart = new byte[psize]; Buffer.BlockCopy(_buffer, offset, passpart, 0, passpart.Length); return passpart; } private void Dispose(bool disposing) { if (!disposing) return; if (_sha != null) _sha.Dispose(); if (_buffer != null) Array.Clear(_buffer, 0, _buffer.Length); if (_salt == null) return; Array.Clear(_salt, 0, _salt.Length); } }