Improve CryptoUtils with wrappers for managed implementations of standard hashing...
[NovacoinLibrary.git] / Novacoin / CryptoUtils.cs
1 \feff/**
2  *  Novacoin classes library
3  *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
4
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.
9
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.
14
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/>.
17  */
18
19 using System;
20 using System.IO;
21 using System.Security.Cryptography;
22
23 namespace Novacoin
24 {
25     public class CryptoUtils
26     {
27         private static SHA1Managed _sha1 = new SHA1Managed();
28         private static SHA256Managed _sha256 = new SHA256Managed();
29         private static RIPEMD160Managed _ripe160 = new RIPEMD160Managed();
30
31         /// <summary>
32         /// Sha1 calculation
33         /// </summary>
34         /// <param name="inputBytes">Bytes to hash</param>
35         /// <returns>Hashing result</returns>
36         public static byte[] ComputeSha1(byte[] inputBytes)
37         {
38             return _sha1.ComputeHash(inputBytes, 0, inputBytes.Length);
39         }
40
41         /// <summary>
42         /// Sha256 calculation
43         /// </summary>
44         /// <param name="inputBytes">Bytes to hash</param>
45         /// <returns>Hashing result</returns>
46         public static byte[] ComputeSha256(byte[] inputBytes)
47         {
48             return _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
49         }
50
51         /// <summary>
52         /// RIPEMD-160 calculation
53         /// </summary>
54         /// <param name="inputBytes">Bytes to hash</param>
55         /// <returns>Hashing result</returns>
56         public static byte[] ComputeRipeMD160(byte[] inputBytes)
57         {
58             return _ripe160.ComputeHash(inputBytes, 0, inputBytes.Length);
59         }
60
61         /// <summary>
62         /// RipeMD160(Sha256(X)) calculation
63         /// </summary>
64         /// <param name="inputBytes">Bytes to hash</param>
65         /// <returns>Hashing result</returns>
66         public static byte[] ComputeHash160(byte[] inputBytes)
67         {
68             var digest1 = _sha256.ComputeHash(inputBytes, 0, inputBytes.Length);
69             return _ripe160.ComputeHash(digest1, 0, digest1.Length);
70         }
71
72         /// <summary>
73         /// Sha256(Sha256(X)) calculation
74         /// </summary>
75         /// <param name="inputBytes">Bytes to hash</param>
76         /// <returns>Hashing result</returns>
77         public static byte[] ComputeHash256(byte[] dataBytes)
78         {
79             var digest1 = _sha256.ComputeHash(dataBytes, 0, dataBytes.Length);
80             return _sha256.ComputeHash(digest1, 0, digest1.Length);
81         }
82
83         /// <summary>
84         /// Sha256(Sha256(X)) calculation
85         /// </summary>
86         /// <param name="input1">Reference to first half of data</param>
87         /// <param name="input2">Reference to second half of data</param>
88         /// <returns>Hashing result</returns>
89         public static byte[] ComputeHash256(ref byte[] input1, ref byte[] input2)
90         {
91             var buffer = new byte[64];
92
93             input1.CopyTo(buffer, 0);
94             input2.CopyTo(buffer, input1.Length);
95
96             var digest1 = _sha256.ComputeHash(buffer, 0, buffer.Length);
97             return _sha256.ComputeHash(digest1, 0, digest1.Length);
98         }
99
100         public static byte[] PBKDF2_Sha256(int dklen, byte[] password, byte[] salt, int iterationCount)
101         {
102             /* Init HMAC state. */
103             using (var hmac = new HMACSHA256(password))
104             {
105                 int hashLength = hmac.HashSize / 8;
106                 if ((hmac.HashSize & 7) != 0)
107                 {
108                     hashLength++;
109                 }
110                 int keyLength = dklen / hashLength;
111                 if (dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
112                 {
113                     throw new ArgumentOutOfRangeException("dklen");
114                 }
115                 if (dklen % hashLength != 0)
116                 {
117                     keyLength++;
118                 }
119                 var extendedkey = new byte[salt.Length + 4];
120                 Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
121                 using (var ms = new MemoryStream())
122                 {
123                     /* Iterate through the blocks. */
124                     for (int i = 0; i < keyLength; i++)
125                     {
126                         /* Generate INT(i + 1). */
127                         extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
128                         extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
129                         extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
130                         extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
131
132                         /* Compute U_1 = PRF(P, S || INT(i)). */
133                         var u = hmac.ComputeHash(extendedkey);
134                         Array.Clear(extendedkey, salt.Length, 4);
135
136                         /* T_i = U_1 ... */
137                         var f = u;
138                         for (int j = 1; j < iterationCount; j++)
139                         {
140                             /* Compute U_j. */
141                             u = hmac.ComputeHash(u);
142                             for (int k = 0; k < f.Length; k++)
143                             {
144                                 /* ... xor U_j ... */
145                                 f[k] ^= u[k];
146                             }
147                         }
148
149                         /* Copy as many bytes as necessary into memory stream. */
150                         ms.Write(f, 0, f.Length);
151                         Array.Clear(u, 0, u.Length);
152                         Array.Clear(f, 0, f.Length);
153                     }
154                     ms.Position = 0;
155
156                     /* Initialize result array. */
157                     var dk = new byte[dklen];
158
159                     /* Read key from memory stream. */
160                     ms.Read(dk, 0, dklen);
161
162                     ms.Position = 0;
163                     for (long i = 0; i < ms.Length; i++)
164                     {
165                         ms.WriteByte(0);
166                     }
167                     Array.Clear(extendedkey, 0, extendedkey.Length);
168                     return dk;
169                 }
170             }
171         }
172     }
173 }