3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</OWNER>
12 // C# implementation of the proposed SHA-384 hash algorithm
15 namespace System.Security.Cryptography {
17 using System.Diagnostics.Contracts;
19 [System.Runtime.InteropServices.ComVisible(true)]
20 public class SHA384Managed : SHA384
22 private byte[] _buffer;
23 private ulong _count; // Number of bytes in the hashed message
24 private UInt64[] _stateSHA384;
28 // public constructors
31 public SHA384Managed()
33 if (CryptoConfig.AllowOnlyFipsAlgorithms)
34 throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NonCompliantFIPSAlgorithm"));
35 Contract.EndContractBlock();
37 _stateSHA384 = 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 _stateSHA384[0] = 0xcbbb9d5dc1059ed8;
74 _stateSHA384[1] = 0x629a292a367cd507;
75 _stateSHA384[2] = 0x9159015a3070dd17;
76 _stateSHA384[3] = 0x152fecd8f70e5939;
77 _stateSHA384[4] = 0x67332667ffc00b31;
78 _stateSHA384[5] = 0x8eb44a8768581511;
79 _stateSHA384[6] = 0xdb0c2e0d64f98fa7;
80 _stateSHA384[7] = 0x47b5481dbefa4fa4;
83 /* SHA384 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* stateSHA384 = _stateSHA384) {
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, stateSHA384, buffer);
112 /* Copy input to temporary buffer and hash */
113 while (partInLen >= 128) {
114 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, 0, 128);
117 SHATransform(expandedBuffer, stateSHA384, buffer);
121 Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen);
128 /* SHA384 finalization. Ends an SHA384 message-digest operation, writing
132 [System.Security.SecurityCritical] // auto-generated
133 private byte[] _EndHash()
138 byte[] hash = new byte[48]; // HashSizeValue = 384
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 // bitCount is at most 8 * 128 = 1024. Its representation as a 128-bit number has all bits set to zero
154 // except eventually the 11 lower bits
156 //pad[padLen-16] = (byte) ((bitCount >> 120) & 0xff);
157 //pad[padLen-15] = (byte) ((bitCount >> 112) & 0xff);
158 //pad[padLen-14] = (byte) ((bitCount >> 104) & 0xff);
159 //pad[padLen-13] = (byte) ((bitCount >> 96) & 0xff);
160 //pad[padLen-12] = (byte) ((bitCount >> 88) & 0xff);
161 //pad[padLen-11] = (byte) ((bitCount >> 80) & 0xff);
162 //pad[padLen-10] = (byte) ((bitCount >> 72) & 0xff);
163 //pad[padLen-9] = (byte) ((bitCount >> 64) & 0xff);
164 pad[padLen-8] = (byte) ((bitCount >> 56) & 0xff);
165 pad[padLen-7] = (byte) ((bitCount >> 48) & 0xff);
166 pad[padLen-6] = (byte) ((bitCount >> 40) & 0xff);
167 pad[padLen-5] = (byte) ((bitCount >> 32) & 0xff);
168 pad[padLen-4] = (byte) ((bitCount >> 24) & 0xff);
169 pad[padLen-3] = (byte) ((bitCount >> 16) & 0xff);
170 pad[padLen-2] = (byte) ((bitCount >> 8) & 0xff);
171 pad[padLen-1] = (byte) ((bitCount >> 0) & 0xff);
174 _HashData(pad, 0, pad.Length);
177 Utils.QuadWordToBigEndian (hash, _stateSHA384, 6);
183 private readonly static UInt64[] _K = {
184 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
185 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
186 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
187 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
188 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
189 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
190 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
191 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
192 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
193 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
194 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
195 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
196 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
197 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
198 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
199 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
200 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
201 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
202 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
203 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
206 [System.Security.SecurityCritical] // auto-generated
207 private static unsafe void SHATransform (UInt64* expandedBuffer, UInt64* state, byte* block)
209 UInt64 a, b, c, d, e, f, g, h;
210 UInt64 aa, bb, cc, dd, ee, ff, hh, gg;
222 // fill in the first 16 blocks of W.
223 Utils.QuadWordFromBigEndian (expandedBuffer, 16, block);
224 SHA384Expand (expandedBuffer);
226 /* Apply the SHA384 compression function */
227 // We are trying to be smart here and avoid as many copies as we can
228 // The perf gain with this method over the straightforward modify and shift
229 // forward is >= 20%, so it's worth the pain
230 for (int j=0; j<80; ) {
231 T1 = h + Sigma_1(e) + Ch(e,f,g) + _K[j] + expandedBuffer[j];
233 aa = T1 + Sigma_0(a) + Maj(a,b,c);
236 T1 = g + Sigma_1(ee) + Ch(ee,e,f) + _K[j] + expandedBuffer[j];
238 bb = T1 + Sigma_0(aa) + Maj(aa,a,b);
241 T1 = f + Sigma_1(ff) + Ch(ff,ee,e) + _K[j] + expandedBuffer[j];
243 cc = T1 + Sigma_0(bb) + Maj(bb,aa,a);
246 T1 = e + Sigma_1(gg) + Ch(gg,ff,ee) + _K[j] + expandedBuffer[j];
248 dd = T1 + Sigma_0(cc) + Maj(cc,bb,aa);
251 T1 = ee + Sigma_1(hh) + Ch(hh,gg,ff) + _K[j] + expandedBuffer[j];
253 d = T1 + Sigma_0(dd) + Maj(dd,cc,bb);
256 T1 = ff + Sigma_1(h) + Ch(h,hh,gg) + _K[j] + expandedBuffer[j];
258 c = T1 + Sigma_0(d) + Maj(d,dd,cc);
261 T1 = gg + Sigma_1(g) + Ch(g,h,hh) + _K[j] + expandedBuffer[j];
263 b = T1 + Sigma_0(c) + Maj(c,d,dd);
266 T1 = hh + Sigma_1(f) + Ch(f,g,h) + _K[j] + expandedBuffer[j];
268 a = T1 + Sigma_0(b) + Maj(b,c,d);
282 private static UInt64 RotateRight(UInt64 x, int n) {
283 return (((x) >> (n)) | ((x) << (64-(n))));
286 private static UInt64 Ch(UInt64 x, UInt64 y, UInt64 z) {
287 return ((x & y) ^ ((x ^ 0xffffffffffffffff) & z));
290 private static UInt64 Maj(UInt64 x, UInt64 y, UInt64 z) {
291 return ((x & y) ^ (x & z) ^ (y & z));
294 private static UInt64 Sigma_0(UInt64 x) {
295 return (RotateRight(x,28) ^ RotateRight(x,34) ^ RotateRight(x,39));
298 private static UInt64 Sigma_1(UInt64 x) {
299 return (RotateRight(x,14) ^ RotateRight(x,18) ^ RotateRight(x,41));
302 private static UInt64 sigma_0(UInt64 x) {
303 return (RotateRight(x,1) ^ RotateRight(x,8) ^ (x >> 7));
306 private static UInt64 sigma_1(UInt64 x) {
307 return (RotateRight(x,19) ^ RotateRight(x,61) ^ (x >> 6));
310 /* This function creates W_16,...,W_79 according to the formula
311 W_j <- sigma_1(W_{j-2}) + W_{j-7} + sigma_0(W_{j-15}) + W_{j-16};
314 [System.Security.SecurityCritical] // auto-generated
315 private static unsafe void SHA384Expand (UInt64* x)
317 for (int i = 16; i < 80; i++) {
318 x[i] = sigma_1(x[i-2]) + x[i-7] + sigma_0(x[i-15]) + x[i-16];