Пример #1
0
        /// <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(DocumentHeaders outputDocumentHeaders, Stream cipherStream, ProgressContext progress)
        {
            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 (DocumentHeaders == null)
            {
                throw new InternalErrorException("Document headers are not loaded");
            }

            using (HmacStream hmacStreamOutput = new HmacStream(outputDocumentHeaders.HmacSubkey.Key, cipherStream))
            {
                outputDocumentHeaders.WriteWithHmac(hmacStreamOutput);
                using (AxCryptDataStream encryptedDataStream = _reader.CreateEncryptedDataStream(DocumentHeaders.HmacSubkey.Key, DocumentHeaders.CipherTextLength, progress))
                {
                    CopyToWithCount(encryptedDataStream, hmacStreamOutput, progress);

                    if (_reader.Hmac != DocumentHeaders.Hmac)
                    {
                        throw new Axantum.AxCrypt.Core.Runtime.InvalidDataException("HMAC validation error in the input stream.", ErrorStatus.HmacValidationError);
                    }
                }

                outputDocumentHeaders.Hmac = hmacStreamOutput.HmacResult;

                // Rewind and rewrite the headers, now with the updated HMAC
                outputDocumentHeaders.WriteWithoutHmac(cipherStream);
                cipherStream.Position = cipherStream.Length;
            }
        }
Пример #2
0
        /// <summary>
        /// Encrypt a stream with a given set of headers and write to an output stream. The caller is responsible for consistency and completeness
        /// of the headers. Headers that are not known until encryption and compression are added here.
        /// </summary>
        /// <param name="outputDocumentHeaders"></param>
        /// <param name="inputStream"></param>
        /// <param name="outputStream"></param>
        public void EncryptTo(DocumentHeaders outputDocumentHeaders, Stream inputStream, Stream outputStream, AxCryptOptions options, ProgressContext progress)
        {
            if (outputDocumentHeaders == null)
            {
                throw new ArgumentNullException("outputDocumentHeaders");
            }
            if (inputStream == null)
            {
                throw new ArgumentNullException("inputStream");
            }
            if (outputStream == null)
            {
                throw new ArgumentNullException("outputStream");
            }
            if (progress == null)
            {
                throw new ArgumentNullException("progress");
            }
            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);
            outputDocumentHeaders.IsCompressed = isCompressed;
            outputDocumentHeaders.WriteWithoutHmac(outputStream);
            using (ICryptoTransform encryptor = DataCrypto.CreateEncryptingTransform())
            {
                long outputStartPosition = outputStream.Position;
                using (CryptoStream encryptingStream = new CryptoStream(new NonClosingStream(outputStream), encryptor, CryptoStreamMode.Write))
                {
                    if (isCompressed)
                    {
                        EncryptWithCompressionInternal(outputDocumentHeaders, inputStream, encryptingStream, progress);
                    }
                    else
                    {
                        outputDocumentHeaders.PlaintextLength = CopyToWithCount(inputStream, encryptingStream, progress);
                    }
                }
                outputStream.Flush();
                outputDocumentHeaders.CipherTextLength = outputStream.Position - outputStartPosition;
                using (HmacStream outputHmacStream = new HmacStream(outputDocumentHeaders.HmacSubkey.Key, outputStream))
                {
                    outputDocumentHeaders.WriteWithHmac(outputHmacStream);
                    outputHmacStream.ReadFrom(outputStream);
                    outputDocumentHeaders.Hmac = outputHmacStream.HmacResult;
                }

                // Rewind and rewrite the headers, now with the updated HMAC
                outputDocumentHeaders.WriteWithoutHmac(outputStream);
                outputStream.Position = outputStream.Length;
            }
        }
Пример #3
0
        public AxCryptDataStream CreateEncryptedDataStream(AesKey hmacKey, long cipherTextLength, ProgressContext progress)
        {
            if (hmacKey == null)
            {
                throw new ArgumentNullException("hmacKey");
            }
            if (progress == null)
            {
                throw new ArgumentNullException("progress");
            }
            if (_disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }
            if (CurrentItemType != AxCryptItemType.Data)
            {
                throw new InvalidOperationException("GetEncryptedDataStream() was called when the reader is not positioned at the data.");
            }

            CurrentItemType = AxCryptItemType.EndOfStream;

            _hmacStream = new HmacStream(hmacKey);
            _hmacBufferStream.Position = 0;
            _hmacBufferStream.CopyTo(_hmacStream, OS.Current.StreamBufferSize);

            _expectedTotalHmacLength = _hmacBufferStream.Length + cipherTextLength;

            AxCryptDataStream encryptedDataStream = new AxCryptDataStream(_inputStream, _hmacStream, cipherTextLength);

            return encryptedDataStream;
        }
Пример #4
0
 private void Dispose(bool disposing)
 {
     if (_disposed)
     {
         return;
     }
     if (disposing)
     {
         if (_inputStream != null)
         {
             _inputStream.Dispose();
             _inputStream = null;
         }
         if (_hmacBufferStream != null)
         {
             _hmacBufferStream.Dispose();
             _hmacBufferStream = null;
         }
         if (_hmacStream != null)
         {
             _hmacStream.Dispose();
             _hmacStream = null;
         }
         _disposed = true;
     }
 }
Пример #5
0
        public static void TestHmacStream()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                using (HmacStream hmacStream = new HmacStream(null)) { }
            });

            AesKey key = new AesKey(new byte[16]);
            using (HmacStream hmacStream = new HmacStream(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.");

                DataHmac 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>(() =>
                {
                    DataHmac 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);
                    }
                });
            }
        }