diff --git a/.gitignore b/.gitignore index b44058613..c54f99d73 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ bin/ *.user TestArchives/Scratch/ TestArchives/Scratch2/ +TestResults/ *.nupkg diff --git a/SharpCompress.Test/Rar/RarReaderTests.cs b/SharpCompress.Test/Rar/RarReaderTests.cs index a0fa2b720..7da0d1393 100644 --- a/SharpCompress.Test/Rar/RarReaderTests.cs +++ b/SharpCompress.Test/Rar/RarReaderTests.cs @@ -79,6 +79,38 @@ public void Rar_Reader() Read("Rar.rar", CompressionType.Rar); } + [TestMethod] + public void Rar_EncryptedFileAndHeader_Reader() + { + ReadRar("Rar.encrypted_filesAndHeader.rar", "test"); + + } + + [TestMethod] + public void Rar_EncryptedFileOnly_Reader() + { + ReadRar("Rar.encrypted_filesOnly.rar", "test"); + + } + + private void ReadRar(string testArchive, string password) + { + ResetScratch(); + using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive))) + using (var reader = RarReader.Open(stream, password)) + { + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar); + reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite); + } + } + } + VerifyFiles(); + } + [TestMethod] public void Rar_Entry_Stream() { diff --git a/SharpCompress.Test/Rar/Unit/RarHeaderFactoryTest.cs b/SharpCompress.Test/Rar/Unit/RarHeaderFactoryTest.cs new file mode 100644 index 000000000..45e13526e --- /dev/null +++ b/SharpCompress.Test/Rar/Unit/RarHeaderFactoryTest.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using System.Net.Security; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SharpCompress.Common; +using SharpCompress.Common.Rar.Headers; +using SharpCompress.IO; + +namespace SharpCompress.Test.Rar.Unit +{ + /// + /// Summary description for RarFactoryReaderTest + /// + [TestClass] + public class RarHeaderFactoryTest : TestBase + { + private RarHeaderFactory rarHeaderFactory; + + [TestInitialize] + public void Initialize() + { + ResetScratch(); + rarHeaderFactory = new RarHeaderFactory(StreamingMode.Seekable, Options.KeepStreamsOpen); + } + + + [TestMethod] + public void ReadHeaders_RecognizeEncryptedFlag() + { + + ReadEncryptedFlag("Rar.Encrypted_filesAndHeader.rar", true); + + + + } + + private void ReadEncryptedFlag(string testArchive, bool isEncrypted) + { + using (var stream = GetReaderStream(testArchive)) + foreach (var header in rarHeaderFactory.ReadHeaders(stream)) + { + if (header.HeaderType == HeaderType.ArchiveHeader) + { + Assert.AreEqual(isEncrypted, rarHeaderFactory.IsEncrypted); + break; + } + } + } + + [TestMethod] + public void ReadHeaders_RecognizeNoEncryptedFlag() + { + ReadEncryptedFlag("Rar.rar", false); + } + + private FileStream GetReaderStream(string testArchive) + { + return new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), + FileMode.Open); + } + } +} diff --git a/SharpCompress.Test/SharpCompress.Test.csproj b/SharpCompress.Test/SharpCompress.Test.csproj index b9ce86c88..7a342ffb7 100644 --- a/SharpCompress.Test/SharpCompress.Test.csproj +++ b/SharpCompress.Test/SharpCompress.Test.csproj @@ -56,6 +56,7 @@ + diff --git a/SharpCompress.Test/TestBase.cs b/SharpCompress.Test/TestBase.cs index 720ed4d85..7726dd590 100644 --- a/SharpCompress.Test/TestBase.cs +++ b/SharpCompress.Test/TestBase.cs @@ -9,7 +9,7 @@ namespace SharpCompress.Test { public class TestBase { - protected const string TEST_BASE_PATH = @"C:\Git\sharpcompress"; + protected const string TEST_BASE_PATH = @"D:\Codes\sharpcompress"; protected static readonly string TEST_ARCHIVES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Archives"); protected static readonly string ORIGINAL_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Original"); protected static readonly string MISC_TEST_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "MiscTest"); @@ -122,14 +122,14 @@ protected void CompareFilesByPath(string file1, string file2) using (var file2Stream = File.OpenRead(file2)) { Assert.AreEqual(file1Stream.Length, file2Stream.Length); - int byte1 = 0; int byte2 = 0; - while (byte1 != -1) + for (int counter = 0; byte1 != -1; counter++ ) { byte1 = file1Stream.ReadByte(); byte2 = file2Stream.ReadByte(); - Assert.AreEqual(byte1, byte2); + if (byte1 != byte2) Assert.AreEqual(byte1, byte2, string.Format("Byte {0} differ between {1} and {2}", + counter, file1, file2)); } } } diff --git a/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs b/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs index 57ee6a8b6..7c79f0720 100644 --- a/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs +++ b/SharpCompress/Common/Rar/Headers/ArchiveHeader.cs @@ -27,5 +27,10 @@ internal ArchiveFlags ArchiveHeaderFlags internal int PosAv { get; private set; } internal byte EncryptionVersion { get; private set; } + + public bool HasPassword + { + get { return ArchiveHeaderFlags.HasFlag(ArchiveFlags.PASSWORD); } + } } } \ No newline at end of file diff --git a/SharpCompress/Common/Rar/Headers/RarHeader.cs b/SharpCompress/Common/Rar/Headers/RarHeader.cs index 260aef3f3..ae7957483 100644 --- a/SharpCompress/Common/Rar/Headers/RarHeader.cs +++ b/SharpCompress/Common/Rar/Headers/RarHeader.cs @@ -35,11 +35,10 @@ internal static RarHeader Create(MarkingBinaryReader reader) return null; } } - protected virtual void ReadFromReader(MarkingBinaryReader reader) { HeadCRC = reader.ReadInt16(); - HeaderType = (HeaderType) (int) (reader.ReadByte() & 0xff); + HeaderType = (HeaderType)(int)(reader.ReadByte() & 0xff); Flags = reader.ReadInt16(); HeaderSize = reader.ReadInt16(); if (FlagUtility.HasFlag(Flags, LONG_BLOCK)) @@ -58,7 +57,7 @@ internal T PromoteHeader(MarkingBinaryReader reader) header.ReadFromReader(reader); header.ReadBytes += reader.CurrentReadByteCount; - int headerSizeDiff = header.HeaderSize - (int) header.ReadBytes; + int headerSizeDiff = header.HeaderSize - (int)header.ReadBytes; if (headerSizeDiff > 0) { diff --git a/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 19f731e99..7ff4a17d1 100644 --- a/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs +++ b/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using SharpCompress.Compressor.Rar; using SharpCompress.IO; namespace SharpCompress.Common.Rar.Headers @@ -9,22 +10,26 @@ internal class RarHeaderFactory { private int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136 - internal RarHeaderFactory(StreamingMode mode, Options options) + internal RarHeaderFactory(StreamingMode mode, Options options, string password = null) { StreamingMode = mode; Options = options; + Password = password; } private Options Options { get; set; } - + public string Password { get; private set; } internal StreamingMode StreamingMode { get; private set; } + internal bool IsEncrypted { get; set; } + internal IEnumerable ReadHeaders(Stream stream) { if (Options.HasFlag(Options.LookForHeader)) { stream = CheckSFX(stream); } + RarHeader header; while ((header = ReadNextHeader(stream)) != null) { @@ -107,9 +112,19 @@ private RewindableStream GetRewindableStream(Stream stream) return rewindableStream; } + private RarHeader ReadNextHeader(Stream stream) { - MarkingBinaryReader reader = new MarkingBinaryReader(stream); + MarkingBinaryReader reader = new MarkingBinaryReader(stream, Password); + + if (IsEncrypted) + { + reader.Salt = null; + reader.SkipQueue(); + byte[] salt = reader.ReadBytes(8); + reader.Salt = salt; + + } RarHeader header = RarHeader.Create(reader); if (header == null) { @@ -119,7 +134,9 @@ private RarHeader ReadNextHeader(Stream stream) { case HeaderType.ArchiveHeader: { - return header.PromoteHeader(reader); + var ah = header.PromoteHeader(reader); + IsEncrypted = ah.HasPassword; + return ah; } case HeaderType.MarkHeader: { @@ -164,7 +181,7 @@ private RarHeader ReadNextHeader(Stream stream) { ReadOnlySubStream ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize); - fh.PackedStream = ms; + fh.PackedStream = fh.Salt == null? (Stream) ms : new RarCryptoWrapper(ms, Password) { Salt = fh.Salt}; } break; default: diff --git a/SharpCompress/Common/Rar/RarCryptoWrapper.cs b/SharpCompress/Common/Rar/RarCryptoWrapper.cs new file mode 100644 index 000000000..fe1fab4cb --- /dev/null +++ b/SharpCompress/Common/Rar/RarCryptoWrapper.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace SharpCompress.Common.Rar +{ + internal class RarCryptoWrapper : Stream + { + private readonly Stream actualStream; + private byte[] salt; + private RarRijndael rijndael; + private readonly string password; + private readonly Queue data = new Queue(); + + public RarCryptoWrapper(Stream actualStream, string password) + { + this.actualStream = actualStream; + this.password = password; + } + + internal byte[] Salt + { + get { return salt; } + set + { + salt = value; + if (value != null) InitializeAes(); + } + } + + private void InitializeAes() + { + rijndael = RarRijndael.InitializeFrom(password, salt); + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (Salt == null) return actualStream.Read(buffer, offset, count); + return ReadAndDecrypt(buffer, offset, count); + } + + public int ReadAndDecrypt(byte[] buffer, int offset, int count) + { + int queueSize = data.Count; + int sizeToRead = count - queueSize; + + if (sizeToRead > 0) + { + int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); + for (int i = 0; i < alignedSize/16; i++) + { + //long ax = System.currentTimeMillis(); + byte[] cipherText = new byte[RarRijndael.CryptoBlockSize]; + actualStream.Read(cipherText, 0, RarRijndael.CryptoBlockSize); + + var readBytes = rijndael.ProcessBlock(cipherText); + foreach(var readByte in readBytes) + data.Enqueue(readByte); + + } + + for (int i = 0; i < count; i++) + buffer[offset+i] = data.Dequeue(); + } + return count; + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override bool CanRead + { + get { throw new NotImplementedException(); } + } + + public override bool CanSeek + { + get { throw new NotImplementedException(); } + } + + public override bool CanWrite + { + get { throw new NotImplementedException(); } + } + + public override long Length + { + get { throw new NotImplementedException(); } + } + + public override long Position { get; set; } + + protected override void Dispose(bool disposing) + { + if(rijndael != null) rijndael.Dispose(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/SharpCompress/Common/Rar/RarRijndael.cs b/SharpCompress/Common/Rar/RarRijndael.cs new file mode 100644 index 000000000..4ae96be7b --- /dev/null +++ b/SharpCompress/Common/Rar/RarRijndael.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace SharpCompress.Common.Rar +{ + internal class RarRijndael : IDisposable + { + private readonly string password; + private readonly byte[] salt; + private byte[] aesInitializationVector; + private Rijndael rijndael; + + private RarRijndael(string password, byte[] salt) + { + this.password = password; + this.salt = salt; + } + + internal const int CryptoBlockSize = 16; + + private void Initialize() + { + + rijndael = new RijndaelManaged() { Padding = PaddingMode.None }; + aesInitializationVector = new byte[CryptoBlockSize]; + int rawLength = 2 * password.Length; + byte[] rawPassword = new byte[rawLength + 8]; + byte[] passwordBytes = Encoding.UTF8.GetBytes(password); + for (int i = 0; i < password.Length; i++) + { + rawPassword[i * 2] = passwordBytes[i]; + rawPassword[i * 2 + 1] = 0; + } + for (int i = 0; i < salt.Length; i++) + { + rawPassword[i + rawLength] = salt[i]; + } + + SHA1 sha = new SHA1CryptoServiceProvider(); + + const int noOfRounds = (1 << 18); + IList bytes = new List(); + byte[] digest; + + //TODO slow code below, find ways to optimize + for (int i = 0; i < noOfRounds; i++) + { + bytes.AddRange(rawPassword); + + bytes.AddRange(new[] { (byte)i, (byte)(i >> 8), (byte)(i >> CryptoBlockSize) }); + if (i % (noOfRounds / CryptoBlockSize) == 0) + { + digest = sha.ComputeHash(bytes.ToArray()); + aesInitializationVector[i / (noOfRounds / CryptoBlockSize)] = digest[19]; + } + } + + digest = sha.ComputeHash(bytes.ToArray()); + //slow code ends + + byte[] aesKey = new byte[CryptoBlockSize]; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + aesKey[i * 4 + j] = (byte) + (((digest[i * 4] * 0x1000000) & 0xff000000 | + (uint)((digest[i * 4 + 1] * 0x10000) & 0xff0000) | + (uint)((digest[i * 4 + 2] * 0x100) & 0xff00) | + (uint)(digest[i * 4 + 3] & 0xff)) >> (j * 8)); + + rijndael.IV = new byte[CryptoBlockSize]; + rijndael.Key = aesKey; + rijndael.BlockSize = CryptoBlockSize * 8; + + } + + public static RarRijndael InitializeFrom(string password, byte[] salt) + { + var rijndael = new RarRijndael(password, salt); + rijndael.Initialize(); + return rijndael; + } + + public byte[] ProcessBlock(byte[] cipherText) + { + var plainText = new byte[CryptoBlockSize]; + var decryptedBytes = new List(); + var decryptor = rijndael.CreateDecryptor(); + using (var msDecrypt = new MemoryStream(cipherText)) + { + using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) + { + csDecrypt.ReadFully(plainText); + } + } + + for (int j = 0; j < plainText.Length; j++) + decryptedBytes.Add((byte)(plainText[j] ^ aesInitializationVector[j % 16])); //32:114, 33:101 + + for (int j = 0; j < aesInitializationVector.Length; j++) + aesInitializationVector[j] = cipherText[j]; + return decryptedBytes.ToArray(); + } + + public void Dispose() + { + rijndael.Dispose(); + } + } +} diff --git a/SharpCompress/Common/Rar/RarVolume.cs b/SharpCompress/Common/Rar/RarVolume.cs index 1d5d0556f..05480d16c 100644 --- a/SharpCompress/Common/Rar/RarVolume.cs +++ b/SharpCompress/Common/Rar/RarVolume.cs @@ -13,11 +13,18 @@ namespace SharpCompress.Common.Rar public abstract class RarVolume : Volume { private readonly RarHeaderFactory headerFactory; + public string Password { get; set; } - internal RarVolume(StreamingMode mode, Stream stream, Options options) + internal RarVolume(StreamingMode mode, Stream stream, Options options) + : this(mode, stream, null, options) + { + + } + + internal RarVolume(StreamingMode mode, Stream stream, string password, Options options) : base(stream, options) { - headerFactory = new RarHeaderFactory(mode, options); + headerFactory = new RarHeaderFactory(mode, options, password); } internal StreamingMode Mode diff --git a/SharpCompress/IO/MarkingBinaryReader.cs b/SharpCompress/IO/MarkingBinaryReader.cs index f01546410..9b61f24f3 100644 --- a/SharpCompress/IO/MarkingBinaryReader.cs +++ b/SharpCompress/IO/MarkingBinaryReader.cs @@ -1,17 +1,43 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using SharpCompress.Common.Rar; namespace SharpCompress.IO { internal class MarkingBinaryReader : BinaryReader { - public MarkingBinaryReader(Stream stream) + private byte[] _salt; + private readonly string _password; + private RarRijndael _rijndael; + private Queue _data = new Queue(); + + public MarkingBinaryReader(Stream stream, string password = null) : base(stream) { + _password = password; } public long CurrentReadByteCount { get; private set; } + internal byte[] Salt + { + get { return _salt; } + set + { + _salt = value; + if (value != null) InitializeAes(); + + } + } + + private void InitializeAes() + { + _rijndael = RarRijndael.InitializeFrom(_password, _salt); + } + + public void Mark() { CurrentReadByteCount = 0; @@ -42,14 +68,49 @@ public override bool ReadBoolean() public override byte ReadByte() { - CurrentReadByteCount++; - return base.ReadByte(); + return ReadBytes(1).Single(); } public override byte[] ReadBytes(int count) { CurrentReadByteCount += count; - return base.ReadBytes(count); + return UseEncryption ? + ReadAndDecryptBytes(count) + : base.ReadBytes(count); + } + + protected bool UseEncryption + { + get { return Salt != null; } + } + + private byte[] ReadAndDecryptBytes(int count) + { + int queueSize = _data.Count; + int sizeToRead = count - queueSize; + + if (sizeToRead > 0) + { + int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf); + for (int i = 0; i < alignedSize / 16; i++) + { + //long ax = System.currentTimeMillis(); + byte[] cipherText = base.ReadBytes(16); + var readBytes = _rijndael.ProcessBlock(cipherText); + foreach (var readByte in readBytes) + _data.Enqueue(readByte); + + } + + } + + var decryptedBytes = new byte[count]; + + for (int i = 0; i < count; i++) + { + decryptedBytes[i] = _data.Dequeue(); + } + return decryptedBytes; } public override char ReadChar() @@ -65,45 +126,49 @@ public override char[] ReadChars(int count) #if !PORTABLE public override decimal ReadDecimal() { - CurrentReadByteCount += 16; - return base.ReadDecimal(); + return ByteArrayToDecimal(ReadBytes(16), 0); + } + + private decimal ByteArrayToDecimal(byte[] src, int offset) + { + //http://stackoverflow.com/a/16984356/385387 + var i1 = BitConverter.ToInt32(src, offset); + var i2 = BitConverter.ToInt32(src, offset + 4); + var i3 = BitConverter.ToInt32(src, offset + 8); + var i4 = BitConverter.ToInt32(src, offset + 12); + + return new decimal(new[] { i1, i2, i3, i4 }); } #endif public override double ReadDouble() { - CurrentReadByteCount += 8; - return base.ReadDouble(); + return BitConverter.ToDouble(ReadBytes(8), 0); } public override short ReadInt16() { - CurrentReadByteCount += 2; - return base.ReadInt16(); + return BitConverter.ToInt16(ReadBytes(2), 0); } public override int ReadInt32() { - CurrentReadByteCount += 4; - return base.ReadInt32(); + return BitConverter.ToInt32(ReadBytes(4), 0); } public override long ReadInt64() { - CurrentReadByteCount += 8; - return base.ReadInt64(); + return BitConverter.ToInt64(ReadBytes(8), 0); } public override sbyte ReadSByte() { - CurrentReadByteCount++; - return base.ReadSByte(); + return (sbyte)ReadByte(); } public override float ReadSingle() { - CurrentReadByteCount += 4; - return base.ReadSingle(); + return BitConverter.ToSingle(ReadBytes(4), 0); } public override string ReadString() @@ -113,20 +178,29 @@ public override string ReadString() public override ushort ReadUInt16() { - CurrentReadByteCount += 2; - return base.ReadUInt16(); + return BitConverter.ToUInt16(ReadBytes(2), 0); } public override uint ReadUInt32() { - CurrentReadByteCount += 4; - return base.ReadUInt32(); + return BitConverter.ToUInt32(ReadBytes(4), 0); } public override ulong ReadUInt64() { - CurrentReadByteCount += 8; - return base.ReadUInt64(); + return BitConverter.ToUInt64(ReadBytes(8), 0); + } + + public void ClearQueue() + { + _data.Clear(); + } + + public void SkipQueue() + { + var position = BaseStream.Position; + BaseStream.Position = position + _data.Count; + ClearQueue(); } } } \ No newline at end of file diff --git a/SharpCompress/IO/NonDisposingStream.cs b/SharpCompress/IO/NonDisposingStream.cs index d7eb7db93..95094d1f8 100644 --- a/SharpCompress/IO/NonDisposingStream.cs +++ b/SharpCompress/IO/NonDisposingStream.cs @@ -11,10 +11,7 @@ public NonDisposingStream(Stream stream) protected override void Dispose(bool disposing) { - if (disposing) - { - //Stream.Dispose(); - } + //don't dispose anything } public Stream Stream { get; private set; } diff --git a/SharpCompress/Reader/Rar/RarReader.cs b/SharpCompress/Reader/Rar/RarReader.cs index cf26e06d1..68ee8b2fb 100644 --- a/SharpCompress/Reader/Rar/RarReader.cs +++ b/SharpCompress/Reader/Rar/RarReader.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using SharpCompress.Common; @@ -12,6 +13,7 @@ namespace SharpCompress.Reader.Rar /// public abstract class RarReader : AbstractReader { + public string Password { get; set; } private RarVolume volume; private readonly Unpack pack = new Unpack(); @@ -37,8 +39,7 @@ public override RarVolume Volume /// public static RarReader Open(Stream stream, Options options = Options.KeepStreamsOpen) { - stream.CheckNotNull("stream"); - return new SingleVolumeRarReader(stream, options); + return Open(stream, null, options); } /// @@ -57,7 +58,7 @@ public static RarReader Open(IEnumerable streams, Options options = Opti internal override IEnumerable GetEntries(Stream stream) { - volume = new RarReaderVolume(stream, Options); + volume = new RarReaderVolume(stream, Password, Options); foreach (RarFilePart fp in volume.ReadFileParts()) { ValidateArchive(volume); @@ -76,5 +77,11 @@ protected override EntryStream GetEntryStream() new MultiVolumeReadOnlyStream( CreateFilePartEnumerableForCurrentEntry().Cast(), this))); } + + public static RarReader Open(Stream stream, string password, Options options = Options.KeepStreamsOpen) + { + stream.CheckNotNull("stream"); + return new SingleVolumeRarReader(stream, password, options); + } } } \ No newline at end of file diff --git a/SharpCompress/Reader/Rar/RarReaderVolume.cs b/SharpCompress/Reader/Rar/RarReaderVolume.cs index d2b6368ec..d24e63bdb 100644 --- a/SharpCompress/Reader/Rar/RarReaderVolume.cs +++ b/SharpCompress/Reader/Rar/RarReaderVolume.cs @@ -9,8 +9,10 @@ namespace SharpCompress.Reader.Rar { public class RarReaderVolume : RarVolume { - internal RarReaderVolume(Stream stream, Options options) - : base(StreamingMode.Streaming, stream, options) + + + internal RarReaderVolume(Stream stream, string password, Options options) + : base(StreamingMode.Streaming, stream, password, options) { } diff --git a/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs b/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs index 028e628e2..2fe2b7f0f 100644 --- a/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs +++ b/SharpCompress/Reader/Rar/SingleVolumeRarReader.cs @@ -7,11 +7,13 @@ namespace SharpCompress.Reader.Rar { internal class SingleVolumeRarReader : RarReader { + private readonly Stream stream; - internal SingleVolumeRarReader(Stream stream, Options options) + internal SingleVolumeRarReader(Stream stream, string password, Options options) : base(options) { + Password = password; this.stream = stream; } diff --git a/SharpCompress/SharpCompress.Portable.csproj b/SharpCompress/SharpCompress.Portable.csproj index 7fcb1f892..ed8a5edee 100644 --- a/SharpCompress/SharpCompress.Portable.csproj +++ b/SharpCompress/SharpCompress.Portable.csproj @@ -113,6 +113,7 @@ + diff --git a/SharpCompress/SharpCompress.csproj b/SharpCompress/SharpCompress.csproj index d412ac803..67dd60702 100644 --- a/SharpCompress/SharpCompress.csproj +++ b/SharpCompress/SharpCompress.csproj @@ -126,6 +126,8 @@ + + diff --git a/TestArchives/Archives/Rar.encrypted_filesAndHeader.rar b/TestArchives/Archives/Rar.encrypted_filesAndHeader.rar new file mode 100644 index 000000000..d055dc77a Binary files /dev/null and b/TestArchives/Archives/Rar.encrypted_filesAndHeader.rar differ diff --git a/TestArchives/Archives/Rar.encrypted_filesOnly.rar b/TestArchives/Archives/Rar.encrypted_filesOnly.rar new file mode 100644 index 000000000..d4ff767b6 Binary files /dev/null and b/TestArchives/Archives/Rar.encrypted_filesOnly.rar differ