/** * Novacoin classes library * Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ using System; using System.Security.Cryptography; namespace Novacoin { public class CryptoUtils { public static byte[] PBKDF2_Sha256(int dklen, byte[] password, byte[] salt, int iterationCount) { /* Init HMAC state. */ using (var hmac = new HMACSHA256(password)) { int hashLength = hmac.HashSize / 8; if ((hmac.HashSize & 7) != 0) { hashLength++; } int keyLength = dklen / hashLength; if (dklen > (0xFFFFFFFFL * hashLength) || dklen < 0) { throw new ArgumentOutOfRangeException("dklen"); } if (dklen % hashLength != 0) { keyLength++; } var extendedkey = new byte[salt.Length + 4]; Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length); using (var ms = new System.IO.MemoryStream()) { /* Iterate through the blocks. */ for (int i = 0; i < keyLength; i++) { /* Generate INT(i + 1). */ 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); /* Compute U_1 = PRF(P, S || INT(i)). */ var u = hmac.ComputeHash(extendedkey); Array.Clear(extendedkey, salt.Length, 4); /* T_i = U_1 ... */ var f = u; for (int j = 1; j < iterationCount; j++) { /* Compute U_j. */ u = hmac.ComputeHash(u); for (int k = 0; k < f.Length; k++) { /* ... xor U_j ... */ f[k] ^= u[k]; } } /* Copy as many bytes as necessary into memory stream. */ ms.Write(f, 0, f.Length); Array.Clear(u, 0, u.Length); Array.Clear(f, 0, f.Length); } ms.Position = 0; /* Initialize result array. */ var dk = new byte[dklen]; /* Read key from memory stream. */ 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; } } } } }