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;
        }
예제 #7
0
        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);
                    }
                });
            }
        }