3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
12 // C# implementation of the proposed SHA-256 hash algorithm
15 namespace System.Security.Cryptography {
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;
29 // public constructors
32 public SHA256Managed()
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];
51 public override void Initialize() {
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() {
71 private void InitializeState() {
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
89 [System.Security.SecuritySafeCritical] // auto-generated
90 private unsafe void _HashData(byte[] partIn, int ibStart, int cbSize)
93 int partInLen = cbSize;
94 int partInBase = ibStart;
96 /* Compute length of buffer */
97 bufferLen = (int) (_count & 0x3f);
99 /* Update number of bytes */
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);
113 /* Copy input to temporary buffer and hash */
114 while (partInLen >= 64) {
115 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, 0, 64);
118 SHATransform(expandedBuffer, stateSHA256, buffer);
122 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen);
129 /* SHA256 finalization. Ends an SHA256 message-digest operation, writing
133 private byte[] _EndHash()
138 byte[] hash = new byte[32]; // HashSizeValue = 256
140 /* Compute padding: 80 00 00 ... 00 00 <bit count>
143 padLen = 64 - (int)(_count & 0x3f);
147 pad = new byte[padLen];
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);
163 _HashData(pad, 0, pad.Length);
166 Utils.DWORDToBigEndian (hash, _stateSHA256, 8);
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;
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];
218 aa = T1 + Sigma_0(a) + Maj(a,b,c);
221 T1 = g + Sigma_1(ee) + Ch(ee,e,f) + _K[j] + expandedBuffer[j];
223 bb = T1 + Sigma_0(aa) + Maj(aa,a,b);
226 T1 = f + Sigma_1(ff) + Ch(ff,ee,e) + _K[j] + expandedBuffer[j];
228 cc = T1 + Sigma_0(bb) + Maj(bb,aa,a);
231 T1 = e + Sigma_1(gg) + Ch(gg,ff,ee) + _K[j] + expandedBuffer[j];
233 dd = T1 + Sigma_0(cc) + Maj(cc,bb,aa);
236 T1 = ee + Sigma_1(hh) + Ch(hh,gg,ff) + _K[j] + expandedBuffer[j];
238 d = T1 + Sigma_0(dd) + Maj(dd,cc,bb);
241 T1 = ff + Sigma_1(h) + Ch(h,hh,gg) + _K[j] + expandedBuffer[j];
243 c = T1 + Sigma_0(d) + Maj(d,dd,cc);
246 T1 = gg + Sigma_1(g) + Ch(g,h,hh) + _K[j] + expandedBuffer[j];
248 b = T1 + Sigma_0(c) + Maj(c,d,dd);
251 T1 = hh + Sigma_1(f) + Ch(f,g,h) + _K[j] + expandedBuffer[j];
253 a = T1 + Sigma_0(b) + Maj(b,c,d);
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];