1
2
3
4
5
6 using System;
7 using System.Collections;
8 using System.IO;
9
10 namespace System.Security
11 {
12 public inline uint LeftRotate(uint x, uint n)
13 {
14 return (x << n) ^ (x >> (32u - n));
15 }
16
17 public class Sha1
18 {
19 public Sha1()
20 {
21 Reset();
22 }
23 public void Reset()
24 {
25 digest[0] = 1732584193u;
26 digest[1] = 4023233417u;
27 digest[2] = 2562383102u;
28 digest[3] = 271733878u;
29 digest[4] = 3285377520u;
30 byteIndex = 0u;
31 bitCount = 0u;
32 }
33 public void Process(byte x)
34 {
35 ProcessByte(x);
36 bitCount = bitCount + 8u;
37 }
38 public void Process(byte* begin, byte* end)
39 {
40 while (begin != end)
41 {
42 Process(*begin);
43 ++begin;
44 }
45 }
46 public void Process(byte* buf, long count)
47 {
48 Process(buf, buf + count);
49 }
50 [nodiscard]
51 public Result<string> GetDigest()
52 {
53 ProcessByte(128u);
54 if (byteIndex > 56u)
55 {
56 while (byteIndex != 0u)
57 {
58 ProcessByte(0u);
59 }
60 while (byteIndex < 56u)
61 {
62 ProcessByte(0u);
63 }
64 }
65 else
66 {
67 while (byteIndex < 56u)
68 {
69 ProcessByte(0u);
70 }
71 }
72 ProcessByte(cast<byte>((bitCount >> 56u) & 255u));
73 ProcessByte(cast<byte>((bitCount >> 48u) & 255u));
74 ProcessByte(cast<byte>((bitCount >> 40u) & 255u));
75 ProcessByte(cast<byte>((bitCount >> 32u) & 255u));
76 ProcessByte(cast<byte>((bitCount >> 24u) & 255u));
77 ProcessByte(cast<byte>((bitCount >> 16u) & 255u));
78 ProcessByte(cast<byte>((bitCount >> 8u) & 255u));
79 ProcessByte(cast<byte>(bitCount & 255u));
80 auto result = ToHexString(digest[0]);
81 if (result.Error())
82 {
83 return Result<string>(ErrorId(result.GetErrorId()));
84 }
85 string s = result.Value();
86 result = ToHexString(digest[1]);
87 if (result.Error())
88 {
89 return Result<string>(ErrorId(result.GetErrorId()));
90 }
91 s.Append(result.Value());
92 result = ToHexString(digest[2]);
93 if (result.Error())
94 {
95 return Result<string>(ErrorId(result.GetErrorId()));
96 }
97 s.Append(result.Value());
98 result = ToHexString(digest[3]);
99 if (result.Error())
100 {
101 return Result<string>(ErrorId(result.GetErrorId()));
102 }
103 s.Append(result.Value());
104 result = ToHexString(digest[4]);
105 if (result.Error())
106 {
107 return Result<string>(ErrorId(result.GetErrorId()));
108 }
109 s.Append(result.Value());
110 return Result<string>(s);
111 }
112 private void ProcessByte(byte x)
113 {
114 block[byteIndex++] = x;
115 if (byteIndex == 64u)
116 {
117 byteIndex = 0u;
118 ProcessBlock();
119 }
120 }
121 private void ProcessBlock()
122 {
123 uint[80] w;
124 for (int i = 0; i < 16; ++i;)
125 {
126 w[i] = cast<uint>(block[4 * i]) << 24u;
127 w[i] = w[i] | cast<uint>(block[4 * i + 1]) << 16u;
128 w[i] = w[i] | cast<uint>(block[4 * i + 2]) << 8u;
129 w[i] = w[i] | cast<uint>(block[4 * i + 3]);
130 }
131 for (int i = 16; i < 80; ++i;)
132 {
133 w[i] = LeftRotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1u);
134 }
135 uint a = digest[0];
136 uint b = digest[1];
137 uint c = digest[2];
138 uint d = digest[3];
139 uint e = digest[4];
140 for (int i = 0; i < 80; ++i;)
141 {
142 uint f;
143 uint k;
144 if (i < 20)
145 {
146 f = (b & c) | (~b & d);
147 k = 1518500249u;
148 }
149 else if (i < 40)
150 {
151 f = b ^ c ^ d;
152 k = 1859775393u;
153 }
154 else if (i < 60)
155 {
156 f = (b & c) | (b & d) | (c & d);
157 k = 2400959708u;
158 }
159 else
160 {
161 f = b ^ c ^ d;
162 k = 3395469782u;
163 }
164 uint temp = LeftRotate(a, 5u) + f + e + k + w[i];
165 e = d;
166 d = c;
167 c = LeftRotate(b, 30u);
168 b = a;
169 a = temp;
170 }
171 digest[0] = digest[0] + a;
172 digest[1] = digest[1] + b;
173 digest[2] = digest[2] + c;
174 digest[3] = digest[3] + d;
175 digest[4] = digest[4] + e;
176 }
177 private uint[5] digest;
178 private byte[64] block;
179 private byte byteIndex;
180 private ulong bitCount;
181 }
182
183 [nodiscard]
184 public Result<string> GetSha1MessageDigest(const string& message)
185 {
186 byte* data = cast<byte*>(cast<void*>(message.Chars()));
187 long count = message.Length();
188 return GetSha1MessageDigest(data, count);
189 }
190
191 [nodiscard]
192 public Result<string> GetSha1MessageDigest(byte* data, long count)
193 {
194 Sha1 sha1;
195 sha1.Process(data, count);
196 return sha1.GetDigest();
197 }
198
199 [nodiscard]
200 public Result<string> GetSha1FileDigest(const string& filePath)
201 {
202 Sha1 sha1;
203 auto nr = File.Size(filePath);
204 if (nr.Error())
205 {
206 return Result<string>(ErrorId(nr.GetErrorId()));
207 }
208 long n = nr.Value();
209 if (n > 0)
210 {
211 auto readerResult = File.OpenBinary(filePath);
212 if (readerResult.Error())
213 {
214 return Result<string>(ErrorId(readerResult.GetErrorId()));
215 }
216 BinaryReader& reader = readerResult.Value();
217 for (long i = 0; i < n; ++i;)
218 {
219 auto result = reader.ReadByte();
220 if (result.Error())
221 {
222 return Result<string>(ErrorId(result.GetErrorId()));
223 }
224 sha1.Process(result.Value());
225 }
226 }
227 return sha1.GetDigest();
228 }
229
230 [nodiscard]
231 public Result<string> GetCumulativeSha1FileDigest(const List<string>& filePaths)
232 {
233 Sha1 sha1;
234 for (const string& filePath : filePaths)
235 {
236 auto nr = File.Size(filePath);
237 if (nr.Error())
238 {
239 return Result<string>(ErrorId(nr.GetErrorId()));
240 }
241 long n = nr.Value();
242 if (n > 0)
243 {
244 auto readerResult = File.OpenBinary(filePath);
245 if (readerResult.Error())
246 {
247 return Result<string>(ErrorId(readerResult.GetErrorId()));
248 }
249 BinaryReader& reader = readerResult.Value();
250 for (long i = 0; i < n; ++i;)
251 {
252 auto result = reader.ReadByte();
253 if (result.Error())
254 {
255 return Result<string>(ErrorId(result.GetErrorId()));
256 }
257 sha1.Process(result.Value());
258 }
259 }
260 }
261 return sha1.GetDigest();
262 }