+++ /dev/null
-\feff//Copyright (c) 2012 Josip Medved <jmedved@jmedved.com>
-
-//2012-04-12: Initial version.
-
-
-using System;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Medo.Security.Cryptography
-{
-
- /// <summary>
- /// Generic PBKDF2 implementation.
- /// </summary>
- /// <example>This sample shows how to initialize class with SHA-256 HMAC.
- /// <code>
- /// using (var hmac = new HMACSHA256()) {
- /// var df = new Pbkdf2(hmac, "password", "salt");
- /// var bytes = df.GetBytes();
- /// }
- /// </code>
- /// </example>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Pbkdf", Justification = "Spelling is correct.")]
- public class Pbkdf2
- {
-
- /// <summary>
- /// Creates new instance.
- /// </summary>
- /// <param name="algorithm">HMAC algorithm to use.</param>
- /// <param name="password">The password used to derive the key.</param>
- /// <param name="salt">The key salt used to derive the key.</param>
- /// <param name="iterations">The number of iterations for the operation.</param>
- /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
- public Pbkdf2(HMAC algorithm, Byte[] password, Byte[] salt, Int32 iterations)
- {
- if (algorithm == null) { throw new ArgumentNullException("algorithm", "Algorithm cannot be null."); }
- if (salt == null) { throw new ArgumentNullException("salt", "Salt cannot be null."); }
- if (password == null) { throw new ArgumentNullException("password", "Password cannot be null."); }
- this.Algorithm = algorithm;
- this.Algorithm.Key = password;
- this.Salt = salt;
- this.IterationCount = iterations;
- this.BlockSize = this.Algorithm.HashSize / 8;
- this.BufferBytes = new byte[this.BlockSize];
- }
-
- /// <summary>
- /// Creates new instance.
- /// </summary>
- /// <param name="algorithm">HMAC algorithm to use.</param>
- /// <param name="password">The password used to derive the key.</param>
- /// <param name="salt">The key salt used to derive the key.</param>
- /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
- public Pbkdf2(HMAC algorithm, Byte[] password, Byte[] salt)
- : this(algorithm, password, salt, 1000)
- {
- }
-
- /// <summary>
- /// Creates new instance.
- /// </summary>
- /// <param name="algorithm">HMAC algorithm to use.</param>
- /// <param name="password">The password used to derive the key.</param>
- /// <param name="salt">The key salt used to derive the key.</param>
- /// <param name="iterations">The number of iterations for the operation.</param>
- /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
- public Pbkdf2(HMAC algorithm, String password, String salt, Int32 iterations) :
- this(algorithm, UTF8Encoding.UTF8.GetBytes(password), UTF8Encoding.UTF8.GetBytes(salt), iterations)
- {
- }
-
- /// <summary>
- /// Creates new instance.
- /// </summary>
- /// <param name="algorithm">HMAC algorithm to use.</param>
- /// <param name="password">The password used to derive the key.</param>
- /// <param name="salt">The key salt used to derive the key.</param>
- /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
- public Pbkdf2(HMAC algorithm, String password, String salt) :
- this(algorithm, password, salt, 1000)
- {
- }
-
-
- private readonly int BlockSize;
- private uint BlockIndex = 1;
-
- private byte[] BufferBytes;
- private int BufferStartIndex = 0;
- private int BufferEndIndex = 0;
-
-
- /// <summary>
- /// Gets algorithm used for generating key.
- /// </summary>
- public HMAC Algorithm { get; private set; }
-
- /// <summary>
- /// Gets salt bytes.
- /// </summary>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Byte array is proper return value in this case.")]
- public Byte[] Salt { get; private set; }
-
- /// <summary>
- /// Gets iteration count.
- /// </summary>
- public Int32 IterationCount { get; private set; }
-
-
- /// <summary>
- /// Returns a pseudo-random key from a password, salt and iteration count.
- /// </summary>
- /// <param name="count">Number of bytes to return.</param>
- /// <returns>Byte array.</returns>
- public Byte[] GetBytes(int count)
- {
- byte[] result = new byte[count];
- int resultOffset = 0;
- int bufferCount = this.BufferEndIndex - this.BufferStartIndex;
-
- if (bufferCount > 0)
- { //if there is some data in buffer
- if (count < bufferCount)
- { //if there is enough data in buffer
- Buffer.BlockCopy(this.BufferBytes, this.BufferStartIndex, result, 0, count);
- this.BufferStartIndex += count;
- return result;
- }
- Buffer.BlockCopy(this.BufferBytes, this.BufferStartIndex, result, 0, bufferCount);
- this.BufferStartIndex = this.BufferEndIndex = 0;
- resultOffset += bufferCount;
- }
-
- while (resultOffset < count)
- {
- int needCount = count - resultOffset;
- this.BufferBytes = this.Func();
- if (needCount > this.BlockSize)
- { //we one (or more) additional passes
- Buffer.BlockCopy(this.BufferBytes, 0, result, resultOffset, this.BlockSize);
- resultOffset += this.BlockSize;
- }
- else
- {
- Buffer.BlockCopy(this.BufferBytes, 0, result, resultOffset, needCount);
- this.BufferStartIndex = needCount;
- this.BufferEndIndex = this.BlockSize;
- return result;
- }
- }
- return result;
- }
-
-
- private byte[] Func()
- {
- var hash1Input = new byte[this.Salt.Length + 4];
- Buffer.BlockCopy(this.Salt, 0, hash1Input, 0, this.Salt.Length);
- Buffer.BlockCopy(GetBytesFromInt(this.BlockIndex), 0, hash1Input, this.Salt.Length, 4);
- var hash1 = this.Algorithm.ComputeHash(hash1Input);
-
- byte[] finalHash = hash1;
- for (int i = 2; i <= this.IterationCount; i++)
- {
- hash1 = this.Algorithm.ComputeHash(hash1, 0, hash1.Length);
- for (int j = 0; j < this.BlockSize; j++)
- {
- finalHash[j] = (byte)(finalHash[j] ^ hash1[j]);
- }
- }
- if (this.BlockIndex == uint.MaxValue) { throw new InvalidOperationException("Derived key too long."); }
- this.BlockIndex += 1;
-
- return finalHash;
- }
-
- private static byte[] GetBytesFromInt(uint i)
- {
- var bytes = BitConverter.GetBytes(i);
- if (BitConverter.IsLittleEndian)
- {
- return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] };
- }
- else
- {
- return bytes;
- }
- }
-
- }
-}
\feffusing System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using Medo.Security.Cryptography;
using System.Security.Cryptography;
namespace Novacoin
{
+ /// <summary>
+ /// Representation of scrypt hash
+ /// </summary>
public class ScryptHash256 : Hash
{
// 32 bytes
public ScryptHash256(byte[] bytesArray) : base(bytesArray) { }
public ScryptHash256(IList<byte> bytesList) : base(bytesList) { }
+ /// <summary>
+ /// Calculate scrypt hash and return new instance of ScryptHash256 class
+ /// </summary>
+ /// <param name="inputBytes">Byte sequence to hash</param>
+ /// <returns>Hashing result instance</returns>
public static ScryptHash256 Compute256(IEnumerable<byte> inputBytes)
{
- byte[] dataBytes = inputBytes.ToArray();
-
uint[] V = new uint[(131072 + 63) / sizeof(uint)];
- uint[] X = null;
- using (HMACSHA256 hmac = new HMACSHA256())
- {
- Pbkdf2 df = new Pbkdf2(hmac, dataBytes, dataBytes, 1);
- byte[] keyBytes1 = df.GetBytes(128);
-
- X = Interop.ToUInt32Array(keyBytes1);
- }
+ byte[] dataBytes = inputBytes.ToArray();
+ byte[] keyBytes1 = PBKDF2Sha256GetBytes(128, dataBytes, dataBytes, 1);
+ uint[] X = Interop.ToUInt32Array(keyBytes1);
- ushort i, j, k;
+ uint i, j, k;
for (i = 0; i < 1024; i++)
{
Array.Copy(X, 0, V, i * 32, 32);
}
for (i = 0; i < 1024; i++)
{
- j = (ushort)(32 * (X[16] & 1023));
+ j = 32 * (X[16] & 1023);
for (k = 0; k < 32; k++)
X[k] ^= V[j + k];
xor_salsa8(ref X, 0, ref X, 16);
}
byte[] xBytes = Interop.LEBytes(X);
+ byte[] keyBytes2 = PBKDF2Sha256GetBytes(32, dataBytes, xBytes, 1);
- byte[] keyBytes2 = null;
- using (HMACSHA256 hmac = new HMACSHA256())
+ return new ScryptHash256(keyBytes2);
+ }
+
+ private static byte[] PBKDF2Sha256GetBytes(int dklen, byte[] password, byte[] salt, int iterationCount)
+ {
+ using (var hmac = new HMACSHA256(password))
{
- Pbkdf2 df = new Pbkdf2(hmac, dataBytes, xBytes, 1);
- keyBytes2 = df.GetBytes(32);
+ int hashLength = hmac.HashSize / 8;
+ if ((hmac.HashSize & 7) != 0)
+ hashLength++;
+ int keyLength = dklen / hashLength;
+ if ((long)dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
+ throw new ArgumentOutOfRangeException("dklen");
+ if (dklen % hashLength != 0)
+ keyLength++;
+ byte[] extendedkey = new byte[salt.Length + 4];
+ Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
+ using (var ms = new System.IO.MemoryStream())
+ {
+ for (int i = 0; i < keyLength; i++)
+ {
+ extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
+ extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
+ extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
+ extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
+ byte[] u = hmac.ComputeHash(extendedkey);
+ Array.Clear(extendedkey, salt.Length, 4);
+ byte[] f = u;
+ for (int j = 1; j < iterationCount; j++)
+ {
+ u = hmac.ComputeHash(u);
+ for (int k = 0; k < f.Length; k++)
+ {
+ f[k] ^= u[k];
+ }
+ }
+ ms.Write(f, 0, f.Length);
+ Array.Clear(u, 0, u.Length);
+ Array.Clear(f, 0, f.Length);
+ }
+ byte[] dk = new byte[dklen];
+ ms.Position = 0;
+ ms.Read(dk, 0, dklen);
+ ms.Position = 0;
+ for (long i = 0; i < ms.Length; i++)
+ {
+ ms.WriteByte(0);
+ }
+ Array.Clear(extendedkey, 0, extendedkey.Length);
+ return dk;
+ }
}
-
- return new ScryptHash256(keyBytes2);
}
private static void xor_salsa8(ref uint[] B, int indexB, ref uint[] Bx, int indexBx)