|
| 1 | +From eadad2b4d7d2ef556a2329dd955a2e7f04f56db6 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Levi Broderick < [email protected]> |
| 3 | +Date: Fri, 20 Nov 2020 07:38:00 -0800 |
| 4 | +Subject: [PATCH] Use substitute SHA-1 implementation in wasm (#44982) |
| 5 | + |
| 6 | +* Use different managed SHA-1 implementation |
| 7 | + |
| 8 | +* Add missing call to Start |
| 9 | +--- |
| 10 | + .../Cryptography/SHAHashProvider.Browser.cs | 328 ++++++++---------- |
| 11 | + 1 file changed, 151 insertions(+), 177 deletions(-) |
| 12 | + |
| 13 | +diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs |
| 14 | +index 9fd4ab1a476..4515b8ae75c 100644 |
| 15 | +--- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs |
| 16 | ++++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs |
| 17 | +@@ -4,6 +4,7 @@ |
| 18 | + using System; |
| 19 | + using System.IO; |
| 20 | + using System.Diagnostics; |
| 21 | ++using System.Numerics; |
| 22 | + using System.Security.Cryptography; |
| 23 | + |
| 24 | + namespace Internal.Cryptography |
| 25 | +@@ -84,213 +85,186 @@ private abstract class SHAManagedImplementationBase |
| 26 | + public abstract byte[] HashFinal(); |
| 27 | + } |
| 28 | + |
| 29 | +- // ported from https://github.com/microsoft/referencesource/blob/a48449cb48a9a693903668a71449ac719b76867c/mscorlib/system/security/cryptography/sha1managed.cs |
| 30 | ++ // Ported from src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs. |
| 31 | ++ // n.b. It's ok to use a "non-secret purposes" hashing implementation here, as this is only |
| 32 | ++ // used in wasm scenarios, and as of the current release we don't make any security guarantees |
| 33 | ++ // about our crypto primitives in wasm environments. |
| 34 | + private class SHA1ManagedImplementation : SHAManagedImplementationBase |
| 35 | + { |
| 36 | +- private byte[] _buffer; |
| 37 | +- private long _count; // Number of bytes in the hashed message |
| 38 | +- private uint[] _stateSHA1; |
| 39 | +- private uint[] _expandedBuffer; |
| 40 | ++ private Sha1ForNonSecretPurposes _state; // mutable struct - don't make readonly |
| 41 | + |
| 42 | +- public SHA1ManagedImplementation() |
| 43 | ++ public override void Initialize() |
| 44 | + { |
| 45 | +- _stateSHA1 = new uint[5]; |
| 46 | +- _buffer = new byte[64]; |
| 47 | +- _expandedBuffer = new uint[80]; |
| 48 | +- |
| 49 | +- InitializeState(); |
| 50 | ++ _state = default; |
| 51 | ++ _state.Start(); |
| 52 | + } |
| 53 | + |
| 54 | +- public override void Initialize() |
| 55 | ++ public override void HashCore(byte[] partIn, int ibStart, int cbSize) |
| 56 | + { |
| 57 | +- InitializeState(); |
| 58 | +- |
| 59 | +- // Zeroize potentially sensitive information. |
| 60 | +- Array.Clear(_buffer, 0, _buffer.Length); |
| 61 | +- Array.Clear(_expandedBuffer, 0, _expandedBuffer.Length); |
| 62 | ++ _state.Append(partIn.AsSpan(ibStart, cbSize)); |
| 63 | + } |
| 64 | + |
| 65 | +- private void InitializeState() |
| 66 | ++ public override byte[] HashFinal() |
| 67 | + { |
| 68 | +- _count = 0; |
| 69 | +- |
| 70 | +- _stateSHA1[0] = 0x67452301; |
| 71 | +- _stateSHA1[1] = 0xefcdab89; |
| 72 | +- _stateSHA1[2] = 0x98badcfe; |
| 73 | +- _stateSHA1[3] = 0x10325476; |
| 74 | +- _stateSHA1[4] = 0xc3d2e1f0; |
| 75 | ++ byte[] output = new byte[20]; |
| 76 | ++ _state.Finish(output); |
| 77 | ++ return output; |
| 78 | + } |
| 79 | + |
| 80 | +- /* Copyright (C) RSA Data Security, Inc. created 1993. This is an |
| 81 | +- unpublished work protected as such under copyright law. This work |
| 82 | +- contains proprietary, confidential, and trade secret information of |
| 83 | +- RSA Data Security, Inc. Use, disclosure or reproduction without the |
| 84 | +- express written authorization of RSA Data Security, Inc. is |
| 85 | +- prohibited. |
| 86 | +- */ |
| 87 | +- |
| 88 | +- /* SHA block update operation. Continues an SHA message-digest |
| 89 | +- operation, processing another message block, and updating the |
| 90 | +- context. |
| 91 | +- */ |
| 92 | +- public override unsafe void HashCore(byte[] partIn, int ibStart, int cbSize) |
| 93 | ++ /// <summary> |
| 94 | ++ /// Implements the SHA1 hashing algorithm. Note that this |
| 95 | ++ /// implementation is for hashing public information. Do not |
| 96 | ++ /// use this code to hash private data, as this implementation does |
| 97 | ++ /// not take any steps to avoid information disclosure. |
| 98 | ++ /// </summary> |
| 99 | ++ private struct Sha1ForNonSecretPurposes |
| 100 | + { |
| 101 | +- int bufferLen; |
| 102 | +- int partInLen = cbSize; |
| 103 | +- int partInBase = ibStart; |
| 104 | +- |
| 105 | +- /* Compute length of buffer */ |
| 106 | +- bufferLen = (int)(_count & 0x3f); |
| 107 | +- |
| 108 | +- /* Update number of bytes */ |
| 109 | +- _count += partInLen; |
| 110 | ++ private long length; // Total message length in bits |
| 111 | ++ private uint[] w; // Workspace |
| 112 | ++ private int pos; // Length of current chunk in bytes |
| 113 | ++ |
| 114 | ++ /// <summary> |
| 115 | ++ /// Call Start() to initialize the hash object. |
| 116 | ++ /// </summary> |
| 117 | ++ public void Start() |
| 118 | ++ { |
| 119 | ++ this.w ??= new uint[85]; |
| 120 | ++ |
| 121 | ++ this.length = 0; |
| 122 | ++ this.pos = 0; |
| 123 | ++ this.w[80] = 0x67452301; |
| 124 | ++ this.w[81] = 0xEFCDAB89; |
| 125 | ++ this.w[82] = 0x98BADCFE; |
| 126 | ++ this.w[83] = 0x10325476; |
| 127 | ++ this.w[84] = 0xC3D2E1F0; |
| 128 | ++ } |
| 129 | + |
| 130 | +- fixed (uint* stateSHA1 = _stateSHA1) |
| 131 | ++ /// <summary> |
| 132 | ++ /// Adds an input byte to the hash. |
| 133 | ++ /// </summary> |
| 134 | ++ /// <param name="input">Data to include in the hash.</param> |
| 135 | ++ public void Append(byte input) |
| 136 | + { |
| 137 | +- fixed (byte* buffer = _buffer) |
| 138 | ++ this.w[this.pos / 4] = (this.w[this.pos / 4] << 8) | input; |
| 139 | ++ if (64 == ++this.pos) |
| 140 | + { |
| 141 | +- fixed (uint* expandedBuffer = _expandedBuffer) |
| 142 | +- { |
| 143 | +- if ((bufferLen > 0) && (bufferLen + partInLen >= 64)) |
| 144 | +- { |
| 145 | +- Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, 64 - bufferLen); |
| 146 | +- partInBase += (64 - bufferLen); |
| 147 | +- partInLen -= (64 - bufferLen); |
| 148 | +- SHATransform(expandedBuffer, stateSHA1, buffer); |
| 149 | +- bufferLen = 0; |
| 150 | +- } |
| 151 | +- |
| 152 | +- /* Copy input to temporary buffer and hash */ |
| 153 | +- while (partInLen >= 64) |
| 154 | +- { |
| 155 | +- Buffer.BlockCopy(partIn, partInBase, _buffer, 0, 64); |
| 156 | +- partInBase += 64; |
| 157 | +- partInLen -= 64; |
| 158 | +- SHATransform(expandedBuffer, stateSHA1, buffer); |
| 159 | +- } |
| 160 | +- |
| 161 | +- if (partInLen > 0) |
| 162 | +- { |
| 163 | +- Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen); |
| 164 | +- } |
| 165 | +- } |
| 166 | ++ this.Drain(); |
| 167 | + } |
| 168 | + } |
| 169 | +- } |
| 170 | + |
| 171 | +- /* SHA finalization. Ends an SHA message-digest operation, writing |
| 172 | +- the message digest. |
| 173 | +- */ |
| 174 | +- public override byte[] HashFinal() |
| 175 | +- { |
| 176 | +- byte[] pad; |
| 177 | +- int padLen; |
| 178 | +- long bitCount; |
| 179 | +- byte[] hash = new byte[20]; |
| 180 | +- |
| 181 | +- /* Compute padding: 80 00 00 ... 00 00 <bit count> |
| 182 | +- */ |
| 183 | +- |
| 184 | +- padLen = 64 - (int)(_count & 0x3f); |
| 185 | +- if (padLen <= 8) |
| 186 | +- padLen += 64; |
| 187 | +- |
| 188 | +- pad = new byte[padLen]; |
| 189 | +- pad[0] = 0x80; |
| 190 | +- |
| 191 | +- // Convert count to bit count |
| 192 | +- bitCount = _count * 8; |
| 193 | +- |
| 194 | +- pad[padLen - 8] = (byte)((bitCount >> 56) & 0xff); |
| 195 | +- pad[padLen - 7] = (byte)((bitCount >> 48) & 0xff); |
| 196 | +- pad[padLen - 6] = (byte)((bitCount >> 40) & 0xff); |
| 197 | +- pad[padLen - 5] = (byte)((bitCount >> 32) & 0xff); |
| 198 | +- pad[padLen - 4] = (byte)((bitCount >> 24) & 0xff); |
| 199 | +- pad[padLen - 3] = (byte)((bitCount >> 16) & 0xff); |
| 200 | +- pad[padLen - 2] = (byte)((bitCount >> 8) & 0xff); |
| 201 | +- pad[padLen - 1] = (byte)((bitCount >> 0) & 0xff); |
| 202 | +- |
| 203 | +- /* Digest padding */ |
| 204 | +- HashCore(pad, 0, pad.Length); |
| 205 | +- |
| 206 | +- /* Store digest */ |
| 207 | +- SHAUtils.DWORDToBigEndian(hash, _stateSHA1, 5); |
| 208 | +- |
| 209 | +- return hash; |
| 210 | +- } |
| 211 | +- |
| 212 | +- private unsafe void SHATransform(uint* expandedBuffer, uint* state, byte* block) |
| 213 | +- { |
| 214 | +- uint a = state[0]; |
| 215 | +- uint b = state[1]; |
| 216 | +- uint c = state[2]; |
| 217 | +- uint d = state[3]; |
| 218 | +- uint e = state[4]; |
| 219 | +- |
| 220 | +- int i; |
| 221 | +- |
| 222 | +- SHAUtils.DWORDFromBigEndian(expandedBuffer, 16, block); |
| 223 | +- SHAExpand(expandedBuffer); |
| 224 | +- |
| 225 | +- /* Round 1 */ |
| 226 | +- for (i = 0; i < 20; i += 5) |
| 227 | ++ /// <summary> |
| 228 | ++ /// Adds input bytes to the hash. |
| 229 | ++ /// </summary> |
| 230 | ++ /// <param name="input"> |
| 231 | ++ /// Data to include in the hash. Must not be null. |
| 232 | ++ /// </param> |
| 233 | ++ public void Append(ReadOnlySpan<byte> input) |
| 234 | + { |
| 235 | +- { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + ((d) ^ ((b) & ((c) ^ (d)))) + (expandedBuffer[i]) + 0x5a827999); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); } |
| 236 | +- { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + ((c) ^ ((a) & ((b) ^ (c)))) + (expandedBuffer[i + 1]) + 0x5a827999); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); } |
| 237 | +- { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + ((b) ^ ((e) & ((a) ^ (b)))) + (expandedBuffer[i + 2]) + 0x5a827999); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; |
| 238 | +- { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + ((a) ^ ((d) & ((e) ^ (a)))) + (expandedBuffer[i + 3]) + 0x5a827999); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; |
| 239 | +- { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + ((e) ^ ((c) & ((d) ^ (e)))) + (expandedBuffer[i + 4]) + 0x5a827999); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; |
| 240 | ++ foreach (byte b in input) |
| 241 | ++ { |
| 242 | ++ this.Append(b); |
| 243 | ++ } |
| 244 | + } |
| 245 | + |
| 246 | +- /* Round 2 */ |
| 247 | +- for (; i < 40; i += 5) |
| 248 | ++ /// <summary> |
| 249 | ++ /// Retrieves the hash value. |
| 250 | ++ /// Note that after calling this function, the hash object should |
| 251 | ++ /// be considered uninitialized. Subsequent calls to Append or |
| 252 | ++ /// Finish will produce useless results. Call Start() to |
| 253 | ++ /// reinitialize. |
| 254 | ++ /// </summary> |
| 255 | ++ /// <param name="output"> |
| 256 | ++ /// Buffer to receive the hash value. Must not be null. |
| 257 | ++ /// Up to 20 bytes of hash will be written to the output buffer. |
| 258 | ++ /// If the buffer is smaller than 20 bytes, the remaining hash |
| 259 | ++ /// bytes will be lost. If the buffer is larger than 20 bytes, the |
| 260 | ++ /// rest of the buffer is left unmodified. |
| 261 | ++ /// </param> |
| 262 | ++ public void Finish(byte[] output) |
| 263 | + { |
| 264 | +- { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + ((b) ^ (c) ^ (d)) + (expandedBuffer[i]) + 0x6ed9eba1); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); }; ; |
| 265 | +- { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + ((a) ^ (b) ^ (c)) + (expandedBuffer[i + 1]) + 0x6ed9eba1); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); }; ; |
| 266 | +- { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + ((e) ^ (a) ^ (b)) + (expandedBuffer[i + 2]) + 0x6ed9eba1); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; |
| 267 | +- { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + ((d) ^ (e) ^ (a)) + (expandedBuffer[i + 3]) + 0x6ed9eba1); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; |
| 268 | +- { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + ((c) ^ (d) ^ (e)) + (expandedBuffer[i + 4]) + 0x6ed9eba1); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; |
| 269 | +- } |
| 270 | ++ long l = this.length + 8 * this.pos; |
| 271 | ++ this.Append(0x80); |
| 272 | ++ while (this.pos != 56) |
| 273 | ++ { |
| 274 | ++ this.Append(0x00); |
| 275 | ++ } |
| 276 | + |
| 277 | +- /* Round 3 */ |
| 278 | +- for (; i < 60; i += 5) |
| 279 | +- { |
| 280 | +- { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + (((b) & (c)) | ((d) & ((b) | (c)))) + (expandedBuffer[i]) + 0x8f1bbcdc); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); }; ; |
| 281 | +- { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + (((a) & (b)) | ((c) & ((a) | (b)))) + (expandedBuffer[i + 1]) + 0x8f1bbcdc); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); }; ; |
| 282 | +- { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + (((e) & (a)) | ((b) & ((e) | (a)))) + (expandedBuffer[i + 2]) + 0x8f1bbcdc); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; |
| 283 | +- { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + (((d) & (e)) | ((a) & ((d) | (e)))) + (expandedBuffer[i + 3]) + 0x8f1bbcdc); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; |
| 284 | +- { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + (((c) & (d)) | ((e) & ((c) | (d)))) + (expandedBuffer[i + 4]) + 0x8f1bbcdc); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; |
| 285 | ++ unchecked |
| 286 | ++ { |
| 287 | ++ this.Append((byte)(l >> 56)); |
| 288 | ++ this.Append((byte)(l >> 48)); |
| 289 | ++ this.Append((byte)(l >> 40)); |
| 290 | ++ this.Append((byte)(l >> 32)); |
| 291 | ++ this.Append((byte)(l >> 24)); |
| 292 | ++ this.Append((byte)(l >> 16)); |
| 293 | ++ this.Append((byte)(l >> 8)); |
| 294 | ++ this.Append((byte)l); |
| 295 | ++ |
| 296 | ++ int end = output.Length < 20 ? output.Length : 20; |
| 297 | ++ for (int i = 0; i != end; i++) |
| 298 | ++ { |
| 299 | ++ uint temp = this.w[80 + i / 4]; |
| 300 | ++ output[i] = (byte)(temp >> 24); |
| 301 | ++ this.w[80 + i / 4] = temp << 8; |
| 302 | ++ } |
| 303 | ++ } |
| 304 | + } |
| 305 | + |
| 306 | +- /* Round 4 */ |
| 307 | +- for (; i < 80; i += 5) |
| 308 | ++ /// <summary> |
| 309 | ++ /// Called when this.pos reaches 64. |
| 310 | ++ /// </summary> |
| 311 | ++ private void Drain() |
| 312 | + { |
| 313 | +- { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + ((b) ^ (c) ^ (d)) + (expandedBuffer[i]) + 0xca62c1d6); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); }; ; |
| 314 | +- { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + ((a) ^ (b) ^ (c)) + (expandedBuffer[i + 1]) + 0xca62c1d6); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); }; ; |
| 315 | +- { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + ((e) ^ (a) ^ (b)) + (expandedBuffer[i + 2]) + 0xca62c1d6); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; |
| 316 | +- { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + ((d) ^ (e) ^ (a)) + (expandedBuffer[i + 3]) + 0xca62c1d6); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; |
| 317 | +- { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + ((c) ^ (d) ^ (e)) + (expandedBuffer[i + 4]) + 0xca62c1d6); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; |
| 318 | +- } |
| 319 | ++ for (int i = 16; i != 80; i++) |
| 320 | ++ { |
| 321 | ++ this.w[i] = BitOperations.RotateLeft(this.w[i - 3] ^ this.w[i - 8] ^ this.w[i - 14] ^ this.w[i - 16], 1); |
| 322 | ++ } |
| 323 | + |
| 324 | +- state[0] += a; |
| 325 | +- state[1] += b; |
| 326 | +- state[2] += c; |
| 327 | +- state[3] += d; |
| 328 | +- state[4] += e; |
| 329 | +- } |
| 330 | ++ unchecked |
| 331 | ++ { |
| 332 | ++ uint a = this.w[80]; |
| 333 | ++ uint b = this.w[81]; |
| 334 | ++ uint c = this.w[82]; |
| 335 | ++ uint d = this.w[83]; |
| 336 | ++ uint e = this.w[84]; |
| 337 | + |
| 338 | +- /* Expands x[0..15] into x[16..79], according to the recurrence |
| 339 | +- x[i] = x[i-3] ^ x[i-8] ^ x[i-14] ^ x[i-16]. |
| 340 | +- */ |
| 341 | +- private unsafe void SHAExpand(uint* x) |
| 342 | +- { |
| 343 | +- int i; |
| 344 | +- uint tmp; |
| 345 | ++ for (int i = 0; i != 20; i++) |
| 346 | ++ { |
| 347 | ++ const uint k = 0x5A827999; |
| 348 | ++ uint f = (b & c) | ((~b) & d); |
| 349 | ++ uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; |
| 350 | ++ } |
| 351 | + |
| 352 | +- for (i = 16; i < 80; i++) |
| 353 | +- { |
| 354 | +- tmp = (x[i - 3] ^ x[i - 8] ^ x[i - 14] ^ x[i - 16]); |
| 355 | +- x[i] = ((tmp << 1) | (tmp >> 31)); |
| 356 | ++ for (int i = 20; i != 40; i++) |
| 357 | ++ { |
| 358 | ++ uint f = b ^ c ^ d; |
| 359 | ++ const uint k = 0x6ED9EBA1; |
| 360 | ++ uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; |
| 361 | ++ } |
| 362 | ++ |
| 363 | ++ for (int i = 40; i != 60; i++) |
| 364 | ++ { |
| 365 | ++ uint f = (b & c) | (b & d) | (c & d); |
| 366 | ++ const uint k = 0x8F1BBCDC; |
| 367 | ++ uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; |
| 368 | ++ } |
| 369 | ++ |
| 370 | ++ for (int i = 60; i != 80; i++) |
| 371 | ++ { |
| 372 | ++ uint f = b ^ c ^ d; |
| 373 | ++ const uint k = 0xCA62C1D6; |
| 374 | ++ uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; |
| 375 | ++ } |
| 376 | ++ |
| 377 | ++ this.w[80] += a; |
| 378 | ++ this.w[81] += b; |
| 379 | ++ this.w[82] += c; |
| 380 | ++ this.w[83] += d; |
| 381 | ++ this.w[84] += e; |
| 382 | ++ } |
| 383 | ++ |
| 384 | ++ this.length += 512; // 64 bytes == 512 bits |
| 385 | ++ this.pos = 0; |
| 386 | + } |
| 387 | + } |
| 388 | + } |
| 389 | +-- |
| 390 | +2.25.2 |
| 391 | + |
0 commit comments