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