internal void _Decrypt(Stream inputStream, Stream outputStream, byte[] password) { var info = new byte[HashLengthSize + SaltLengthSize + EncryptedLengthSize]; inputStream.Read(info, 0, info.Length); var hashLength = BitConverter.ToInt32(info, 0); var saltLength = BitConverter.ToInt32(info, HashLengthSize); var encryptedLength = BitConverter.ToInt64(info, HashLengthSize + SaltLengthSize); byte[] salt = new byte[saltLength], hash = new byte[hashLength]; inputStream.Read(hash,0, hashLength); inputStream.Read(salt, 0, saltLength); using (var rfc2898 = new Rfc2898DeriveBytes(password, salt, DefaultIteration)) using (var algorithm = GetSymmetricAlgorithm()) { algorithm.KeySize = DefaultKeySize; algorithm.BlockSize = DefaultBlockSize; var key = rfc2898.GetBytes(DefaultKeySize / 8); var iv = rfc2898.GetBytes(DefaultBlockSize / 8); using (var transform = algorithm.CreateDecryptor(key, iv)) using (var hasher = IncrementalHash.CreateHMAC(DefaultHashAlgorithm, password)) using (var crytoStream = new CryptoStream(outputStream, transform, CryptoStreamMode.Write)) { foreach (var bytes in inputStream.ReadByChunk(Config.DefaultChunkSize, encryptedLength)) { hasher.AppendData(bytes); crytoStream.Write(bytes, 0, bytes.Length); } if (!hash.SequenceEqual(hasher.GetHashAndReset())) throw new Exception("HMAC value is not correct"); } } }
internal void _EncryptThenMac(Stream inputStream, Stream outputStream, byte[] password, byte[] salt) { using (var rfc2898 = new Rfc2898DeriveBytes(password, salt, DefaultIteration)) using (var algorithm = GetSymmetricAlgorithm()) { algorithm.KeySize = DefaultKeySize; algorithm.BlockSize = DefaultBlockSize; var key = rfc2898.GetBytes(DefaultKeySize / 8); var iv = rfc2898.GetBytes(DefaultBlockSize / 8); long encryptedLength = 0; using (var transform = algorithm.CreateEncryptor(key, iv)) using (var hasher = IncrementalHash.CreateHMAC(DefaultHashAlgorithm, password)) using (var delegateStream = new DelegateStream(outputStream, null, (buffer, offset, count) => { encryptedLength += buffer.Length; hasher.AppendData(buffer); })) { var hash = hasher.GetHashAndReset(); outputStream.Write(BitConverter.GetBytes(hash.Length), 0, HashLengthSize); outputStream.Write(BitConverter.GetBytes(salt.Length), 0, SaltLengthSize); outputStream.Write(BitConverter.GetBytes(encryptedLength), 0, EncryptedLengthSize); outputStream.Write(hash, 0, hash.Length); outputStream.Write(salt, 0, salt.Length); using (var crytoStream = new CryptoStream(delegateStream, transform, CryptoStreamMode.Write)) { foreach (var bytes in inputStream.ReadByChunk()) crytoStream.Write(bytes, 0, bytes.Length); } outputStream.Seek(HashLengthSize + SaltLengthSize, SeekOrigin.Begin); outputStream.Write(BitConverter.GetBytes(encryptedLength), 0, EncryptedLengthSize); outputStream.Write(hasher.GetHashAndReset(), 0, hash.Length); } } }