3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</OWNER>
12 // C# implementation of the proposed SHA-512 hash algorithm
15 namespace System.Security.Cryptography {
17 using System.Diagnostics.Contracts;
19 [System.Runtime.InteropServices.ComVisible(true)]
20 public class SHA512Managed : SHA512
22 private byte[] _buffer;
23 private ulong _count; // Number of bytes in the hashed message
24 private UInt64[] _stateSHA512;
28 // public constructors
31 public SHA512Managed()
33 if (CryptoConfig.AllowOnlyFipsAlgorithms)
34 throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NonCompliantFIPSAlgorithm"));
35 Contract.EndContractBlock();
37 _stateSHA512 = new UInt64[8];
38 _buffer = new byte[128];
48 public override void Initialize() {
51 // Zeroize potentially sensitive information.
52 Array.Clear(_buffer, 0, _buffer.Length);
53 Array.Clear(_W, 0, _W.Length);
56 [System.Security.SecuritySafeCritical] // auto-generated
57 protected override void HashCore(byte[] rgb, int ibStart, int cbSize) {
58 _HashData(rgb, ibStart, cbSize);
61 [System.Security.SecuritySafeCritical] // auto-generated
62 protected override byte[] HashFinal() {
70 private void InitializeState() {
73 _stateSHA512[0] = 0x6a09e667f3bcc908;
74 _stateSHA512[1] = 0xbb67ae8584caa73b;
75 _stateSHA512[2] = 0x3c6ef372fe94f82b;
76 _stateSHA512[3] = 0xa54ff53a5f1d36f1;
77 _stateSHA512[4] = 0x510e527fade682d1;
78 _stateSHA512[5] = 0x9b05688c2b3e6c1f;
79 _stateSHA512[6] = 0x1f83d9abfb41bd6b;
80 _stateSHA512[7] = 0x5be0cd19137e2179;
83 /* SHA512 block update operation. Continues an SHA message-digest
84 operation, processing another message block, and updating the
88 [System.Security.SecurityCritical] // auto-generated
89 private unsafe void _HashData(byte[] partIn, int ibStart, int cbSize)
92 int partInLen = cbSize;
93 int partInBase = ibStart;
95 /* Compute length of buffer */
96 bufferLen = (int) (_count & 0x7f);
98 /* Update number of bytes */
99 _count += (ulong) partInLen;
101 fixed (UInt64* stateSHA512 = _stateSHA512) {
102 fixed (byte* buffer = _buffer) {
103 fixed (UInt64* expandedBuffer = _W) {
104 if ((bufferLen > 0) && (bufferLen + partInLen >= 128)) {
105 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, 128 - bufferLen);
106 partInBase += (128 - bufferLen);
107 partInLen -= (128 - bufferLen);
108 SHATransform(expandedBuffer, stateSHA512, buffer);
112 /* Copy input to temporary buffer and hash */
113 while (partInLen >= 128) {
114 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, 0, 128);
117 SHATransform(expandedBuffer, stateSHA512, buffer);
121 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen);
128 /* SHA512 finalization. Ends an SHA512 message-digest operation, writing
132 [System.Security.SecurityCritical] // auto-generated
133 private byte[] _EndHash()
138 byte[] hash = new byte[64]; // HashSizeValue = 512
140 /* Compute padding: 80 00 00 ... 00 00 <bit count>
143 padLen = 128 - (int)(_count & 0x7f);
147 pad = new byte[padLen];
150 // Convert count to bit count
151 bitCount = _count * 8;
153 // If we ever have UInt128 for bitCount, then these need to be uncommented.
154 // Note that C# only looks at the low 6 bits of the shift value for ulongs,
155 // so >>0 and >>64 are equal!
157 //pad[padLen-16] = (byte) ((bitCount >> 120) & 0xff);
158 //pad[padLen-15] = (byte) ((bitCount >> 112) & 0xff);
159 //pad[padLen-14] = (byte) ((bitCount >> 104) & 0xff);
160 //pad[padLen-13] = (byte) ((bitCount >> 96) & 0xff);
161 //pad[padLen-12] = (byte) ((bitCount >> 88) & 0xff);
162 //pad[padLen-11] = (byte) ((bitCount >> 80) & 0xff);
163 //pad[padLen-10] = (byte) ((bitCount >> 72) & 0xff);
164 //pad[padLen-9] = (byte) ((bitCount >> 64) & 0xff);
165 pad[padLen-8] = (byte) ((bitCount >> 56) & 0xff);
166 pad[padLen-7] = (byte) ((bitCount >> 48) & 0xff);
167 pad[padLen-6] = (byte) ((bitCount >> 40) & 0xff);
168 pad[padLen-5] = (byte) ((bitCount >> 32) & 0xff);
169 pad[padLen-4] = (byte) ((bitCount >> 24) & 0xff);
170 pad[padLen-3] = (byte) ((bitCount >> 16) & 0xff);
171 pad[padLen-2] = (byte) ((bitCount >> 8) & 0xff);
172 pad[padLen-1] = (byte) ((bitCount >> 0) & 0xff);
175 _HashData(pad, 0, pad.Length);
178 Utils.QuadWordToBigEndian (hash, _stateSHA512, 8);
184 private readonly static UInt64[] _K = {
185 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
186 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
187 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
188 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
189 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
190 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
191 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
192 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
193 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
194 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
195 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
196 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
197 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
198 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
199 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
200 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
201 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
202 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
203 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
204 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
207 [System.Security.SecurityCritical] // auto-generated
208 private static unsafe void SHATransform (UInt64* expandedBuffer, UInt64* state, byte* block)
210 UInt64 a, b, c, d, e, f, g, h;
211 UInt64 aa, bb, cc, dd, ee, ff, hh, gg;
223 // fill in the first 16 blocks of W.
224 Utils.QuadWordFromBigEndian (expandedBuffer, 16, block);
225 SHA512Expand (expandedBuffer);
227 /* Apply the SHA512 compression function */
228 // We are trying to be smart here and avoid as many copies as we can
229 // The perf gain with this method over the straightforward modify and shift
230 // forward is >= 20%, so it's worth the pain
231 for (int j=0; j<80; ) {
232 T1 = h + Sigma_1(e) + Ch(e,f,g) + _K[j] + expandedBuffer[j];
234 aa = T1 + Sigma_0(a) + Maj(a,b,c);
237 T1 = g + Sigma_1(ee) + Ch(ee,e,f) + _K[j] + expandedBuffer[j];
239 bb = T1 + Sigma_0(aa) + Maj(aa,a,b);
242 T1 = f + Sigma_1(ff) + Ch(ff,ee,e) + _K[j] + expandedBuffer[j];
244 cc = T1 + Sigma_0(bb) + Maj(bb,aa,a);
247 T1 = e + Sigma_1(gg) + Ch(gg,ff,ee) + _K[j] + expandedBuffer[j];
249 dd = T1 + Sigma_0(cc) + Maj(cc,bb,aa);
252 T1 = ee + Sigma_1(hh) + Ch(hh,gg,ff) + _K[j] + expandedBuffer[j];
254 d = T1 + Sigma_0(dd) + Maj(dd,cc,bb);
257 T1 = ff + Sigma_1(h) + Ch(h,hh,gg) + _K[j] + expandedBuffer[j];
259 c = T1 + Sigma_0(d) + Maj(d,dd,cc);
262 T1 = gg + Sigma_1(g) + Ch(g,h,hh) + _K[j] + expandedBuffer[j];
264 b = T1 + Sigma_0(c) + Maj(c,d,dd);
267 T1 = hh + Sigma_1(f) + Ch(f,g,h) + _K[j] + expandedBuffer[j];
269 a = T1 + Sigma_0(b) + Maj(b,c,d);
283 private static UInt64 RotateRight(UInt64 x, int n) {
284 return (((x) >> (n)) | ((x) << (64-(n))));
287 private static UInt64 Ch(UInt64 x, UInt64 y, UInt64 z) {
288 return ((x & y) ^ ((x ^ 0xffffffffffffffff) & z));
291 private static UInt64 Maj(UInt64 x, UInt64 y, UInt64 z) {
292 return ((x & y) ^ (x & z) ^ (y & z));
295 private static UInt64 Sigma_0(UInt64 x) {
296 return (RotateRight(x,28) ^ RotateRight(x,34) ^ RotateRight(x,39));
299 private static UInt64 Sigma_1(UInt64 x) {
300 return (RotateRight(x,14) ^ RotateRight(x,18) ^ RotateRight(x,41));
303 private static UInt64 sigma_0(UInt64 x) {
304 return (RotateRight(x,1) ^ RotateRight(x,8) ^ (x >> 7));
307 private static UInt64 sigma_1(UInt64 x) {
308 return (RotateRight(x,19) ^ RotateRight(x,61) ^ (x >> 6));
311 /* This function creates W_16,...,W_79 according to the formula
312 W_j <- sigma_1(W_{j-2}) + W_{j-7} + sigma_0(W_{j-15}) + W_{j-16};
315 [System.Security.SecurityCritical] // auto-generated
316 private static unsafe void SHA512Expand (UInt64* x)
318 for (int i = 16; i < 80; i++) {
319 x[i] = sigma_1(x[i-2]) + x[i-7] + sigma_0(x[i-15]) + x[i-16];