DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
CryptoHashExtensions.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.IO;
19 using System.Security.Cryptography;
20 using System.Text;
21 
22 namespace Deveel.Data.Security {
23  public static class CryptoHashExtenions {
24  #region Pbkdf2
25 
26  private const int DefaultIterationCount = 10000;
27 
28  public static string MakePbkdf2String(this IKeyedHashFunction hash, string input, string salt, int length) {
29  return MakePbkdf2String(hash, input, salt, length, DefaultIterationCount);
30  }
31 
32  public static string MakePbkdf2String(this IKeyedHashFunction hash, string input, string salt, int length, int iterationCount) {
33  return hash.MakePbkdf2String(input, Convert.FromBase64String(salt), length, iterationCount);
34  }
35 
36  public static string MakePbkdf2String(this IKeyedHashFunction hash, string input, byte[] salt, int length) {
37  return MakePbkdf2String(hash, input, salt, length, DefaultIterationCount);
38  }
39 
40  public static string MakePbkdf2String(this IKeyedHashFunction hash, string input, byte[] salt, int length, int iterationCount) {
41  var data = Encoding.UTF8.GetBytes(input);
42  var result = hash.MakePbkdf2(data, salt, length, iterationCount);
43  return Convert.ToBase64String(result);
44  }
45 
46  public static byte[] MakePbkdf2(this IKeyedHashFunction hash, byte[] salt, int length, int iterationCount) {
47  var hashKey = hash.Key;
48  if (hashKey == null || hashKey.Length == 0)
49  throw new InvalidOperationException("Key was not specified for the hash.");
50 
51  return MakePbkdf2(hash, hashKey, salt, length, iterationCount);
52  }
53 
54  public static byte[] MakePbkdf2(this IKeyedHashFunction hash, byte[] data, byte[] salt, int length) {
55  return MakePbkdf2(hash, data, salt, length, DefaultIterationCount);
56  }
57 
58  public static byte[] MakePbkdf2(this IKeyedHashFunction hash, byte[] data, byte[] salt, int length, int iterationCount) {
59  hash.Key = data;
60 
61  int hashLength = hash.HashSize/8;
62  if ((hash.HashSize & 7) != 0)
63  hashLength++;
64 
65  int keyLength = length/hashLength;
66  if (length > (0xFFFFFFFFL*hashLength) || length < 0)
67  throw new ArgumentOutOfRangeException("length");
68 
69  if (length%hashLength != 0)
70  keyLength++;
71 
72  byte[] extendedkey = new byte[salt.Length + 4];
73  Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
74 
75  using (var ms = new MemoryStream()) {
76  for (int i = 0; i < keyLength; i++) {
77  extendedkey[salt.Length] = (byte) (((i + 1) >> 24) & 0xFF);
78  extendedkey[salt.Length + 1] = (byte) (((i + 1) >> 16) & 0xFF);
79  extendedkey[salt.Length + 2] = (byte) (((i + 1) >> 8) & 0xFF);
80  extendedkey[salt.Length + 3] = (byte) (((i + 1)) & 0xFF);
81 
82  byte[] u = hash.Compute(extendedkey);
83  Array.Clear(extendedkey, salt.Length, 4);
84 
85  byte[] f = u;
86  for (int j = 1; j < iterationCount; j++) {
87  u = hash.Compute(u);
88  for (int k = 0; k < f.Length; k++) {
89  f[k] ^= u[k];
90  }
91  }
92 
93  ms.Write(f, 0, f.Length);
94  Array.Clear(u, 0, u.Length);
95  Array.Clear(f, 0, f.Length);
96  }
97 
98  byte[] dk = new byte[length];
99  ms.Position = 0;
100  ms.Read(dk, 0, length);
101  ms.Position = 0;
102 
103  for (long i = 0; i < ms.Length; i++) {
104  ms.WriteByte(0);
105  }
106 
107  Array.Clear(extendedkey, 0, extendedkey.Length);
108  return dk;
109  }
110  }
111 
112  public static bool VerifyPbkdf2(this IKeyedHashFunction hash, byte[] hashed, byte[] otherData, byte[] salt) {
113  return VerifyPbkdf2(hash, hashed, otherData, salt, DefaultIterationCount);
114  }
115 
116  public static bool VerifyPbkdf2(this IKeyedHashFunction hash, byte[] hashed, byte[] otherData, byte[] salt, int iterationCount) {
117  int length = hashed.Length;
118 
119  var otherHashed = hash.MakePbkdf2(otherData, salt, length, iterationCount);
120 
121  if (otherHashed.Length != hashed.Length)
122  return false;
123 
124  return ByteArraysEqual(hashed, otherHashed);
125  }
126 
127  public static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, byte[] salt) {
128  return VerifyPbkdf2String(hash, hashedString, otherString, salt, DefaultIterationCount);
129  }
130 
131  public static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, byte[] salt, int iterationCount) {
132  return hash.VerifyPbkdf2String(hashedString, otherString, Convert.ToBase64String(salt), iterationCount);
133  }
134 
135  public static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, string saltString) {
136  return VerifyPbkdf2String(hash, hashedString, otherString, saltString, DefaultIterationCount);
137  }
138 
139  public static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, string saltString, int iterationCount) {
140  var hashed = Convert.FromBase64String(hashedString);
141  var otherData = Encoding.UTF8.GetBytes(otherString);
142  var salt = Convert.FromBase64String(saltString);
143 
144  return hash.VerifyPbkdf2(hashed, otherData, salt, iterationCount);
145  }
146 
147  private static bool ByteArraysEqual(byte[] a, byte[] b) {
148  if (ReferenceEquals(a, b)) {
149  return true;
150  }
151 
152  if (a == null || b == null || a.Length != b.Length) {
153  return false;
154  }
155 
156  bool areSame = true;
157  for (int i = 0; i < a.Length; i++) {
158  areSame &= (a[i] == b[i]);
159  }
160  return areSame;
161  }
162 
163  #endregion
164 
165  public static string ComputeString(this IHashFunction hash, string s) {
166  var data = Encoding.UTF8.GetBytes(s);
167  return BinaryToHex(hash.Compute(data));
168  }
169 
170  public static byte[] GenerateSalt(this IHashFunction hash) {
171  int byteLength = (hash.HashSize / 2) / 8;
172  byte[] buf = new byte[byteLength];
173  var rng = new RNGCryptoServiceProvider();
174  rng.GetBytes(buf);
175  return buf;
176  }
177 
178  public static string GenerateSaltString(this IHashFunction hash) {
179  return Convert.ToBase64String(hash.GenerateSalt());
180  }
181 
182  private static string BinaryToHex(byte[] data) {
183  char[] hex = new char[data.Length * 2];
184 
185  for (int iter = 0; iter < data.Length; iter++) {
186  byte hexChar = ((byte)(data[iter] >> 4));
187  hex[iter * 2] = (char)(hexChar > 9 ? hexChar + 0x37 : hexChar + 0x30);
188  hexChar = ((byte)(data[iter] & 0xF));
189  hex[(iter * 2) + 1] = (char)(hexChar > 9 ? hexChar + 0x37 : hexChar + 0x30);
190  }
191  return new string(hex);
192  }
193  }
194 }
static byte[] MakePbkdf2(this IKeyedHashFunction hash, byte[] salt, int length, int iterationCount)
static string MakePbkdf2String(this IKeyedHashFunction hash, string input, string salt, int length)
static string MakePbkdf2String(this IKeyedHashFunction hash, string input, byte[] salt, int length, int iterationCount)
static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, byte[] salt)
int HashSize
Gets the size of the hash to generate.
static bool ByteArraysEqual(byte[] a, byte[] b)
static string ComputeString(this IHashFunction hash, string s)
static string MakePbkdf2String(this IKeyedHashFunction hash, string input, string salt, int length, int iterationCount)
static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, string saltString)
Defines a function to hash as user provided password
static byte[] MakePbkdf2(this IKeyedHashFunction hash, byte[] data, byte[] salt, int length, int iterationCount)
static byte[] MakePbkdf2(this IKeyedHashFunction hash, byte[] data, byte[] salt, int length)
static string GenerateSaltString(this IHashFunction hash)
static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, string saltString, int iterationCount)
static bool VerifyPbkdf2String(this IKeyedHashFunction hash, string hashedString, string otherString, byte[] salt, int iterationCount)
An hash function that requires a private key to compute the final result.
static bool VerifyPbkdf2(this IKeyedHashFunction hash, byte[] hashed, byte[] otherData, byte[] salt)
byte[] Key
Gets or sets the private key to use for computing the hash.
static byte[] GenerateSalt(this IHashFunction hash)
byte[] Compute(byte[] data)
Computes the hash from the given input.
static bool VerifyPbkdf2(this IKeyedHashFunction hash, byte[] hashed, byte[] otherData, byte[] salt, int iterationCount)
static string MakePbkdf2String(this IKeyedHashFunction hash, string input, byte[] salt, int length)