public static void TestKeyEncryptingKey() { AesKey keyEncryptingKey = new AesKey(); DocumentHeaders headers = new DocumentHeaders(keyEncryptingKey); Assert.That(headers.KeyEncryptingKey, Is.EqualTo(keyEncryptingKey), "Unexpected key encrypting key retrieved."); }
public static void Encrypt(IRuntimeFileInfo sourceFile, Stream destinationStream, AesKey key, AxCryptOptions options, ProgressContext progress) { if (sourceFile == null) { throw new ArgumentNullException("sourceFile"); } if (destinationStream == null) { throw new ArgumentNullException("destinationStream"); } if (key == null) { throw new ArgumentNullException("key"); } if (progress == null) { throw new ArgumentNullException("progress"); } using (Stream sourceStream = sourceFile.OpenRead()) { using (AxCryptDocument document = new AxCryptDocument()) { DocumentHeaders headers = new DocumentHeaders(key); headers.FileName = sourceFile.Name; headers.CreationTimeUtc = sourceFile.CreationTimeUtc; headers.LastAccessTimeUtc = sourceFile.LastAccessTimeUtc; headers.LastWriteTimeUtc = sourceFile.LastWriteTimeUtc; document.DocumentHeaders = headers; document.EncryptTo(headers, sourceStream, destinationStream, options, progress); } } }
public static void TestInvalidHmacInCopyEncryptedTo() { using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); bool keyIsOk = document.Load(FakeRuntimeFileInfo.ExpandableMemoryStream(Resources.helloworld_key_a_txt), passphrase.DerivedPassphrase); Assert.That(keyIsOk, Is.True, "The passphrase provided is correct and should work!"); Passphrase newPassphrase = new Passphrase("b"); using (Stream changedStream = new MemoryStream()) { DocumentHeaders outputDocumentHeaders = new DocumentHeaders(document.DocumentHeaders); outputDocumentHeaders.SetCurrentVersion(); outputDocumentHeaders.RewrapMasterKey(newPassphrase.DerivedPassphrase); byte[] modifiedHmacBytes = document.DocumentHeaders.Hmac.GetBytes(); modifiedHmacBytes[0] += 1; document.DocumentHeaders.Hmac = new DataHmac(modifiedHmacBytes); Assert.Throws <Axantum.AxCrypt.Core.Runtime.InvalidDataException>(() => { document.CopyEncryptedTo(outputDocumentHeaders, changedStream, new ProgressContext()); }); } } }
public static void TestInvalidArguments() { using (Stream inputStream = FakeRuntimeFileInfo.ExpandableMemoryStream(Encoding.UTF8.GetBytes("AxCrypt is Great!"))) { using (Stream outputStream = new MemoryStream()) { using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); DocumentHeaders headers = new DocumentHeaders(passphrase.DerivedPassphrase); Assert.Throws <ArgumentNullException>(() => { document.EncryptTo(null, inputStream, outputStream, AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws <ArgumentNullException>(() => { document.EncryptTo(headers, null, outputStream, AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws <ArgumentNullException>(() => { document.EncryptTo(headers, inputStream, null, AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws <ArgumentNullException>(() => { document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.EncryptWithCompression, null); }); Assert.Throws <ArgumentException>(() => { document.EncryptTo(headers, inputStream, new NonSeekableStream(), AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws <ArgumentException>(() => { document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.EncryptWithCompression | AxCryptOptions.EncryptWithoutCompression, new ProgressContext()); }); Assert.Throws <ArgumentException>(() => { document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.None, new ProgressContext()); }); Assert.Throws <ArgumentNullException>(() => { document.CopyEncryptedTo(null, outputStream, new ProgressContext()); }); Assert.Throws <ArgumentNullException>(() => { document.CopyEncryptedTo(headers, null, new ProgressContext()); }); Assert.Throws <ArgumentException>(() => { document.CopyEncryptedTo(headers, new NonSeekableStream(), new ProgressContext()); }); Assert.Throws <InternalErrorException>(() => { document.CopyEncryptedTo(headers, outputStream, new ProgressContext()); }); } } } }
public static void TestChangePassphraseForSimpleFile() { using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); bool keyIsOk = document.Load(FakeRuntimeFileInfo.ExpandableMemoryStream(Resources.helloworld_key_a_txt), passphrase.DerivedPassphrase); Assert.That(keyIsOk, Is.True, "The passphrase provided is correct and should work!"); Passphrase newPassphrase = new Passphrase("b"); using (Stream changedStream = new MemoryStream()) { DocumentHeaders outputDocumentHeaders = new DocumentHeaders(document.DocumentHeaders); outputDocumentHeaders.SetCurrentVersion(); outputDocumentHeaders.RewrapMasterKey(newPassphrase.DerivedPassphrase); document.CopyEncryptedTo(outputDocumentHeaders, changedStream, new ProgressContext()); changedStream.Position = 0; using (AxCryptDocument changedDocument = new AxCryptDocument()) { bool changedKeyIsOk = changedDocument.Load(changedStream, newPassphrase.DerivedPassphrase); Assert.That(changedKeyIsOk, Is.True, "The changed passphrase provided is correct and should work!"); using (MemoryStream plaintextStream = new MemoryStream()) { changedDocument.DecryptTo(plaintextStream, new ProgressContext()); Assert.That(Encoding.ASCII.GetString(plaintextStream.GetBuffer(), 0, (int)plaintextStream.Length), Is.EqualTo("HelloWorld"), "Unexpected result of decryption."); Assert.That(changedDocument.DocumentHeaders.PlaintextLength, Is.EqualTo(10), "'HelloWorld' should be 10 bytes uncompressed plaintext."); } } } } }
public bool VerifyHmac() { using (Stream encryptedDataStream = CreateEncryptedDataStream()) { encryptedDataStream.CopyTo(Stream.Null); } DocumentHeaders.Trailers(_reader); return(DocumentHeaders.HmacCalculator.Hmac == DocumentHeaders.Hmac); }
/// <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(Stream inputStream, Stream outputStream, AxCryptOptions options) { if (inputStream == null) { throw new ArgumentNullException("inputStream"); } if (outputStream == null) { throw new ArgumentNullException("outputStream"); } 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."); } DocumentHeaders.IsCompressed = options.HasMask(AxCryptOptions.EncryptWithCompression); V2HmacCalculator hmacCalculator = new V2HmacCalculator(new SymmetricKey(DocumentHeaders.GetHmacKey())); V2HmacStream <Stream> outputHmacStream = V2HmacStream.Create(hmacCalculator, outputStream); CryptoStreamBase encryptingStream = New <CryptoStreamBase>().Initialize(V2AxCryptDataStream.Create(outputHmacStream), DocumentHeaders.DataCrypto().EncryptingTransform(), CryptoStreamMode.Write); DocumentHeaders.WriteStartWithHmac(outputHmacStream); if (DocumentHeaders.IsCompressed) { using (ZOutputStream deflatingStream = new ZOutputStream(encryptingStream, -1)) { deflatingStream.FlushMode = JZlib.Z_SYNC_FLUSH; inputStream.CopyTo(deflatingStream); deflatingStream.FlushMode = JZlib.Z_FINISH; deflatingStream.Finish(); _plaintextLength = deflatingStream.TotalIn; _compressedPlaintextLength = deflatingStream.TotalOut; encryptingStream.FinalFlush(); DocumentHeaders.WriteEndWithHmac(hmacCalculator, outputHmacStream, _plaintextLength, _compressedPlaintextLength); } } else { try { _compressedPlaintextLength = _plaintextLength = StreamExtensions.CopyTo(inputStream, encryptingStream); encryptingStream.FinalFlush(); DocumentHeaders.WriteEndWithHmac(hmacCalculator, outputHmacStream, _plaintextLength, _compressedPlaintextLength); } finally { encryptingStream.Dispose(); } } }
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; } }
/// <summary> /// Loads an AxCrypt file from the specified reader. After this, the reader is positioned to /// read encrypted data. /// </summary> /// <param name="stream">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> public bool Load(Stream stream, AesKey key) { _reader = AxCryptReader.Create(stream); DocumentHeaders documentHeaders = new DocumentHeaders(key); PassphraseIsValid = documentHeaders.Load(_reader); if (PassphraseIsValid) { DocumentHeaders = documentHeaders; } return(PassphraseIsValid); }
private static void EncryptWithCompressionInternal(DocumentHeaders outputDocumentHeaders, Stream inputStream, CryptoStream encryptingStream, ProgressContext progress) { using (ZOutputStream deflatingStream = new ZOutputStream(encryptingStream, -1)) { deflatingStream.FlushMode = JZlib.Z_SYNC_FLUSH; CopyToWithCount(inputStream, deflatingStream, progress); deflatingStream.FlushMode = JZlib.Z_FINISH; deflatingStream.Finish(); outputDocumentHeaders.UncompressedLength = deflatingStream.TotalIn; outputDocumentHeaders.PlaintextLength = deflatingStream.TotalOut; } }
public static void TestBadArguments() { DocumentHeaders documentHeaders = new DocumentHeaders(new AesKey()); Assert.Throws<ArgumentNullException>(() => { documentHeaders.WriteWithHmac(null); }); Assert.Throws<ArgumentNullException>(() => { documentHeaders.WriteWithoutHmac(null); }); Assert.Throws<ArgumentNullException>(() => { documentHeaders.Hmac = null; }); }
public static void TestBadKey() { using (Stream testStream = FakeRuntimeFileInfo.ExpandableMemoryStream(Resources.helloworld_key_a_txt)) { using (AxCryptReader reader = AxCryptReader.Create(testStream)) { Passphrase passphrase = new Passphrase("b"); DocumentHeaders documentHeaders = new DocumentHeaders(passphrase.DerivedPassphrase); bool isPassphraseValid = documentHeaders.Load(reader); Assert.That(isPassphraseValid, Is.False, "The passphrase is intentionally wrong for this test case."); Assert.That(documentHeaders.HmacSubkey, Is.Null, "Since the passphrase is wrong, HmacSubkey should return null."); Assert.That(documentHeaders.DataSubkey, Is.Null, "Since the passphrase is wrong, DataSubkey should return null."); Assert.That(documentHeaders.HeadersSubkey, Is.Null, "Since the passphrase is wrong, HeadersSubkey should return null."); } } }
public static void TestInvalidItemType() { using (MemoryStream inputStream = new MemoryStream()) { AxCrypt1Guid.Write(inputStream); new PreambleHeaderBlock().Write(inputStream); inputStream.Position = 0; using (AxCryptReaderForTest axCryptReader = new AxCryptReaderForTest(inputStream)) { DocumentHeaders documentHeaders = new DocumentHeaders(new AesKey()); Assert.Throws <InternalErrorException>(() => { documentHeaders.Load(axCryptReader); }); } } }
public static void TestBadArguments() { DocumentHeaders documentHeaders = new DocumentHeaders(new AesKey()); Assert.Throws <ArgumentNullException>(() => { documentHeaders.WriteWithHmac(null); }); Assert.Throws <ArgumentNullException>(() => { documentHeaders.WriteWithoutHmac(null); }); Assert.Throws <ArgumentNullException>(() => { documentHeaders.Hmac = null; }); }
/// <summary> /// Decrypt from loaded AxCryptDocument to a destination file /// </summary> /// <param name="document">The loaded AxCryptDocument</param> /// <param name="destinationFile">The destination file</param> public static void Decrypt(AxCryptDocument document, IRuntimeFileInfo destinationFile, AxCryptOptions options, ProgressContext progress) { if (document == null) { throw new ArgumentNullException("document"); } if (destinationFile == null) { throw new ArgumentNullException("destinationFile"); } if (progress == null) { throw new ArgumentNullException("progress"); } try { if (OS.Log.IsInfoEnabled) { OS.Log.LogInfo("Decrypting to '{0}'.".InvariantFormat(destinationFile.Name)); } using (Stream destinationStream = destinationFile.OpenWrite()) { document.DecryptTo(destinationStream, progress); } if (OS.Log.IsInfoEnabled) { OS.Log.LogInfo("Decrypted to '{0}'.".InvariantFormat(destinationFile.Name)); } } catch (OperationCanceledException) { if (destinationFile.Exists) { AxCryptFile.Wipe(destinationFile, progress); } throw; } if (options.HasMask(AxCryptOptions.SetFileTimes)) { DocumentHeaders headers = document.DocumentHeaders; destinationFile.SetFileTimes(headers.CreationTimeUtc, headers.LastAccessTimeUtc, headers.LastWriteTimeUtc); } }
public static void TestHmac() { using (Stream inputStream = FakeRuntimeFileInfo.ExpandableMemoryStream(Resources.helloworld_key_a_txt)) { using (AxCryptReader axCryptReader = new AxCryptStreamReader(inputStream)) { Assert.Throws <InvalidOperationException>(() => { if (axCryptReader.Hmac == null) { } }, "The reader is not positioned properly to get the HMAC."); Passphrase passphrase = new Passphrase("a"); DocumentHeaders documentHeaders = new DocumentHeaders(passphrase.DerivedPassphrase); bool keyIsOk = documentHeaders.Load(axCryptReader); Assert.That(keyIsOk, Is.True, "The passphrase provided is correct!"); using (Stream encrypedDataStream = axCryptReader.CreateEncryptedDataStream(documentHeaders.HmacSubkey.Key, documentHeaders.CipherTextLength, new ProgressContext())) { Assert.Throws <InvalidOperationException>(() => { if (axCryptReader.Hmac == null) { } }, "We have not read the encrypted data yet."); Assert.That(axCryptReader.Read(), Is.False, "The reader should be at end of stream now, and Read() should return false."); encrypedDataStream.CopyTo(Stream.Null, 4096); Assert.That(documentHeaders.Hmac, Is.EqualTo(axCryptReader.Hmac), "The HMAC should be correct."); axCryptReader.Dispose(); Assert.Throws <ObjectDisposedException>(() => { DataHmac disposedHmac = axCryptReader.Hmac; Object.Equals(disposedHmac, null); }, "The reader is disposed."); } } } }
public static void TestSimpleEncryptToWithoutCompression() { DateTime creationTimeUtc = new DateTime(2012, 1, 1, 1, 2, 3, DateTimeKind.Utc); DateTime lastAccessTimeUtc = creationTimeUtc + new TimeSpan(1, 0, 0); DateTime lastWriteTimeUtc = creationTimeUtc + new TimeSpan(2, 0, 0);; using (Stream inputStream = FakeRuntimeFileInfo.ExpandableMemoryStream(Encoding.UTF8.GetBytes("AxCrypt is Great!"))) { using (Stream outputStream = new MemoryStream()) { using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); DocumentHeaders headers = new DocumentHeaders(passphrase.DerivedPassphrase); headers.FileName = "MyFile.txt"; headers.CreationTimeUtc = creationTimeUtc; headers.LastAccessTimeUtc = lastAccessTimeUtc; headers.LastWriteTimeUtc = lastWriteTimeUtc; document.DocumentHeaders = headers; document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.EncryptWithoutCompression, new ProgressContext()); } outputStream.Position = 0; using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); bool keyIsOk = document.Load(outputStream, passphrase.DerivedPassphrase); Assert.That(keyIsOk, Is.True, "The passphrase provided is correct!"); Assert.That(document.DocumentHeaders.FileName, Is.EqualTo("MyFile.txt")); Assert.That(document.DocumentHeaders.CreationTimeUtc, Is.EqualTo(creationTimeUtc)); Assert.That(document.DocumentHeaders.LastAccessTimeUtc, Is.EqualTo(lastAccessTimeUtc)); Assert.That(document.DocumentHeaders.LastWriteTimeUtc, Is.EqualTo(lastWriteTimeUtc)); using (MemoryStream plaintextStream = new MemoryStream()) { document.DecryptTo(plaintextStream, new ProgressContext()); Assert.That(document.DocumentHeaders.UncompressedLength, Is.EqualTo(-1), "'AxCrypt is Great!' should not return a value at all for uncompressed, since it was not compressed."); Assert.That(document.DocumentHeaders.PlaintextLength, Is.EqualTo(17), "'AxCrypt is Great!' is 17 bytes plaintext length."); Assert.That(Encoding.ASCII.GetString(plaintextStream.GetBuffer(), 0, (int)plaintextStream.Length), Is.EqualTo("AxCrypt is Great!"), "Unexpected result of decryption."); } } } } }
/// <summary> /// Encrypt a file /// </summary> /// <param name="file">The file to encrypt</param> /// <param name="destination">The destination file</param> /// <remarks>It is the callers responsibility to ensure that the source file exists, that the destination file /// does not exist and can be created etc.</remarks> public static void Encrypt(IRuntimeFileInfo sourceFile, IRuntimeFileInfo destinationFile, Passphrase passphrase, AxCryptOptions options, ProgressContext progress) { if (sourceFile == null) { throw new ArgumentNullException("sourceFile"); } if (destinationFile == null) { throw new ArgumentNullException("destinationFile"); } if (passphrase == null) { throw new ArgumentNullException("passphrase"); } if (progress == null) { throw new ArgumentNullException("progress"); } using (Stream sourceStream = sourceFile.OpenRead()) { using (Stream destinationStream = destinationFile.OpenWrite()) { using (AxCryptDocument document = new AxCryptDocument()) { DocumentHeaders headers = new DocumentHeaders(passphrase.DerivedPassphrase); headers.FileName = sourceFile.Name; headers.CreationTimeUtc = sourceFile.CreationTimeUtc; headers.LastAccessTimeUtc = sourceFile.LastAccessTimeUtc; headers.LastWriteTimeUtc = sourceFile.LastWriteTimeUtc; document.DocumentHeaders = headers; document.EncryptTo(headers, sourceStream, destinationStream, options, progress); } } if (options.HasMask(AxCryptOptions.SetFileTimes)) { destinationFile.SetFileTimes(sourceFile.CreationTimeUtc, sourceFile.LastAccessTimeUtc, sourceFile.LastWriteTimeUtc); } } }
/// <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); }
/// <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; } }
/// <summary> /// Decrypts the encrypted data to the given stream /// </summary> /// <param name="outputPlaintextStream">The resulting plain text stream.</param> public void DecryptTo(Stream outputPlaintextStream) { if (outputPlaintextStream == null) { throw new ArgumentNullException("outputPlaintextStream"); } if (!PassphraseIsValid) { throw new InternalErrorException("Passphrase is not valid!"); } using (Stream encryptedDataStream = CreateEncryptedDataStream()) { encryptedDataStream.DecryptTo(outputPlaintextStream, DocumentHeaders.DataCrypto().DecryptingTransform(), DocumentHeaders.IsCompressed); } DocumentHeaders.Trailers(_reader); if (DocumentHeaders.HmacCalculator.Hmac != DocumentHeaders.Hmac) { throw new Axantum.AxCrypt.Core.Runtime.IncorrectDataException("HMAC validation error.", ErrorStatus.HmacValidationError); } }
public static void TestInvalidArguments() { using (Stream inputStream = FakeRuntimeFileInfo.ExpandableMemoryStream(Encoding.UTF8.GetBytes("AxCrypt is Great!"))) { using (Stream outputStream = new MemoryStream()) { using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); DocumentHeaders headers = new DocumentHeaders(passphrase.DerivedPassphrase); Assert.Throws<ArgumentNullException>(() => { document.EncryptTo(null, inputStream, outputStream, AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws<ArgumentNullException>(() => { document.EncryptTo(headers, null, outputStream, AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws<ArgumentNullException>(() => { document.EncryptTo(headers, inputStream, null, AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws<ArgumentNullException>(() => { document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.EncryptWithCompression, null); }); Assert.Throws<ArgumentException>(() => { document.EncryptTo(headers, inputStream, new NonSeekableStream(), AxCryptOptions.EncryptWithCompression, new ProgressContext()); }); Assert.Throws<ArgumentException>(() => { document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.EncryptWithCompression | AxCryptOptions.EncryptWithoutCompression, new ProgressContext()); }); Assert.Throws<ArgumentException>(() => { document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.None, new ProgressContext()); }); Assert.Throws<ArgumentNullException>(() => { document.CopyEncryptedTo(null, outputStream, new ProgressContext()); }); Assert.Throws<ArgumentNullException>(() => { document.CopyEncryptedTo(headers, null, new ProgressContext()); }); Assert.Throws<ArgumentException>(() => { document.CopyEncryptedTo(headers, new NonSeekableStream(), new ProgressContext()); }); Assert.Throws<InternalErrorException>(() => { document.CopyEncryptedTo(headers, outputStream, new ProgressContext()); }); } } } }
public static void TestSimpleEncryptToWithoutCompression() { DateTime creationTimeUtc = new DateTime(2012, 1, 1, 1, 2, 3, DateTimeKind.Utc); DateTime lastAccessTimeUtc = creationTimeUtc + new TimeSpan(1, 0, 0); DateTime lastWriteTimeUtc = creationTimeUtc + new TimeSpan(2, 0, 0); ; using (Stream inputStream = FakeRuntimeFileInfo.ExpandableMemoryStream(Encoding.UTF8.GetBytes("AxCrypt is Great!"))) { using (Stream outputStream = new MemoryStream()) { using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); DocumentHeaders headers = new DocumentHeaders(passphrase.DerivedPassphrase); headers.FileName = "MyFile.txt"; headers.CreationTimeUtc = creationTimeUtc; headers.LastAccessTimeUtc = lastAccessTimeUtc; headers.LastWriteTimeUtc = lastWriteTimeUtc; document.DocumentHeaders = headers; document.EncryptTo(headers, inputStream, outputStream, AxCryptOptions.EncryptWithoutCompression, new ProgressContext()); } outputStream.Position = 0; using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); bool keyIsOk = document.Load(outputStream, passphrase.DerivedPassphrase); Assert.That(keyIsOk, Is.True, "The passphrase provided is correct!"); Assert.That(document.DocumentHeaders.FileName, Is.EqualTo("MyFile.txt")); Assert.That(document.DocumentHeaders.CreationTimeUtc, Is.EqualTo(creationTimeUtc)); Assert.That(document.DocumentHeaders.LastAccessTimeUtc, Is.EqualTo(lastAccessTimeUtc)); Assert.That(document.DocumentHeaders.LastWriteTimeUtc, Is.EqualTo(lastWriteTimeUtc)); using (MemoryStream plaintextStream = new MemoryStream()) { document.DecryptTo(plaintextStream, new ProgressContext()); Assert.That(document.DocumentHeaders.UncompressedLength, Is.EqualTo(-1), "'AxCrypt is Great!' should not return a value at all for uncompressed, since it was not compressed."); Assert.That(document.DocumentHeaders.PlaintextLength, Is.EqualTo(17), "'AxCrypt is Great!' is 17 bytes plaintext length."); Assert.That(Encoding.ASCII.GetString(plaintextStream.GetBuffer(), 0, (int)plaintextStream.Length), Is.EqualTo("AxCrypt is Great!"), "Unexpected result of decryption."); } } } } }
public static void TestInvalidHmacInCopyEncryptedTo() { using (AxCryptDocument document = new AxCryptDocument()) { Passphrase passphrase = new Passphrase("a"); bool keyIsOk = document.Load(FakeRuntimeFileInfo.ExpandableMemoryStream(Resources.helloworld_key_a_txt), passphrase.DerivedPassphrase); Assert.That(keyIsOk, Is.True, "The passphrase provided is correct and should work!"); Passphrase newPassphrase = new Passphrase("b"); using (Stream changedStream = new MemoryStream()) { DocumentHeaders outputDocumentHeaders = new DocumentHeaders(document.DocumentHeaders); outputDocumentHeaders.SetCurrentVersion(); outputDocumentHeaders.RewrapMasterKey(newPassphrase.DerivedPassphrase); byte[] modifiedHmacBytes = document.DocumentHeaders.Hmac.GetBytes(); modifiedHmacBytes[0] += 1; document.DocumentHeaders.Hmac = new DataHmac(modifiedHmacBytes); Assert.Throws<Axantum.AxCrypt.Core.Runtime.InvalidDataException>(() => { document.CopyEncryptedTo(outputDocumentHeaders, changedStream, new ProgressContext()); }); } } }
public static void TestHmac() { using (Stream inputStream = FakeRuntimeFileInfo.ExpandableMemoryStream(Resources.helloworld_key_a_txt)) { using (AxCryptReader axCryptReader = new AxCryptStreamReader(inputStream)) { Assert.Throws<InvalidOperationException>(() => { if (axCryptReader.Hmac == null) { } }, "The reader is not positioned properly to get the HMAC."); Passphrase passphrase = new Passphrase("a"); DocumentHeaders documentHeaders = new DocumentHeaders(passphrase.DerivedPassphrase); bool keyIsOk = documentHeaders.Load(axCryptReader); Assert.That(keyIsOk, Is.True, "The passphrase provided is correct!"); using (Stream encrypedDataStream = axCryptReader.CreateEncryptedDataStream(documentHeaders.HmacSubkey.Key, documentHeaders.CipherTextLength, new ProgressContext())) { Assert.Throws<InvalidOperationException>(() => { if (axCryptReader.Hmac == null) { } }, "We have not read the encrypted data yet."); Assert.That(axCryptReader.Read(), Is.False, "The reader should be at end of stream now, and Read() should return false."); encrypedDataStream.CopyTo(Stream.Null, 4096); Assert.That(documentHeaders.Hmac, Is.EqualTo(axCryptReader.Hmac), "The HMAC should be correct."); axCryptReader.Dispose(); Assert.Throws<ObjectDisposedException>(() => { DataHmac disposedHmac = axCryptReader.Hmac; Object.Equals(disposedHmac, null); }, "The reader is disposed."); } } } }
/// <summary> /// Loads an AxCrypt file from the specified reader. After this, the reader is positioned to /// read encrypted data. /// </summary> /// <param name="stream">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> public bool Load(Stream stream, AesKey key) { _reader = AxCryptReader.Create(stream); DocumentHeaders documentHeaders = new DocumentHeaders(key); PassphraseIsValid = documentHeaders.Load(_reader); if (PassphraseIsValid) { DocumentHeaders = documentHeaders; } return PassphraseIsValid; }
/// <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; } }
public static void TestInvalidItemType() { using (MemoryStream inputStream = new MemoryStream()) { AxCrypt1Guid.Write(inputStream); new PreambleHeaderBlock().Write(inputStream); inputStream.Position = 0; using (AxCryptReaderForTest axCryptReader = new AxCryptReaderForTest(inputStream)) { DocumentHeaders documentHeaders = new DocumentHeaders(new AesKey()); Assert.Throws<InternalErrorException>(() => { documentHeaders.Load(axCryptReader); }); } } }