Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / sha256managed.cs
blob242bfff1b172424f2615ba4f2dd3e796e115699a
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 //
9 //
10 // SHA256Managed.cs
12 // C# implementation of the proposed SHA-256 hash algorithm
15 namespace System.Security.Cryptography {
16 using System;
17 using System.Security;
18 using System.Diagnostics.Contracts;
20 [System.Runtime.InteropServices.ComVisible(true)]
21 public class SHA256Managed : SHA256
23 private byte[] _buffer;
24 private long _count; // Number of bytes in the hashed message
25 private UInt32[] _stateSHA256;
26 private UInt32[] _W;
29 // public constructors
32 public SHA256Managed()
34 #if FEATURE_CRYPTO
35 if (CryptoConfig.AllowOnlyFipsAlgorithms)
36 throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NonCompliantFIPSAlgorithm"));
37 Contract.EndContractBlock();
38 #endif // FEATURE_CRYPTO
40 _stateSHA256 = new UInt32[8];
41 _buffer = new byte[64];
42 _W = new UInt32[64];
44 InitializeState();
48 // public methods
51 public override void Initialize() {
52 InitializeState();
54 // Zeroize potentially sensitive information.
55 Array.Clear(_buffer, 0, _buffer.Length);
56 Array.Clear(_W, 0, _W.Length);
59 protected override void HashCore(byte[] rgb, int ibStart, int cbSize) {
60 _HashData(rgb, ibStart, cbSize);
63 protected override byte[] HashFinal() {
64 return _EndHash();
68 // private methods
71 private void InitializeState() {
72 _count = 0;
74 _stateSHA256[0] = 0x6a09e667;
75 _stateSHA256[1] = 0xbb67ae85;
76 _stateSHA256[2] = 0x3c6ef372;
77 _stateSHA256[3] = 0xa54ff53a;
78 _stateSHA256[4] = 0x510e527f;
79 _stateSHA256[5] = 0x9b05688c;
80 _stateSHA256[6] = 0x1f83d9ab;
81 _stateSHA256[7] = 0x5be0cd19;
84 /* SHA256 block update operation. Continues an SHA message-digest
85 operation, processing another message block, and updating the
86 context.
89 [System.Security.SecuritySafeCritical] // auto-generated
90 private unsafe void _HashData(byte[] partIn, int ibStart, int cbSize)
92 int bufferLen;
93 int partInLen = cbSize;
94 int partInBase = ibStart;
96 /* Compute length of buffer */
97 bufferLen = (int) (_count & 0x3f);
99 /* Update number of bytes */
100 _count += partInLen;
102 fixed (uint* stateSHA256 = _stateSHA256) {
103 fixed (byte* buffer = _buffer) {
104 fixed (uint* expandedBuffer = _W) {
105 if ((bufferLen > 0) && (bufferLen + partInLen >= 64)) {
106 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, 64 - bufferLen);
107 partInBase += (64 - bufferLen);
108 partInLen -= (64 - bufferLen);
109 SHATransform(expandedBuffer, stateSHA256, buffer);
110 bufferLen = 0;
113 /* Copy input to temporary buffer and hash */
114 while (partInLen >= 64) {
115 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, 0, 64);
116 partInBase += 64;
117 partInLen -= 64;
118 SHATransform(expandedBuffer, stateSHA256, buffer);
121 if (partInLen > 0) {
122 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen);
129 /* SHA256 finalization. Ends an SHA256 message-digest operation, writing
130 the message digest.
133 private byte[] _EndHash()
135 byte[] pad;
136 int padLen;
137 long bitCount;
138 byte[] hash = new byte[32]; // HashSizeValue = 256
140 /* Compute padding: 80 00 00 ... 00 00 <bit count>
143 padLen = 64 - (int)(_count & 0x3f);
144 if (padLen <= 8)
145 padLen += 64;
147 pad = new byte[padLen];
148 pad[0] = 0x80;
150 // Convert count to bit count
151 bitCount = _count * 8;
153 pad[padLen-8] = (byte) ((bitCount >> 56) & 0xff);
154 pad[padLen-7] = (byte) ((bitCount >> 48) & 0xff);
155 pad[padLen-6] = (byte) ((bitCount >> 40) & 0xff);
156 pad[padLen-5] = (byte) ((bitCount >> 32) & 0xff);
157 pad[padLen-4] = (byte) ((bitCount >> 24) & 0xff);
158 pad[padLen-3] = (byte) ((bitCount >> 16) & 0xff);
159 pad[padLen-2] = (byte) ((bitCount >> 8) & 0xff);
160 pad[padLen-1] = (byte) ((bitCount >> 0) & 0xff);
162 /* Digest padding */
163 _HashData(pad, 0, pad.Length);
165 /* Store digest */
166 Utils.DWORDToBigEndian (hash, _stateSHA256, 8);
168 HashValue = hash;
169 return hash;
172 private readonly static UInt32[] _K = {
173 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
174 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
175 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
176 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
177 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
178 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
179 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
180 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
181 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
182 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
183 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
184 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
185 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
186 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
187 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
188 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
191 [System.Security.SecurityCritical] // auto-generated
192 private static unsafe void SHATransform (uint* expandedBuffer, uint* state, byte* block)
194 UInt32 a, b, c, d, e, f, h, g;
195 UInt32 aa, bb, cc, dd, ee, ff, hh, gg;
196 UInt32 T1;
198 a = state[0];
199 b = state[1];
200 c = state[2];
201 d = state[3];
202 e = state[4];
203 f = state[5];
204 g = state[6];
205 h = state[7];
207 // fill in the first 16 bytes of W.
208 Utils.DWORDFromBigEndian(expandedBuffer, 16, block);
209 SHA256Expand(expandedBuffer);
211 /* Apply the SHA256 compression function */
212 // We are trying to be smart here and avoid as many copies as we can
213 // The perf gain with this method over the straightforward modify and shift
214 // forward is >= 20%, so it's worth the pain
215 for (int j=0; j<64; ) {
216 T1 = h + Sigma_1(e) + Ch(e,f,g) + _K[j] + expandedBuffer[j];
217 ee = d + T1;
218 aa = T1 + Sigma_0(a) + Maj(a,b,c);
219 j++;
221 T1 = g + Sigma_1(ee) + Ch(ee,e,f) + _K[j] + expandedBuffer[j];
222 ff = c + T1;
223 bb = T1 + Sigma_0(aa) + Maj(aa,a,b);
224 j++;
226 T1 = f + Sigma_1(ff) + Ch(ff,ee,e) + _K[j] + expandedBuffer[j];
227 gg = b + T1;
228 cc = T1 + Sigma_0(bb) + Maj(bb,aa,a);
229 j++;
231 T1 = e + Sigma_1(gg) + Ch(gg,ff,ee) + _K[j] + expandedBuffer[j];
232 hh = a + T1;
233 dd = T1 + Sigma_0(cc) + Maj(cc,bb,aa);
234 j++;
236 T1 = ee + Sigma_1(hh) + Ch(hh,gg,ff) + _K[j] + expandedBuffer[j];
237 h = aa + T1;
238 d = T1 + Sigma_0(dd) + Maj(dd,cc,bb);
239 j++;
241 T1 = ff + Sigma_1(h) + Ch(h,hh,gg) + _K[j] + expandedBuffer[j];
242 g = bb + T1;
243 c = T1 + Sigma_0(d) + Maj(d,dd,cc);
244 j++;
246 T1 = gg + Sigma_1(g) + Ch(g,h,hh) + _K[j] + expandedBuffer[j];
247 f = cc + T1;
248 b = T1 + Sigma_0(c) + Maj(c,d,dd);
249 j++;
251 T1 = hh + Sigma_1(f) + Ch(f,g,h) + _K[j] + expandedBuffer[j];
252 e = dd + T1;
253 a = T1 + Sigma_0(b) + Maj(b,c,d);
254 j++;
257 state[0] += a;
258 state[1] += b;
259 state[2] += c;
260 state[3] += d;
261 state[4] += e;
262 state[5] += f;
263 state[6] += g;
264 state[7] += h;
267 private static UInt32 RotateRight(UInt32 x, int n) {
268 return (((x) >> (n)) | ((x) << (32-(n))));
271 private static UInt32 Ch(UInt32 x, UInt32 y, UInt32 z) {
272 return ((x & y) ^ ((x ^ 0xffffffff) & z));
275 private static UInt32 Maj(UInt32 x, UInt32 y, UInt32 z) {
276 return ((x & y) ^ (x & z) ^ (y & z));
279 private static UInt32 sigma_0(UInt32 x) {
280 return (RotateRight(x,7) ^ RotateRight(x,18) ^ (x >> 3));
283 private static UInt32 sigma_1(UInt32 x) {
284 return (RotateRight(x,17) ^ RotateRight(x,19) ^ (x >> 10));
287 private static UInt32 Sigma_0(UInt32 x) {
288 return (RotateRight(x,2) ^ RotateRight(x,13) ^ RotateRight(x,22));
291 private static UInt32 Sigma_1(UInt32 x) {
292 return (RotateRight(x,6) ^ RotateRight(x,11) ^ RotateRight(x,25));
295 /* This function creates W_16,...,W_63 according to the formula
296 W_j <- sigma_1(W_{j-2}) + W_{j-7} + sigma_0(W_{j-15}) + W_{j-16};
299 [System.Security.SecurityCritical] // auto-generated
300 private static unsafe void SHA256Expand (uint* x)
302 for (int i = 16; i < 64; i++) {
303 x[i] = sigma_1(x[i-2]) + x[i-7] + sigma_0(x[i-15]) + x[i-16];