root / trunk / Pithos.Network / Signature.cs @ c875d683
History | View | Annotate | Download (12.6 kB)
1 | 255f5f86 | Panagiotis Kanavos | #region |
---|---|---|---|
2 | 255f5f86 | Panagiotis Kanavos | /* ----------------------------------------------------------------------- |
3 | 255f5f86 | Panagiotis Kanavos | * <copyright file="Signature.cs" company="GRNet"> |
4 | 255f5f86 | Panagiotis Kanavos | * |
5 | 255f5f86 | Panagiotis Kanavos | * Copyright 2011-2012 GRNET S.A. All rights reserved. |
6 | 255f5f86 | Panagiotis Kanavos | * |
7 | 255f5f86 | Panagiotis Kanavos | * Redistribution and use in source and binary forms, with or |
8 | 255f5f86 | Panagiotis Kanavos | * without modification, are permitted provided that the following |
9 | 255f5f86 | Panagiotis Kanavos | * conditions are met: |
10 | 255f5f86 | Panagiotis Kanavos | * |
11 | 255f5f86 | Panagiotis Kanavos | * 1. Redistributions of source code must retain the above |
12 | 255f5f86 | Panagiotis Kanavos | * copyright notice, this list of conditions and the following |
13 | 255f5f86 | Panagiotis Kanavos | * disclaimer. |
14 | 255f5f86 | Panagiotis Kanavos | * |
15 | 255f5f86 | Panagiotis Kanavos | * 2. Redistributions in binary form must reproduce the above |
16 | 255f5f86 | Panagiotis Kanavos | * copyright notice, this list of conditions and the following |
17 | 255f5f86 | Panagiotis Kanavos | * disclaimer in the documentation and/or other materials |
18 | 255f5f86 | Panagiotis Kanavos | * provided with the distribution. |
19 | 255f5f86 | Panagiotis Kanavos | * |
20 | 255f5f86 | Panagiotis Kanavos | * |
21 | 255f5f86 | Panagiotis Kanavos | * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
22 | 255f5f86 | Panagiotis Kanavos | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
23 | 255f5f86 | Panagiotis Kanavos | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | 255f5f86 | Panagiotis Kanavos | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
25 | 255f5f86 | Panagiotis Kanavos | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 | 255f5f86 | Panagiotis Kanavos | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
27 | 255f5f86 | Panagiotis Kanavos | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
28 | 255f5f86 | Panagiotis Kanavos | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
29 | 255f5f86 | Panagiotis Kanavos | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | 255f5f86 | Panagiotis Kanavos | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
31 | 255f5f86 | Panagiotis Kanavos | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | 255f5f86 | Panagiotis Kanavos | * POSSIBILITY OF SUCH DAMAGE. |
33 | 255f5f86 | Panagiotis Kanavos | * |
34 | 255f5f86 | Panagiotis Kanavos | * The views and conclusions contained in the software and |
35 | 255f5f86 | Panagiotis Kanavos | * documentation are those of the authors and should not be |
36 | 255f5f86 | Panagiotis Kanavos | * interpreted as representing official policies, either expressed |
37 | 255f5f86 | Panagiotis Kanavos | * or implied, of GRNET S.A. |
38 | 255f5f86 | Panagiotis Kanavos | * </copyright> |
39 | 255f5f86 | Panagiotis Kanavos | * ----------------------------------------------------------------------- |
40 | 255f5f86 | Panagiotis Kanavos | */ |
41 | 255f5f86 | Panagiotis Kanavos | #endregion |
42 | 0c02aa65 | Panagiotis Kanavos | using System; |
43 | 0c02aa65 | Panagiotis Kanavos | using System.Collections.Concurrent; |
44 | 0c02aa65 | Panagiotis Kanavos | using System.Collections.Generic; |
45 | 9c4346c9 | Panagiotis Kanavos | using System.Diagnostics.Contracts; |
46 | 0eea575a | Panagiotis Kanavos | using System.IO; |
47 | 6bcdd8e2 | Panagiotis Kanavos | using System.Reflection; |
48 | 9c4346c9 | Panagiotis Kanavos | using System.Runtime.Remoting.Metadata.W3cXsd2001; |
49 | 0eea575a | Panagiotis Kanavos | using System.Security.Cryptography; |
50 | c875d683 | pkanavos | using System.Threading; |
51 | 0c02aa65 | Panagiotis Kanavos | using System.Threading.Tasks; |
52 | 0c02aa65 | Panagiotis Kanavos | using System.Linq; |
53 | 0eea575a | Panagiotis Kanavos | |
54 | 1caef52e | Panagiotis Kanavos | namespace Pithos.Network |
55 | 0eea575a | Panagiotis Kanavos | { |
56 | 9c4346c9 | Panagiotis Kanavos | public static class Signature |
57 | 0eea575a | Panagiotis Kanavos | { |
58 | 6bcdd8e2 | Panagiotis Kanavos | private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
59 | f5f9b225 | pkanavos | public const int BufferSize = 16384; |
60 | 6bcdd8e2 | Panagiotis Kanavos | |
61 | a60e5887 | pkanavos | public const string MD5_EMPTY = "d41d8cd98f00b204e9800998ecf8427e"; |
62 | cd942434 | pkanavos | public const string MERKLE_EMPTY = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; |
63 | a60e5887 | pkanavos | |
64 | a60e5887 | pkanavos | |
65 | a60e5887 | pkanavos | public static string CalculateMD5(FileSystemInfo info) |
66 | a27aa447 | Panagiotis Kanavos | { |
67 | a27aa447 | Panagiotis Kanavos | if (info==null) |
68 | a27aa447 | Panagiotis Kanavos | throw new ArgumentNullException("info"); |
69 | cfed7823 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(info.FullName)) |
70 | cfed7823 | Panagiotis Kanavos | throw new ArgumentException("info.FullName is empty","info"); |
71 | a27aa447 | Panagiotis Kanavos | Contract.EndContractBlock(); |
72 | a27aa447 | Panagiotis Kanavos | |
73 | a60e5887 | pkanavos | if (info is DirectoryInfo) |
74 | a60e5887 | pkanavos | return MD5_EMPTY; |
75 | a60e5887 | pkanavos | |
76 | a27aa447 | Panagiotis Kanavos | return CalculateMD5(info.FullName); |
77 | a27aa447 | Panagiotis Kanavos | } |
78 | a27aa447 | Panagiotis Kanavos | |
79 | 9c4346c9 | Panagiotis Kanavos | public static string CalculateMD5(string path) |
80 | 0eea575a | Panagiotis Kanavos | { |
81 | 9c4346c9 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(path)) |
82 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentNullException("path"); |
83 | 9c4346c9 | Panagiotis Kanavos | Contract.EndContractBlock(); |
84 | 0c02aa65 | Panagiotis Kanavos | |
85 | 1caef52e | Panagiotis Kanavos | //DON'T calculate hashes for folders |
86 | 1caef52e | Panagiotis Kanavos | if (Directory.Exists(path)) |
87 | 1caef52e | Panagiotis Kanavos | return ""; |
88 | 1caef52e | Panagiotis Kanavos | |
89 | 9c4346c9 | Panagiotis Kanavos | string hash; |
90 | 9c4346c9 | Panagiotis Kanavos | using (var hasher = MD5.Create()) |
91 | f5f9b225 | pkanavos | using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, Signature.BufferSize, true)) |
92 | 0c02aa65 | Panagiotis Kanavos | { |
93 | 9c4346c9 | Panagiotis Kanavos | var hashBytes = hasher.ComputeHash(stream); |
94 | 9c4346c9 | Panagiotis Kanavos | hash = hashBytes.ToHashString(); |
95 | 9c4346c9 | Panagiotis Kanavos | } |
96 | 9c4346c9 | Panagiotis Kanavos | return hash; |
97 | 9c4346c9 | Panagiotis Kanavos | } |
98 | 9c4346c9 | Panagiotis Kanavos | |
99 | 9c4346c9 | Panagiotis Kanavos | /* |
100 | 9c4346c9 | Panagiotis Kanavos | public static string BytesToString(byte[] hashBytes) |
101 | 9c4346c9 | Panagiotis Kanavos | { |
102 | 9c4346c9 | Panagiotis Kanavos | var shb=new SoapHexBinary(hashBytes); |
103 | 9c4346c9 | Panagiotis Kanavos | return shb.ToString(); |
104 | 0c02aa65 | Panagiotis Kanavos | |
105 | 9c4346c9 | Panagiotis Kanavos | } |
106 | 0c02aa65 | Panagiotis Kanavos | |
107 | 0c02aa65 | Panagiotis Kanavos | |
108 | 9c4346c9 | Panagiotis Kanavos | public static byte[] StringToBytes(string hash) |
109 | 0c02aa65 | Panagiotis Kanavos | { |
110 | 9c4346c9 | Panagiotis Kanavos | var shb=SoapHexBinary.Parse(hash); |
111 | 9c4346c9 | Panagiotis Kanavos | return shb.Value; |
112 | 0c02aa65 | Panagiotis Kanavos | } |
113 | 9c4346c9 | Panagiotis Kanavos | */ |
114 | 0c02aa65 | Panagiotis Kanavos | |
115 | 9c4346c9 | Panagiotis Kanavos | public static byte[] ToBytes(this string hash) |
116 | 9c4346c9 | Panagiotis Kanavos | { |
117 | 9c4346c9 | Panagiotis Kanavos | var shb = SoapHexBinary.Parse(hash); |
118 | 9c4346c9 | Panagiotis Kanavos | return shb.Value; |
119 | 9c4346c9 | Panagiotis Kanavos | } |
120 | 9c4346c9 | Panagiotis Kanavos | |
121 | 9c4346c9 | Panagiotis Kanavos | public static string ToHashString(this byte[] hashBytes) |
122 | 0c02aa65 | Panagiotis Kanavos | { |
123 | 9c4346c9 | Panagiotis Kanavos | var shb = new SoapHexBinary(hashBytes); |
124 | bfc13ed8 | Panagiotis Kanavos | return shb.ToString().ToLower(); |
125 | 9c4346c9 | Panagiotis Kanavos | } |
126 | 9c4346c9 | Panagiotis Kanavos | |
127 | c875d683 | pkanavos | public static TreeHash CalculateTreeHash(FileSystemInfo fileInfo, int blockSize, string algorithm,CancellationToken token,IProgress<double> progress ) |
128 | a27aa447 | Panagiotis Kanavos | { |
129 | 174bbb6e | Panagiotis Kanavos | if (fileInfo == null) |
130 | a27aa447 | Panagiotis Kanavos | throw new ArgumentNullException("fileInfo"); |
131 | cfed7823 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(fileInfo.FullName)) |
132 | 174bbb6e | Panagiotis Kanavos | throw new ArgumentException("fileInfo.FullName is empty", "fileInfo"); |
133 | a27aa447 | Panagiotis Kanavos | if (blockSize <= 0) |
134 | a27aa447 | Panagiotis Kanavos | throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero "); |
135 | a27aa447 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(algorithm)) |
136 | a27aa447 | Panagiotis Kanavos | throw new ArgumentNullException("algorithm"); |
137 | a27aa447 | Panagiotis Kanavos | Contract.EndContractBlock(); |
138 | c945b450 | pkanavos | fileInfo.Refresh(); |
139 | 174bbb6e | Panagiotis Kanavos | if (fileInfo is DirectoryInfo || !fileInfo.Exists) |
140 | 174bbb6e | Panagiotis Kanavos | return TreeHash.Empty; |
141 | 174bbb6e | Panagiotis Kanavos | |
142 | c875d683 | pkanavos | return CalculateTreeHash(fileInfo.FullName, blockSize, algorithm,token,progress); |
143 | a27aa447 | Panagiotis Kanavos | } |
144 | 0c02aa65 | Panagiotis Kanavos | |
145 | 9c4346c9 | Panagiotis Kanavos | /// <summary> |
146 | 9c4346c9 | Panagiotis Kanavos | /// Calculates a file's tree hash synchronously, using the specified block size |
147 | 9c4346c9 | Panagiotis Kanavos | /// </summary> |
148 | 9c4346c9 | Panagiotis Kanavos | /// <param name="filePath">Path to an existing file</param> |
149 | 9c4346c9 | Panagiotis Kanavos | /// <param name="blockSize">Block size used to calculate leaf hashes</param> |
150 | 9c4346c9 | Panagiotis Kanavos | /// <param name="algorithm"></param> |
151 | 9c4346c9 | Panagiotis Kanavos | /// <returns>A <see cref="TreeHash"/> with the block hashes and top hash</returns> |
152 | c875d683 | pkanavos | public static TreeHash CalculateTreeHash(string filePath, int blockSize, string algorithm,CancellationToken token,IProgress<double> progress ) |
153 | 9c4346c9 | Panagiotis Kanavos | { |
154 | 9c4346c9 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(filePath)) |
155 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentNullException("filePath"); |
156 | 9c4346c9 | Panagiotis Kanavos | if (blockSize<=0) |
157 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentOutOfRangeException("blockSize","blockSize must be a value greater than zero "); |
158 | 9c4346c9 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(algorithm)) |
159 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentNullException("algorithm"); |
160 | 4b58c004 | pkanavos | Contract.EndContractBlock(); |
161 | c875d683 | pkanavos | var hash=CalculateTreeHashAsync(filePath, blockSize, algorithm, 1,token,progress); |
162 | 4b58c004 | pkanavos | return hash; |
163 | 0c02aa65 | Panagiotis Kanavos | } |
164 | a27aa447 | Panagiotis Kanavos | |
165 | c875d683 | pkanavos | public static TreeHash CalculateTreeHashAsync(FileInfo fileInfo, int blockSize, string algorithm, byte parallelism,CancellationToken token,IProgress<double> progress ) |
166 | a27aa447 | Panagiotis Kanavos | { |
167 | a27aa447 | Panagiotis Kanavos | if (fileInfo == null) |
168 | a27aa447 | Panagiotis Kanavos | throw new ArgumentNullException("fileInfo"); |
169 | cfed7823 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(fileInfo.FullName)) |
170 | cfed7823 | Panagiotis Kanavos | throw new ArgumentNullException("fileInfo.FullName is empty","fileInfo"); |
171 | a27aa447 | Panagiotis Kanavos | if (blockSize <= 0) |
172 | a27aa447 | Panagiotis Kanavos | throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero "); |
173 | a27aa447 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(algorithm)) |
174 | a27aa447 | Panagiotis Kanavos | throw new ArgumentNullException("algorithm"); |
175 | a27aa447 | Panagiotis Kanavos | Contract.EndContractBlock(); |
176 | 422c9598 | Panagiotis Kanavos | |
177 | c875d683 | pkanavos | return CalculateTreeHashAsync(fileInfo.FullName, blockSize, algorithm, parallelism,token,progress); |
178 | a27aa447 | Panagiotis Kanavos | } |
179 | 0c02aa65 | Panagiotis Kanavos | |
180 | 9c4346c9 | Panagiotis Kanavos | |
181 | c875d683 | pkanavos | public static TreeHash CalculateTreeHashAsync(string filePath, int blockSize,string algorithm, int parallelism,CancellationToken token,IProgress<double> progress ) |
182 | 9c4346c9 | Panagiotis Kanavos | { |
183 | 1caef52e | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(filePath)) |
184 | 1caef52e | Panagiotis Kanavos | throw new ArgumentNullException("filePath"); |
185 | 9c4346c9 | Panagiotis Kanavos | if (blockSize <= 0) |
186 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero "); |
187 | 9c4346c9 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(algorithm)) |
188 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentNullException("algorithm"); |
189 | 9c4346c9 | Panagiotis Kanavos | Contract.EndContractBlock(); |
190 | 9c4346c9 | Panagiotis Kanavos | |
191 | 174bbb6e | Panagiotis Kanavos | if (Log.IsDebugEnabled) |
192 | 174bbb6e | Panagiotis Kanavos | Log.DebugFormat("Calc Signature [{0}]",filePath); |
193 | 174bbb6e | Panagiotis Kanavos | |
194 | e1fa1d21 | pkanavos | if (filePath.Split('/').Contains(".pithos.cache")) |
195 | e1fa1d21 | pkanavos | throw new ArgumentException(String.Format("Trying to hash file from the cache folder: [{0}]",filePath)); |
196 | e1fa1d21 | pkanavos | |
197 | 1caef52e | Panagiotis Kanavos | //DON'T calculate hashes for folders |
198 | 1caef52e | Panagiotis Kanavos | if (Directory.Exists(filePath)) |
199 | 437abfca | Panagiotis Kanavos | return new TreeHash(algorithm); |
200 | a64c87c8 | Panagiotis Kanavos | //The hash of a non-existent file is the empty hash |
201 | a64c87c8 | Panagiotis Kanavos | if (!File.Exists(filePath)) |
202 | 437abfca | Panagiotis Kanavos | return new TreeHash(algorithm); |
203 | 1caef52e | Panagiotis Kanavos | |
204 | a27aa447 | Panagiotis Kanavos | //Calculate the hash of all blocks using a blockhash iterator |
205 | f5f9b225 | pkanavos | using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, BufferSize, true)) |
206 | a27aa447 | Panagiotis Kanavos | { |
207 | db63c1ae | pkanavos | var md5 = new MD5BlockCalculator(); |
208 | db63c1ae | pkanavos | Action<long, byte[], int> postAction = md5.PostBlock; |
209 | a27aa447 | Panagiotis Kanavos | //Calculate the blocks asyncrhonously |
210 | c875d683 | pkanavos | var hashes = BlockHashAlgorithms.CalculateBlockHashesInPlacePFor(stream, blockSize, algorithm, parallelism,postAction,token, progress).Result; |
211 | 437abfca | Panagiotis Kanavos | |
212 | a27aa447 | Panagiotis Kanavos | //And then proceed with creating and returning a TreeHash |
213 | 437abfca | Panagiotis Kanavos | var length = stream.Length; |
214 | 437abfca | Panagiotis Kanavos | var list = hashes.OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList(); |
215 | a27aa447 | Panagiotis Kanavos | |
216 | a27aa447 | Panagiotis Kanavos | var treeHash = new TreeHash(algorithm) |
217 | a27aa447 | Panagiotis Kanavos | { |
218 | 437abfca | Panagiotis Kanavos | Bytes = length, |
219 | 437abfca | Panagiotis Kanavos | BlockSize = blockSize, |
220 | 43dd02a8 | pkanavos | Hashes = list, |
221 | a27aa447 | Panagiotis Kanavos | }; |
222 | a27aa447 | Panagiotis Kanavos | |
223 | 43dd02a8 | pkanavos | string fileHash; |
224 | db63c1ae | pkanavos | |
225 | db63c1ae | pkanavos | var md5Hash=md5.GetHash().Result; |
226 | db63c1ae | pkanavos | /* |
227 | 43dd02a8 | pkanavos | var hasher = HashAlgorithm.Create("MD5"); |
228 | 43dd02a8 | pkanavos | stream.Position = 0; |
229 | db63c1ae | pkanavos | */ |
230 | db63c1ae | pkanavos | treeHash.MD5= md5Hash; |
231 | 43dd02a8 | pkanavos | |
232 | 437abfca | Panagiotis Kanavos | return treeHash; |
233 | a27aa447 | Panagiotis Kanavos | } |
234 | a27aa447 | Panagiotis Kanavos | } |
235 | 9c4346c9 | Panagiotis Kanavos | |
236 | 437abfca | Panagiotis Kanavos | |
237 | 6e25cc48 | Panagiotis Kanavos | public static byte[] CalculateTopHash(IList<byte[]> hashMap, string algorithm) |
238 | 1caef52e | Panagiotis Kanavos | { |
239 | 1caef52e | Panagiotis Kanavos | if (hashMap == null) |
240 | 1caef52e | Panagiotis Kanavos | throw new ArgumentNullException("hashMap"); |
241 | 1caef52e | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(algorithm)) |
242 | 1caef52e | Panagiotis Kanavos | throw new ArgumentNullException("algorithm"); |
243 | 6e25cc48 | Panagiotis Kanavos | Contract.EndContractBlock(); |
244 | 1caef52e | Panagiotis Kanavos | |
245 | 6e25cc48 | Panagiotis Kanavos | var hashCount = hashMap.Count; |
246 | 6e25cc48 | Panagiotis Kanavos | //The tophash of an empty hashmap is an empty array |
247 | 1caef52e | Panagiotis Kanavos | if (hashCount == 0) |
248 | 6e25cc48 | Panagiotis Kanavos | return new byte[0]; |
249 | 6e25cc48 | Panagiotis Kanavos | //The tophash of a one-item hashmap is the hash itself |
250 | 1caef52e | Panagiotis Kanavos | if (hashCount == 1) |
251 | 6e25cc48 | Panagiotis Kanavos | return hashMap[0]; |
252 | 1caef52e | Panagiotis Kanavos | |
253 | 6e25cc48 | Panagiotis Kanavos | //Calculate the required number of leaf nodes |
254 | 5ce54458 | Panagiotis Kanavos | var leafs =(int)Math.Pow(2, Math.Ceiling(Math.Log(hashCount,2))); |
255 | 6e25cc48 | Panagiotis Kanavos | //The size of all nodes is the same and equal to the size of the input hashes |
256 | 6e25cc48 | Panagiotis Kanavos | var hashSize = hashMap[0].Length; |
257 | 6e25cc48 | Panagiotis Kanavos | |
258 | 6e25cc48 | Panagiotis Kanavos | //If the hashmap containes fewer nodes than the required leaf count, we need to fill |
259 | 6e25cc48 | Panagiotis Kanavos | //the rest with empty blocks |
260 | 6e25cc48 | Panagiotis Kanavos | byte[] empty=null; |
261 | 6e25cc48 | Panagiotis Kanavos | if (hashCount < leafs) |
262 | 6e25cc48 | Panagiotis Kanavos | empty = new byte[hashSize]; |
263 | 6e25cc48 | Panagiotis Kanavos | |
264 | 6e25cc48 | Panagiotis Kanavos | //New hashes will be stored in a dictionary keyed by their step to preserve order |
265 | 6e25cc48 | Panagiotis Kanavos | var newHashes=new ConcurrentDictionary<int, byte[]>(); |
266 | 6e25cc48 | Panagiotis Kanavos | |
267 | 6e25cc48 | Panagiotis Kanavos | Parallel.For(0, leafs/2, |
268 | 6e25cc48 | Panagiotis Kanavos | (step, state) => |
269 | 1caef52e | Panagiotis Kanavos | { |
270 | 6e25cc48 | Panagiotis Kanavos | using (var hasher = HashAlgorithm.Create(algorithm)) |
271 | 6e25cc48 | Panagiotis Kanavos | { |
272 | 6e25cc48 | Panagiotis Kanavos | var i = step*2; |
273 | 6e25cc48 | Panagiotis Kanavos | var block1 = i <= hashCount - 1 ? hashMap[i] : empty; |
274 | 6e25cc48 | Panagiotis Kanavos | var block2 = i <= hashCount - 2 ? hashMap[i + 1] : empty; |
275 | 6e25cc48 | Panagiotis Kanavos | |
276 | 6e25cc48 | Panagiotis Kanavos | hasher.TransformBlock(block1, 0, block1.Length, null, 0); |
277 | 6e25cc48 | Panagiotis Kanavos | hasher.TransformFinalBlock(block2, 0, block2.Length); |
278 | 6e25cc48 | Panagiotis Kanavos | |
279 | 6e25cc48 | Panagiotis Kanavos | var finalHash = hasher.Hash; |
280 | 6e25cc48 | Panagiotis Kanavos | //Store the final value in its proper place |
281 | 6e25cc48 | Panagiotis Kanavos | newHashes[step] = finalHash; |
282 | 6e25cc48 | Panagiotis Kanavos | } |
283 | 6e25cc48 | Panagiotis Kanavos | }); |
284 | 34bdb91d | Panagiotis Kanavos | |
285 | 6e25cc48 | Panagiotis Kanavos | //Extract the hashes to a list ordered by their step |
286 | 6e25cc48 | Panagiotis Kanavos | var hashes = newHashes.OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList(); |
287 | 6e25cc48 | Panagiotis Kanavos | return CalculateTopHash(hashes, algorithm); |
288 | 34bdb91d | Panagiotis Kanavos | } |
289 | 9c4346c9 | Panagiotis Kanavos | |
290 | 9c4346c9 | Panagiotis Kanavos | |
291 | 9c4346c9 | Panagiotis Kanavos | public static byte[] CalculateHash(byte[] buffer,string algorithm) |
292 | 9c4346c9 | Panagiotis Kanavos | { |
293 | 9c4346c9 | Panagiotis Kanavos | if (buffer == null) |
294 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentNullException("buffer"); |
295 | 9c4346c9 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(algorithm)) |
296 | 9c4346c9 | Panagiotis Kanavos | throw new ArgumentNullException("algorithm"); |
297 | 9c4346c9 | Panagiotis Kanavos | Contract.EndContractBlock(); |
298 | 9c4346c9 | Panagiotis Kanavos | |
299 | 9c4346c9 | Panagiotis Kanavos | using (var hasher = HashAlgorithm.Create(algorithm)) |
300 | 9c4346c9 | Panagiotis Kanavos | { |
301 | 9c4346c9 | Panagiotis Kanavos | var hash = hasher.ComputeHash(buffer, 0, buffer.Length); |
302 | 9c4346c9 | Panagiotis Kanavos | return hash; |
303 | 9c4346c9 | Panagiotis Kanavos | } |
304 | 0c02aa65 | Panagiotis Kanavos | } |
305 | 0c02aa65 | Panagiotis Kanavos | } |
306 | 9c4346c9 | Panagiotis Kanavos | } |
307 | 9c4346c9 | Panagiotis Kanavos | |
308 | 0c02aa65 | Panagiotis Kanavos | |
309 | 9c4346c9 | Panagiotis Kanavos |