/// <summary> /// Duplicates Python hash library pbkdf2_hmac for hash_name = 'sha512' and dklen = None /// /// Performance can be improved by pre-computing _trans_36 and _trans_5c. /// Unlike Python's hash functions, .NET doesn't currently support copying state between blocks. /// This results in having to recompute hash of innerSeed and outerSeed on each iteration. /// </summary> /// <param name="password"></param> /// <param name="salt"></param> /// <param name="iterations"></param> /// <returns></returns> public static UInt512 PbKdf2HmacSha512(ReadOnlyByteSpan password, ReadOnlyByteSpan salt, int iterations) { if (iterations < 1) { throw new ArgumentException(); } byte[] passwordBytes = password; using var inner = new SHA512Managed(); using var outer = new SHA512Managed(); const int blocksize = 128; // match python hash library sha512 block size. if (passwordBytes.Length > blocksize) { inner.TransformFinalBlock(passwordBytes, 0, passwordBytes.Length); passwordBytes = inner.Hash; //inner.Initialize(); } if (passwordBytes.Length < blocksize) { Array.Resize(ref passwordBytes, blocksize); } var trans36 = new byte[256]; var trans5C = new byte[256]; for (var i = 0; i < 256; i++) { trans36[i] = (byte)(i ^ 0x36); trans5C[i] = (byte)(i ^ 0x5c); } var innerSeed = passwordBytes.Select(pb => trans36[pb]).ToArray(); var outerSeed = passwordBytes.Select(pb => trans5C[pb]).ToArray(); var hash = new UInt512(); var xhash = new UInt512(); var data = new byte[salt.Length + 4]; salt.CopyTo(data); 1.AsReadOnlySpan(bigEndian: true).CopyTo(data.AsSpan(salt.Length)); var dataSpan = data.AsSpan(); for (var i = 0; i < iterations; i++) { inner.TransformBlock(innerSeed); outer.TransformBlock(outerSeed); inner.TransformFinalBlock(dataSpan, hash.Span); outer.TransformFinalBlock(hash.Span, hash.Span); dataSpan = hash.Span; xhash = i == 0 ? hash : xhash ^ hash; } return(xhash); }
/// <summary> /// Computes a SHA512 hash /// </summary> /// <param name="text">String or filename of file hash</param> /// <returns>Hexadecimal SHA512 hash string</returns> public static string SHA512(string s) { if (System.IO.File.Exists(s)) { int offset = 0; byte[] block = new byte[ZefieLib.Data.BlockSize]; byte[] hash; using (BufferedStream f = new BufferedStream(new FileStream(s, FileMode.Open, FileAccess.Read))) { using (SHA512 shaM = new SHA512Managed()) { // For each block: while (offset + block.Length < f.Length) { f.Position = offset; f.Read(block, 0, ZefieLib.Data.BlockSize); offset += shaM.TransformBlock(block, 0, block.Length, null, 0); } int remain = (int)(f.Length - (long)offset); block = new byte[remain]; f.Position = offset; _ = f.Read(block, 0, remain); _ = shaM.TransformFinalBlock(block, 0, block.Length); hash = shaM.Hash; } } return(ZefieLib.Data.BytesToHex(hash)); } else { return(SHA512(Encoding.UTF8.GetBytes(s))); } }
internal static byte[] GetHmacKey64(byte[] pbKey, ulong uBlockIndex) { if (pbKey == null) { throw new ArgumentNullException("pbKey"); } Debug.Assert(pbKey.Length == 64); // We are computing the HMAC using SHA-256, whose internal // block size is 512 bits; thus create a key that is 512 // bits long (using SHA-512) byte[] pbBlockKey; using (SHA512Managed h = new SHA512Managed()) { byte[] pbIndex = MemUtil.UInt64ToBytes(uBlockIndex); h.TransformBlock(pbIndex, 0, pbIndex.Length, pbIndex, 0); h.TransformBlock(pbKey, 0, pbKey.Length, pbKey, 0); h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); pbBlockKey = h.Hash; } #if DEBUG byte[] pbZero = new byte[64]; Debug.Assert((pbBlockKey.Length == 64) && !MemUtil.ArraysEqual( pbBlockKey, pbZero)); // Ensure we own pbBlockKey #endif return(pbBlockKey); }
/// <summary> /// Given a string for a site name, generate the registry subkey name /// </summary> /// <param name="site">The site name to get the key from</param> /// <returns>The generated registry key string, or null on failure</returns> public static string GenerateKeyFromSite(string site) { try { // Otherwise, only bother if we have a site to work with: if (!String.IsNullOrEmpty(site) && site.Length > 0) { // Get the SHA-512 of the site name. We'll also include the user's // username and the machine name as a salt. We really should change // the encoding here to something like UTF-8, but we'll leave this // at the default to keep from breaking the user's data. SHA512Managed hasher = new SHA512Managed(); byte[] keyBytes = Encoding.Default.GetBytes(site + Environment.UserName + Environment.MachineName); keyBytes = hasher.TransformFinalBlock(keyBytes, 0, keyBytes.Length); // Convert the binary hash to Base64, then chop it down to 255 characters // if it's too long. Windows registry keys can only be 255 characters // in length. string key = Convert.ToBase64String(keyBytes); if (key.Length > 255) { return(key.Substring(0, 255)); } else { return(key); } } else { return(null); } } catch { return(null); } }
/// <summary> /// Hashes data from a stream. /// </summary> /// <param name="es">The input stream.</param> /// <param name="length">The number of bytes to hash.</param> /// <returns>The hashed digest.</returns> /// <remarks> /// The method will hash length bytes of the stream from the current position /// and the stream position will be restored before the method /// returns. /// </remarks> public static byte[] Compute(EnhancedStream es, long length) { var sha512 = new SHA512Managed(); long streamPos; byte[] buf; int cb; streamPos = es.Position; buf = new byte[8192]; while (length > 0) { cb = (int)(length > buf.Length ? buf.Length : length); if (es.Read(buf, 0, cb) < cb) { throw new InvalidOperationException("Read past end of stream."); } sha512.TransformBlock(buf, 0, cb, buf, 0); length -= cb; } sha512.TransformFinalBlock(buf, 0, 0); es.Seek(streamPos, SeekOrigin.Begin); return(sha512.Hash); }
public byte[] CreateChecksum(string filePath) { using (var hashAlgorithm = new SHA512Managed()) { using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024 * 1024)) { fileStream.Position = 0; long bytesToHash = 1024 * 1024; var buf = new byte[4 * 1024]; while (bytesToHash > 0) { var bytesRead = fileStream.Read(buf, 0, (int)Math.Min(bytesToHash, buf.Length)); hashAlgorithm.TransformBlock(buf, 0, bytesRead, null, 0); bytesToHash -= bytesRead; if (bytesRead == 0) { throw new InvalidOperationException("Unexpected end of stream"); } } hashAlgorithm.TransformFinalBlock(buf, 0, 0); var hash = hashAlgorithm.Hash; return(hash); } } }
/// <summary> /// Given a size in bytes, generate an initialization vector (IV) for encryption /// </summary> /// <param name="size">Size of the output byte array</param> /// <returns>An array of bytes to be used as the IV</returns> private static byte[] GenerateIV(int size, string key) { // Use SHA-512 to generate a pseudo-random IV. We'll use the user's username and // the machine name as the key data; this isn't really super secure, but it should // at least be unique per user/machine. Note that we're using the system default // encoding here, rather than UTF-8; this is a bit of legacy code, and we can't // really change this without breaking existing parameters. Since this is an // internal thing, so it shouldn't be a problem. SHA512Managed hasher = new SHA512Managed(); byte[] iv = Encoding.Default.GetBytes(key + Environment.UserName + Environment.MachineName); hasher.TransformFinalBlock(iv, 0, iv.Length); iv = hasher.Hash; // SHA-512 is probably overkill for the IV we need. So given the size value, // chop of only the number of bytes we need and return those. if (iv.Length > size) { byte[] slice = new byte[size]; Array.Copy(iv, 0, slice, 0, size); return(slice); } else { return(iv); } }
public static string GEtSHA512Hash(string plainMessage) { byte[] bytes = Encoding.UTF8.GetBytes(plainMessage); using (HashAlgorithm algorithm = new SHA512Managed()) { algorithm.TransformFinalBlock(bytes, 0, bytes.Length); return(Convert.ToBase64String(algorithm.Hash)); } }
/// <summary> /// 使用 SHA512算法哈希 /// </summary> /// <param name="plainMessage"></param> /// <returns></returns> public static string GetSHA512Hash(string plainMessage) { var data = Encoding.UTF8.GetBytes(plainMessage); using (HashAlgorithm sha = new SHA512Managed()) { sha.TransformFinalBlock(data, 0, data.Length); return(Convert.ToBase64String(sha.Hash)); } }
private void DeriveCipher() { SHA512Managed sha = new SHA512Managed(); sha.TransformBlock(_secretKey, 0, _secretKey.Length, _secretKey, 0); sha.TransformFinalBlock(_cipherSalt, 0, _cipherSalt.Length); _aes = new AesManaged(); _aes.KeySize = (int)AesKeyBits; _aes.IV = _iv; _aes.Key = new byte[AesKeyBits / 8]; Array.Copy(sha.Hash, _aes.Key, _aes.Key.Length); _aes.Mode = CipherMode.CBC; }
public static byte[] GenerateSharedSecret(byte[] server_pub_key, out byte[] client_pub_key) { byte[] client_sec_key = RandomBytes(32); client_pub_key = ScalarMultBase(client_sec_key); byte [] q = ScalarMult(client_sec_key, server_pub_key); var h = new SHA512Managed(); h.TransformBlock(q, 0, q.Length, q, 0); h.TransformBlock(client_pub_key, 0, client_pub_key.Length, client_pub_key, 0); h.TransformBlock(server_pub_key, 0, server_pub_key.Length, server_pub_key, 0); h.TransformFinalBlock(q, 0, 0); return(h.Hash); }
private void DeriveCipher() { SHA512Managed sha = new SHA512Managed(); sha.TransformBlock(_secretKey, 0, _secretKey.Length, _secretKey, 0); sha.TransformFinalBlock(_cipherSalt, 0, _cipherSalt.Length); _aes = new AesManaged { KeySize = (int)AesKeyBits, IV = _iv, Key = sha.Hash.Take((int)(AesKeyBits / 8)).ToArray(), Mode = CipherMode.CBC }; }
/// <summary> /// Given the user's password, generate a salt which will be mixed with the password /// when setting up the encryption parameters /// </summary> /// <param name="password">A string containing the user's password</param> /// <returns>An array of bytes containing the raw salt value</returns> private static byte[] GenerateSaltFromPassword(string password) { // Get the password as Unicode (UTF-8) bytes: byte[] salt = Encoding.UTF8.GetBytes(password); // Try to hash password multiple times using a really strong hash. // This should give us some really random-ish data for the salt. SHA512Managed hasher = new SHA512Managed(); for (int i = 0; i < SALT_ITERATION_COUNT; i++) { // .NET notes: This isn't quite as simple as the Java version. Each // time we use the hash engine, it must be initialized. We then have // to tell it to transform the final block, which effectively gets it // to hash the whole thing. Then we have to update our salt reference // to the new value. hasher.Initialize(); hasher.TransformFinalBlock(salt, 0, salt.Length); salt = hasher.Hash; } return(salt); }
private byte[] GetSystemEntropy() { SHA512Managed h = new SHA512Managed(); byte[] pb4 = new byte[4]; byte[] pb8 = new byte[8]; GAction <byte[], bool> f = delegate(byte[] pbValue, bool bClearValue) { if (pbValue == null) { Debug.Assert(false); return; } if (pbValue.Length == 0) { return; } h.TransformBlock(pbValue, 0, pbValue.Length, pbValue, 0); if (bClearValue) { MemUtil.ZeroByteArray(pbValue); } }; Action <int> fI32 = delegate(int iValue) { MemUtil.Int32ToBytesEx(iValue, pb4, 0); f(pb4, false); }; Action <long> fI64 = delegate(long lValue) { MemUtil.Int64ToBytesEx(lValue, pb8, 0); f(pb8, false); }; Action <string> fStr = delegate(string strValue) { if (strValue == null) { Debug.Assert(false); return; } if (strValue.Length == 0) { return; } f(StrUtil.Utf8.GetBytes(strValue), false); }; fI32(Environment.TickCount); fI64(DateTime.UtcNow.ToBinary()); #if !KeePassLibSD && !NETSTANDARD2_0 // In try-catch for systems without GUI; // https://sourceforge.net/p/keepass/discussion/329221/thread/20335b73/ try { Point pt = Cursor.Position; fI32(pt.X); fI32(pt.Y); } catch (Exception) { Debug.Assert(NativeLib.IsUnix()); } #endif try { fI32((int)NativeLib.GetPlatformID()); #if KeePassUAP fStr(EnvironmentExt.OSVersion.VersionString); #else fStr(Environment.OSVersion.VersionString); #endif fI32(Environment.ProcessorCount); #if !KeePassUAP && !NETSTANDARD2_0 fStr(Environment.CommandLine); fI64(Environment.WorkingSet); #endif } catch (Exception) { Debug.Assert(false); } try { foreach (DictionaryEntry de in Environment.GetEnvironmentVariables()) { fStr(de.Key as string); fStr(de.Value as string); } } catch (Exception) { Debug.Assert(false); } try { #if KeePassUAP f(DiagnosticsExt.GetProcessEntropy(), true); #elif !KeePassLibSD && !NETSTANDARD2_0 using (Process p = Process.GetCurrentProcess()) { fI64(p.Handle.ToInt64()); fI32(p.HandleCount); fI32(p.Id); fI64(p.NonpagedSystemMemorySize64); fI64(p.PagedMemorySize64); fI64(p.PagedSystemMemorySize64); fI64(p.PeakPagedMemorySize64); fI64(p.PeakVirtualMemorySize64); fI64(p.PeakWorkingSet64); fI64(p.PrivateMemorySize64); fI64(p.StartTime.ToBinary()); fI64(p.VirtualMemorySize64); fI64(p.WorkingSet64); // Not supported in Mono 1.2.6: // fI32(p.SessionId); } #endif } catch (Exception) { Debug.Assert(NativeLib.IsUnix()); } try { CultureInfo ci = CultureInfo.CurrentCulture; if (ci != null) { fI32(ci.GetHashCode()); } else { Debug.Assert(false); } } catch (Exception) { Debug.Assert(false); } f(Guid.NewGuid().ToByteArray(), false); f(GetCspRandom(), true); h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); byte[] pbHash = h.Hash; h.Clear(); MemUtil.ZeroByteArray(pb4); MemUtil.ZeroByteArray(pb8); return(pbHash); }
public static void SHA512(this ReadOnlySpan <byte> data, Span <byte> hash) { using (var sha = new SHA512Managed()) { sha.TransformFinalBlock(data, hash); } }
public static ServiceManifestType SetHashVersion(this ServiceManifestType srv, string baseDir, string targetDir, int maxHashLength) { SHA512Managed sha; List <byte> configHash = new List <byte>(); int offset = 0; if (srv.CodePackage != null) { foreach (var cv in srv.CodePackage) { sha = new SHA512Managed(); offset = 0; var path = cv.Name == "Code" ? targetDir : Path.Combine(baseDir, "PackageRoot", cv.Name); foreach (var f in Directory.GetFiles(path, "*.dll").Concat(Directory.GetFiles(path, "*.exe"))) { var b = File.ReadAllBytes(f); sha.TransformBlock(b, offset, b.Length, b, offset); } sha.TransformFinalBlock(new byte[0], offset, 0); cv.Version += "." + Uri.EscapeDataString(Convert.ToBase64String(sha.Hash)); configHash.AddRange(sha.Hash); } } if (srv.ConfigPackage != null) { foreach (var cv in srv.ConfigPackage) { sha = new SHA512Managed(); offset = 0; foreach (var f in Directory.GetFiles(Path.Combine(baseDir, "PackageRoot", cv.Name))) { var b = File.ReadAllBytes(f); sha.TransformBlock(b, offset, b.Length, b, offset); } sha.TransformFinalBlock(new byte[0], offset, 0); cv.Version += "." + Uri.EscapeDataString(Convert.ToBase64String(sha.Hash)); configHash.AddRange(sha.Hash); } } if (srv.DataPackage != null) { foreach (var cv in srv.DataPackage) { sha = new SHA512Managed(); offset = 0; foreach (var f in Directory.GetFiles(Path.Combine(baseDir, "PackageRoot", cv.Name))) { var b = File.ReadAllBytes(f); sha.TransformBlock(b, offset, b.Length, b, offset); } sha.TransformFinalBlock(new byte[0], offset, 0); cv.Version += "." + Uri.EscapeDataString(Convert.ToBase64String(sha.Hash)); configHash.AddRange(sha.Hash); } } srv.Version += "." + Uri.EscapeDataString(Convert.ToBase64String(new SHA512Managed().ComputeHash(configHash.ToArray()))); return(srv); }
public static void Sha512(this ReadOnlyByteSequence data, ByteSpan hash) { using var sha = new SHA512Managed(); sha.TransformFinalBlock(data, hash); }
/// <summary> /// Gets the final <see cref="SHA512Value"/>. /// Once this value has been read this stream should be disposed. /// </summary> /// <returns>The final SHA512 value.</returns> public SHA512Value GetFinalResult() { _sha512.TransformFinalBlock(Array.Empty <byte>(), 0, 0); return(new SHA512Value(_sha512.Hash)); }
/// <summary> /// Duplicates Python hashlib's pbkdf2_hmac for hash_name = 'sha512' and dklen = None /// /// Performance can be improved by precomputing _trans_36 and _trans_5c. /// Unlike Python's hash functions, .NET doesn't currently support copying state between blocks. /// This results in having to recompute hash of innerSeed and outerSeed on each iteration. /// </summary> /// <param name="password"></param> /// <param name="salt"></param> /// <param name="iterations"></param> /// <returns></returns> public static KzUInt512 pbkdf2_hmac_sha512(ReadOnlySpan <byte> password, ReadOnlySpan <byte> salt, int iterations) { if (iterations < 1) { throw new ArgumentException(); } var _password = password.ToArray(); using var inner = new SHA512Managed(); using var outer = new SHA512Managed(); var blocksize = 128; // match python hashlib's sha512 blocksize. if (_password.Length > blocksize) { inner.TransformFinalBlock(_password, 0, _password.Length); _password = inner.Hash; //inner.Initialize(); } if (_password.Length < blocksize) { Array.Resize(ref _password, blocksize); } var _trans_36 = new byte[256]; var _trans_5c = new byte[256]; for (var i = 0; i < 256; i++) { _trans_36[i] = (byte)(i ^ 0x36); _trans_5c[i] = (byte)(i ^ 0x5c); } var innerSeed = _password.Select(pb => _trans_36[pb]).ToArray(); var outerSeed = _password.Select(pb => _trans_5c[pb]).ToArray(); var hash = new KzUInt512(); var xhash = new KzUInt512(); var data = new byte[salt.Length + 4]; salt.CopyTo(data); var loop = 1; loop.AsReadOnlySpan(bigEndian: true).CopyTo(data.AsSpan(salt.Length)); var dataSpan = data.AsSpan(); for (var i = 0; i < iterations; i++) { inner.TransformBlock(innerSeed); outer.TransformBlock(outerSeed); inner.TransformFinalBlock(dataSpan, hash.Span); outer.TransformFinalBlock(hash.Span, hash.Span); dataSpan = hash.Span; xhash = i == 0 ? hash : xhash ^ hash; } return(xhash); }
static void Main(string[] args) { if (args == null || args.Length < 1 || (args[0].ToLower() != "e" && args[0].ToLower() != "d")) { Console.Error.WriteLine("Usage:"); Console.Error.WriteLine(" To encrypt: AesCrypt.exe e <file path>"); Console.Error.WriteLine(" To decrypt: AesCrypt.exe d <file path> <iv> <key>"); return; } if (args[0].ToLower() == "e") { // ENCRYPTION if (args.Length < 2) { Console.Error.WriteLine("Usage: AesCrypt.exe e <file path>"); } string fileToEncrypt = args[1]; FileInfo inpFile = new FileInfo(fileToEncrypt); if (!inpFile.Exists) { Console.Error.WriteLine("File does not exist"); return; } byte[] fileName = Encoding.UTF8.GetBytes(inpFile.FullName); string rootDir = Path.GetDirectoryName(fileToEncrypt); string randomName = Guid.NewGuid().ToString("N"); string tempName = Path.Combine(rootDir, randomName); string finalHash; if (File.Exists(tempName)) { Console.Error.WriteLine("ERROR: temporary file exists, wtf how does that even happen"); return; } using (FileStream inp = File.Open(fileToEncrypt, FileMode.Open, FileAccess.Read, FileShare.Read)) using (FileStream oup = File.Create(tempName)) using (AesManaged enc = new AesManaged()) { enc.KeySize = 256; enc.Mode = CipherMode.CBC; enc.GenerateIV(); enc.GenerateKey(); SHA512Managed originalHash = new SHA512Managed(); originalHash.Initialize(); SHA512Managed cryptedHash = new SHA512Managed(); using (CryptoStream hashStream = new CryptoStream(oup, cryptedHash, CryptoStreamMode.Write)) using (CryptoStream cs = new CryptoStream(hashStream, enc.CreateEncryptor(), CryptoStreamMode.Write)) { // crypted file structure: {name length x2}{full file name}{data length x8}{data}{sha512 hash of data x64} byte[] lenFileName = BitConverter.GetBytes((ushort)fileName.Length); cs.Write(lenFileName, 0, lenFileName.Length); cs.Write(fileName, 0, fileName.Length); byte[] fileSizeBits = BitConverter.GetBytes(inpFile.Length); cs.Write(fileSizeBits, 0, fileSizeBits.Length); byte[] data = new byte[64 * 1024]; int bytesRead; long bytesHashed = 0; do { // pull data from original file bytesRead = inp.Read(data, 0, data.Length); // send it to crypted stream cs.Write(data, 0, bytesRead); // also hash it for decryption verification purposes bytesHashed += originalHash.TransformBlock(data, 0, bytesRead, data, 0); } while (bytesRead > 0); // write original hash into crypted file so we can verify it after decryption originalHash.TransformFinalBlock(data, 0, 0); cs.Write(originalHash.Hash, 0, originalHash.Hash.Length); } finalHash = Base32.ToBase32String(cryptedHash.Hash); string iv = Convert.ToBase64String(enc.IV); string key = Convert.ToBase64String(enc.Key); Console.Out.WriteLine("{0} {1} {2}", finalHash, iv, key); } File.Move(tempName, Path.Combine(rootDir, finalHash)); } else { // DECRYPTION if (args.Length < 4) { Console.Error.WriteLine("Usage: AesCrypt.exe d <file path> <iv> <key>"); return; } FileInfo encFile = new FileInfo(args[1]); if (!encFile.Exists) { Console.Error.WriteLine("File does not exist"); return; } byte[] iv = Convert.FromBase64String(args[2]); if (iv == null || iv.Length < 1) { Console.Error.WriteLine("ERROR: invalid iv"); return; } byte[] key = Convert.FromBase64String(args[3]); if (key == null || key.Length < 1) { Console.Error.WriteLine("ERROR: invalid key"); return; } using (FileStream inp = encFile.OpenRead()) using (AesManaged aes = new AesManaged()) { aes.KeySize = 256; aes.Mode = CipherMode.CBC; aes.IV = iv; aes.Key = key; using (CryptoStream cs = new CryptoStream(inp, aes.CreateDecryptor(), CryptoStreamMode.Read)) { // crypted file structure: {name length x4}{full file name}{data length x8}{data}{sha512 hash of data x64} byte[] nameLengthBits = new byte[2]; if (cs.Read(nameLengthBits, 0, 2) != 2) { Console.Error.WriteLine("ERROR: Failed reading file name size"); return; } ushort nameLength = BitConverter.ToUInt16(nameLengthBits, 0); byte[] originalName = new byte[nameLength]; if (cs.Read(originalName, 0, nameLength) != nameLength) { Console.Error.WriteLine("ERROR: Failed reading file name"); return; } string fileName = Encoding.UTF8.GetString(originalName); byte[] dataLengthBits = new byte[8]; if (cs.Read(dataLengthBits, 0, dataLengthBits.Length) != dataLengthBits.Length) { Console.Error.WriteLine("ERROR: Failed reading data length"); return; } long dataLength = BitConverter.ToInt64(dataLengthBits, 0); string outputFileName = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(fileName)); if (File.Exists(outputFileName)) { Console.Error.WriteLine("ERROR: '{0}' already exists, exiting", outputFileName); return; } Console.Out.WriteLine("Decrypting what was originally called '{0}' ({1:N0} bytes)", fileName, dataLength); byte[] decryptedHash; long totalRead = 0; using (FileStream outputStream = new FileStream(outputFileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read)) using (SHA512Managed hasher = new SHA512Managed()) { byte[] buffer = new byte[ReadBufferSize]; long bytesRemaining = dataLength; while (bytesRemaining > 0) { int readingThisRound = ReadBufferSize < bytesRemaining ? ReadBufferSize : (int)bytesRemaining; int bytesRead = cs.Read(buffer, 0, readingThisRound); totalRead += bytesRead; // dump decrypted data to file outputStream.Write(buffer, 0, bytesRead); // run it through the grinder for verification later int hashProgress = hasher.TransformBlock(buffer, 0, bytesRead, buffer, 0); Debug.Assert(hashProgress == bytesRead, "Hash calculation out of whack with file IO, wtf is going on"); bytesRemaining -= bytesRead; } hasher.TransformFinalBlock(buffer, 0, 0); decryptedHash = hasher.Hash; } byte[] originalHashBits = new byte[64]; if (cs.Read(originalHashBits, 0, originalHashBits.Length) != originalHashBits.Length) { Console.Error.WriteLine("ERROR: Failed reading verification hash, encrypted file is corrupted!"); return; } if (originalHashBits.SequenceEqual(decryptedHash)) { Console.Out.WriteLine("Successfully decrypted '{0}'", outputFileName); } else { Console.Out.WriteLine("Decryption FAIL"); } } } } }
byte[] IHashAlgorithm.GetRunningHash () { var copy = new SHA512Managed (this); copy.TransformFinalBlock (empty, 0, 0); return copy.Hash; }