public void WriteWithHmac(V1HmacStream hmacStream) { if (hmacStream == null) { throw new ArgumentNullException("hmacStream"); } WriteInternal(hmacStream.ChainedStream, hmacStream); }
public void EncryptTo(Stream inputStream, Stream outputStream, AxCryptOptions options) { if (inputStream == null) { throw new ArgumentNullException("inputStream"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } if (!outputStream.CanSeek) { throw new ArgumentException("The output stream must support seek in order to back-track and write the HMAC."); } if (options.HasMask(AxCryptOptions.EncryptWithCompression) && options.HasMask(AxCryptOptions.EncryptWithoutCompression)) { throw new ArgumentException("Invalid options, cannot specify both with and without compression."); } if (!options.HasMask(AxCryptOptions.EncryptWithCompression) && !options.HasMask(AxCryptOptions.EncryptWithoutCompression)) { throw new ArgumentException("Invalid options, must specify either with or without compression."); } bool isCompressed = options.HasMask(AxCryptOptions.EncryptWithCompression); DocumentHeaders.IsCompressed = isCompressed; DocumentHeaders.WriteWithoutHmac(outputStream); using (ICryptoTransform encryptor = DataCrypto.EncryptingTransform()) { long outputStartPosition = outputStream.Position; using (Stream encryptingStream = New <CryptoStreamBase>().Initialize(new NonClosingStream(outputStream), encryptor, CryptoStreamMode.Write)) { if (isCompressed) { EncryptWithCompressionInternal(DocumentHeaders, inputStream, encryptingStream); } else { DocumentHeaders.PlaintextLength = StreamExtensions.CopyTo(inputStream, encryptingStream); } } outputStream.Flush(); DocumentHeaders.CipherTextLength = outputStream.Position - outputStartPosition; using (V1HmacStream outputHmacStream = new V1HmacStream(DocumentHeaders.HmacSubkey.Key, outputStream)) { DocumentHeaders.WriteWithHmac(outputHmacStream); outputHmacStream.ReadFrom(outputStream); DocumentHeaders.Headers.Hmac = outputHmacStream.HmacResult; } // Rewind and rewrite the headers, now with the updated HMAC DocumentHeaders.WriteWithoutHmac(outputStream); outputStream.Position = outputStream.Length; } }
private void ResetState(Passphrase passphrase) { DocumentHeaders = new V1DocumentHeaders(passphrase); PassphraseIsValid = false; Properties = EncryptedProperties.Create(this); if (_hmacStream != null) { _hmacStream.Dispose(); _hmacStream = null; } }
/// <summary> /// Write a copy of the current encrypted stream. Used to change meta-data /// and encryption key(s) etc. /// </summary> /// <param name="outputStream"></param> public void CopyEncryptedTo(V1DocumentHeaders outputDocumentHeaders, Stream cipherStream) { if (outputDocumentHeaders == null) { throw new ArgumentNullException("outputDocumentHeaders"); } if (cipherStream == null) { throw new ArgumentNullException("cipherStream"); } if (!cipherStream.CanSeek) { throw new ArgumentException("The output stream must support seek in order to back-track and write the HMAC."); } if (!PassphraseIsValid) { throw new InternalErrorException("Passphrase is not valid."); } using (V1HmacStream hmacStreamOutput = new V1HmacStream(outputDocumentHeaders.HmacSubkey.Key, cipherStream)) { outputDocumentHeaders.WriteWithHmac(hmacStreamOutput); using (V1AxCryptDataStream encryptedDataStream = CreateEncryptedDataStream(_reader.InputStream, DocumentHeaders.CipherTextLength)) { encryptedDataStream.CopyTo(hmacStreamOutput); if (Hmac != DocumentHeaders.Headers.Hmac) { throw new Axantum.AxCrypt.Core.Runtime.IncorrectDataException("HMAC validation error in the input stream.", ErrorStatus.HmacValidationError); } } outputDocumentHeaders.Headers.Hmac = hmacStreamOutput.HmacResult; // Rewind and rewrite the headers, now with the updated HMAC outputDocumentHeaders.WriteWithoutHmac(cipherStream); cipherStream.Position = cipherStream.Length; } }
/// <summary> /// Loads an AxCrypt file from the specified reader. After this, the reader is positioned to /// read encrypted data. /// </summary> /// <param name="inputStream">The stream to read from. Will be disposed when this instance is disposed.</param> /// <returns>True if the key was valid, false if it was wrong.</returns> private bool Load(Passphrase passphrase, AxCryptReader reader, Headers headers) { _reader = reader; ResetState(passphrase); PassphraseIsValid = DocumentHeaders.Load(headers); if (!PassphraseIsValid) { return(false); } _hmacStream = new V1HmacStream(DocumentHeaders.HmacSubkey.Key); foreach (HeaderBlock header in DocumentHeaders.Headers.HeaderBlocks) { if (header.HeaderBlockType != HeaderBlockType.Preamble) { header.Write(_hmacStream); } } Properties = EncryptedProperties.Create(this); return(true); }
private void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { if (_reader != null) { _reader.Dispose(); _reader = null; } if (_hmacStream != null) { _hmacStream.Dispose(); _hmacStream = null; } } _disposed = true; }
public static void TestHmacStream(CryptoImplementation cryptoImplementation) { SetupAssembly.AssemblySetupCrypto(cryptoImplementation); Assert.Throws <ArgumentNullException>(() => { using (V1HmacStream hmacStream = new V1HmacStream(null)) { } }); SymmetricKey key = new SymmetricKey(new byte[16]); using (V1HmacStream hmacStream = new V1HmacStream(key)) { Assert.That(hmacStream.CanRead, Is.False, "HmacStream does not support reading."); Assert.That(hmacStream.CanSeek, Is.False, "HmacStream does not support seeking."); Assert.That(hmacStream.CanWrite, Is.True, "HmacStream does support writing."); Assert.Throws <NotSupportedException>(() => { byte[] buffer = new byte[5]; hmacStream.Read(buffer, 0, buffer.Length); }); Assert.Throws <NotSupportedException>(() => { hmacStream.Seek(0, SeekOrigin.Begin); }); Assert.Throws <NotSupportedException>(() => { hmacStream.SetLength(0); }); Assert.Throws <ArgumentNullException>(() => { hmacStream.ReadFrom(null); }); hmacStream.Write(new byte[10], 0, 10); using (Stream dataStream = new MemoryStream()) { dataStream.Write(new byte[10], 0, 10); dataStream.Position = 0; hmacStream.ReadFrom(dataStream); } Assert.That(hmacStream.Position, Is.EqualTo(20), "There are 20 bytes written so the position should be 20."); Assert.That(hmacStream.Length, Is.EqualTo(20), "There are 20 bytes written so the position should be 20."); hmacStream.Flush(); Assert.That(hmacStream.Position, Is.EqualTo(20), "Nothing should change after Flush(), this is not a buffered stream."); Assert.That(hmacStream.Length, Is.EqualTo(20), "Nothing should change after Flush(), this is not a buffered stream."); Assert.Throws <NotSupportedException>(() => { hmacStream.Position = 0; }, "Position is not supported."); Hmac dataHmac = hmacStream.HmacResult; Assert.That(dataHmac.GetBytes(), Is.EquivalentTo(new byte[] { 0x62, 0x6f, 0x2c, 0x61, 0xc7, 0x68, 0x00, 0xb3, 0xa6, 0x8d, 0xf9, 0x55, 0x95, 0xbc, 0x1f, 0xd1 }), "The HMAC of 20 bytes of zero with 128-bit AesKey all zero should be this."); Assert.Throws <InvalidOperationException>(() => { hmacStream.Write(new byte[1], 0, 1); }, "Can't write to the stream after checking and thus finalizing the HMAC"); // This also implicitly covers double-dispose since we're in a using block. hmacStream.Dispose(); Assert.Throws <ObjectDisposedException>(() => { Hmac invalidDataHmac = hmacStream.HmacResult; // Remove FxCop warning Object.Equals(invalidDataHmac, null); }); Assert.Throws <ObjectDisposedException>(() => { hmacStream.Write(new byte[1], 0, 1); }); Assert.Throws <ObjectDisposedException>(() => { using (Stream stream = new MemoryStream()) { hmacStream.ReadFrom(stream); } }); } }