4ba7ee0400988698cd8ab133b5bcf7cf7bf35cfb
[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.Security.Cryptography;
21
22 namespace Novacoin
23 {
24     public class CryptoUtils
25     {
26         public static byte[] PBKDF2_Sha256(int dklen, byte[] password, byte[] salt, int iterationCount)
27         {
28             /* Init HMAC state. */
29             using (var hmac = new HMACSHA256(password))
30             {
31                 int hashLength = hmac.HashSize / 8;
32                 if ((hmac.HashSize & 7) != 0)
33                 {
34                     hashLength++;
35                 }
36                 int keyLength = dklen / hashLength;
37                 if (dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
38                 {
39                     throw new ArgumentOutOfRangeException("dklen");
40                 }
41                 if (dklen % hashLength != 0)
42                 {
43                     keyLength++;
44                 }
45                 var extendedkey = new byte[salt.Length + 4];
46                 Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
47                 using (var ms = new System.IO.MemoryStream())
48                 {
49                     /* Iterate through the blocks. */
50                     for (int i = 0; i < keyLength; i++)
51                     {
52                         /* Generate INT(i + 1). */
53                         extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
54                         extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
55                         extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
56                         extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
57
58                         /* Compute U_1 = PRF(P, S || INT(i)). */
59                         var u = hmac.ComputeHash(extendedkey);
60                         Array.Clear(extendedkey, salt.Length, 4);
61
62                         /* T_i = U_1 ... */
63                         var f = u;
64                         for (int j = 1; j < iterationCount; j++)
65                         {
66                             /* Compute U_j. */
67                             u = hmac.ComputeHash(u);
68                             for (int k = 0; k < f.Length; k++)
69                             {
70                                 /* ... xor U_j ... */
71                                 f[k] ^= u[k];
72                             }
73                         }
74
75                         /* Copy as many bytes as necessary into memory stream. */
76                         ms.Write(f, 0, f.Length);
77                         Array.Clear(u, 0, u.Length);
78                         Array.Clear(f, 0, f.Length);
79                     }
80                     ms.Position = 0;
81
82                     /* Initialize result array. */
83                     var dk = new byte[dklen];
84
85                     /* Read key from memory stream. */
86                     ms.Read(dk, 0, dklen);
87
88                     ms.Position = 0;
89                     for (long i = 0; i < ms.Length; i++)
90                     {
91                         ms.WriteByte(0);
92                     }
93                     Array.Clear(extendedkey, 0, extendedkey.Length);
94                     return dk;
95                 }
96             }
97         }
98     }
99 }