2 * Novacoin classes library
3 * Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 using System.Diagnostics.Contracts;
22 using System.Security.Cryptography;
27 /// Hashing functionality.
29 public class CryptoUtils
31 #region Private instances for various hashing algorithm implementations.
33 /// Computes the SHA1 hash for the input data using the managed library.
35 private static SHA1Managed _sha1 = new SHA1Managed();
38 /// Computes the SHA256 hash for the input data using the managed library.
40 private static SHA256Managed _sha256 = new SHA256Managed();
43 /// Computes the SHA1 hash for the input data using the managed library.
45 private static RIPEMD160Managed _ripe160 = new RIPEMD160Managed();
51 /// <param name="inputBytes">Bytes to hash</param>
52 /// <returns>Hashing result</returns>
53 public static byte[] ComputeSha1(byte[] inputBytes)
55 return _sha1.ComputeHash(inputBytes, 0, inputBytes.Length);
59 /// Sha256 calculation
61 /// <param name="inputBytes">Bytes to hash</param>
62 /// <returns>Hashing result</returns>
63 public static byte[] ComputeSha256(byte[] inputBytes)
65 return _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
69 /// RIPEMD-160 calculation
71 /// <param name="inputBytes">Bytes to hash</param>
72 /// <returns>Hashing result</returns>
73 public static byte[] ComputeRipeMD160(byte[] inputBytes)
75 return _ripe160.ComputeHash(inputBytes, 0, inputBytes.Length);
79 /// RipeMD160(Sha256(X)) calculation
81 /// <param name="inputBytes">Bytes to hash</param>
82 /// <returns>Hashing result</returns>
83 public static byte[] ComputeHash160(byte[] inputBytes)
85 var digest1 = _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
86 return _ripe160.ComputeHash(digest1, 0, digest1.Length);
90 /// Sha256(Sha256(X)) calculation
92 /// <param name="inputBytes">Bytes to hash</param>
93 /// <returns>Hashing result</returns>
94 public static byte[] ComputeHash256(byte[] dataBytes)
96 var digest1 = _sha256.ComputeHash(dataBytes, 0, dataBytes.Length);
97 return _sha256.ComputeHash(digest1, 0, digest1.Length);
101 /// Sha256(Sha256(X)) calculation
103 /// <param name="input1">Reference to first half of data</param>
104 /// <param name="input2">Reference to second half of data</param>
105 /// <returns>Hashing result</returns>
106 public static byte[] ComputeHash256(ref byte[] input1, ref byte[] input2)
108 var buffer = new byte[input1.Length + input2.Length];
111 input1.CopyTo(buffer, 0);
112 input2.CopyTo(buffer, input1.Length);
114 var digest1 = _sha256.ComputeHash(buffer, 0, buffer.Length);
115 return _sha256.ComputeHash(digest1, 0, digest1.Length);
119 /// Calculate PBKDF2-SHA256(SALSA20/8(PBKDF2-SHA256(X)))
121 /// <param name="inputBytes">Bytes to hash</param>
122 /// <returns>Hashing result</returns>
123 public static byte[] ComputeScryptHash256(byte[] inputBytes)
125 var V = new uint[(131072 + 63) / sizeof(uint)];
127 var keyBytes1 = PBKDF2_Sha256(128, inputBytes, inputBytes, 1);
128 var X = Interop.ToUInt32Array(keyBytes1);
130 for (var i = 0; i < 1024; i++)
132 Array.Copy(X, 0, V, i * 32, 32);
134 xor_salsa8(ref X, 0, ref X, 16);
135 xor_salsa8(ref X, 16, ref X, 0);
137 for (var i = 0; i < 1024; i++)
139 var j = 32 * (X[16] & 1023);
140 for (var k = 0; k < 32; k++)
144 xor_salsa8(ref X, 0, ref X, 16);
145 xor_salsa8(ref X, 16, ref X, 0);
148 var xBytes = Interop.LEBytes(X);
150 return PBKDF2_Sha256(32, inputBytes, xBytes, 1);
154 #region PBKDF2-SHA256
156 /// Managed implementation of PBKDF2-SHA256.
158 /// <param name="dklen">Key length</param>
159 /// <param name="password">Password</param>
160 /// <param name="salt">Salt</param>
161 /// <param name="iterationCount">Amount of derive iterations.</param>
162 /// <returns>Derived key</returns>
163 public static byte[] PBKDF2_Sha256(int dklen, byte[] password, byte[] salt, int iterationCount)
165 /* Init HMAC state. */
166 using (var hmac = new HMACSHA256(password))
168 int hashLength = hmac.HashSize / 8;
169 if ((hmac.HashSize & 7) != 0)
173 int keyLength = dklen / hashLength;
174 if (dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
176 throw new ArgumentOutOfRangeException("dklen");
178 if (dklen % hashLength != 0)
182 var extendedkey = new byte[salt.Length + 4];
183 Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
184 using (var ms = new MemoryStream())
186 /* Iterate through the blocks. */
187 for (int i = 0; i < keyLength; i++)
189 /* Generate INT(i + 1). */
190 extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
191 extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
192 extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
193 extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
195 /* Compute U_1 = PRF(P, S || INT(i)). */
196 var u = hmac.ComputeHash(extendedkey);
197 Array.Clear(extendedkey, salt.Length, 4);
201 for (int j = 1; j < iterationCount; j++)
204 u = hmac.ComputeHash(u);
205 for (int k = 0; k < f.Length; k++)
207 /* ... xor U_j ... */
212 /* Copy as many bytes as necessary into memory stream. */
213 ms.Write(f, 0, f.Length);
214 Array.Clear(u, 0, u.Length);
215 Array.Clear(f, 0, f.Length);
219 /* Initialize result array. */
220 var dk = new byte[dklen];
222 /* Read key from memory stream. */
223 ms.Read(dk, 0, dklen);
226 for (long i = 0; i < ms.Length; i++)
230 Array.Clear(extendedkey, 0, extendedkey.Length);
238 private static void xor_salsa8(ref uint[] B, int indexB, ref uint[] Bx, int indexBx)
240 uint x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14, x15;
243 x00 = (B[indexB + 0] ^= Bx[indexBx + 0]);
244 x01 = (B[indexB + 1] ^= Bx[indexBx + 1]);
245 x02 = (B[indexB + 2] ^= Bx[indexBx + 2]);
246 x03 = (B[indexB + 3] ^= Bx[indexBx + 3]);
247 x04 = (B[indexB + 4] ^= Bx[indexBx + 4]);
248 x05 = (B[indexB + 5] ^= Bx[indexBx + 5]);
249 x06 = (B[indexB + 6] ^= Bx[indexBx + 6]);
250 x07 = (B[indexB + 7] ^= Bx[indexBx + 7]);
251 x08 = (B[indexB + 8] ^= Bx[indexBx + 8]);
252 x09 = (B[indexB + 9] ^= Bx[indexBx + 9]);
253 x10 = (B[indexB + 10] ^= Bx[indexBx + 10]);
254 x11 = (B[indexB + 11] ^= Bx[indexBx + 11]);
255 x12 = (B[indexB + 12] ^= Bx[indexBx + 12]);
256 x13 = (B[indexB + 13] ^= Bx[indexBx + 13]);
257 x14 = (B[indexB + 14] ^= Bx[indexBx + 14]);
258 x15 = (B[indexB + 15] ^= Bx[indexBx + 15]);
260 Func<uint, int, uint> R = (a, b) => (((a) << (b)) | ((a) >> (32 - (b))));
262 for (i = 0; i < 8; i += 2)
264 /* Operate on columns. */
265 x04 ^= R(x00 + x12, 7); x09 ^= R(x05 + x01, 7);
266 x14 ^= R(x10 + x06, 7); x03 ^= R(x15 + x11, 7);
268 x08 ^= R(x04 + x00, 9); x13 ^= R(x09 + x05, 9);
269 x02 ^= R(x14 + x10, 9); x07 ^= R(x03 + x15, 9);
271 x12 ^= R(x08 + x04, 13); x01 ^= R(x13 + x09, 13);
272 x06 ^= R(x02 + x14, 13); x11 ^= R(x07 + x03, 13);
274 x00 ^= R(x12 + x08, 18); x05 ^= R(x01 + x13, 18);
275 x10 ^= R(x06 + x02, 18); x15 ^= R(x11 + x07, 18);
277 /* Operate on rows. */
278 x01 ^= R(x00 + x03, 7); x06 ^= R(x05 + x04, 7);
279 x11 ^= R(x10 + x09, 7); x12 ^= R(x15 + x14, 7);
281 x02 ^= R(x01 + x00, 9); x07 ^= R(x06 + x05, 9);
282 x08 ^= R(x11 + x10, 9); x13 ^= R(x12 + x15, 9);
284 x03 ^= R(x02 + x01, 13); x04 ^= R(x07 + x06, 13);
285 x09 ^= R(x08 + x11, 13); x14 ^= R(x13 + x12, 13);
287 x00 ^= R(x03 + x02, 18); x05 ^= R(x04 + x07, 18);
288 x10 ^= R(x09 + x08, 18); x15 ^= R(x14 + x13, 18);
291 B[indexB + 0] += x00;
292 B[indexB + 1] += x01;
293 B[indexB + 2] += x02;
294 B[indexB + 3] += x03;
295 B[indexB + 4] += x04;
296 B[indexB + 5] += x05;
297 B[indexB + 6] += x06;
298 B[indexB + 7] += x07;
299 B[indexB + 8] += x08;
300 B[indexB + 9] += x09;
301 B[indexB + 10] += x10;
302 B[indexB + 11] += x11;
303 B[indexB + 12] += x12;
304 B[indexB + 13] += x13;
305 B[indexB + 14] += x14;
306 B[indexB + 15] += x15;