Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

verify RAR crc on header and file data #220

Merged
merged 1 commit into from
Apr 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions src/SharpCompress/Common/Rar/Headers/RarHeader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using SharpCompress.IO;

namespace SharpCompress.Common.Rar.Headers
Expand All @@ -18,14 +19,14 @@ private void FillBase(RarHeader baseHeader)
ReadBytes = baseHeader.ReadBytes;
}

internal static RarHeader Create(MarkingBinaryReader reader)
internal static RarHeader Create(RarCrcBinaryReader reader)
{
try
{
RarHeader header = new RarHeader();

reader.Mark();
header.ReadFromReader(reader);
header.ReadStartFromReader(reader);
header.ReadBytes += reader.CurrentReadByteCount;

return header;
Expand All @@ -36,9 +37,10 @@ internal static RarHeader Create(MarkingBinaryReader reader)
}
}

protected virtual void ReadFromReader(MarkingBinaryReader reader)
private void ReadStartFromReader(RarCrcBinaryReader reader)
{
HeadCRC = reader.ReadInt16();
HeadCRC = reader.ReadUInt16();
reader.ResetCrc();
HeaderType = (HeaderType)(reader.ReadByte() & 0xff);
Flags = reader.ReadInt16();
HeaderSize = reader.ReadInt16();
Expand All @@ -48,7 +50,11 @@ protected virtual void ReadFromReader(MarkingBinaryReader reader)
}
}

internal T PromoteHeader<T>(MarkingBinaryReader reader)
protected virtual void ReadFromReader(MarkingBinaryReader reader) {
throw new NotImplementedException();
}

internal T PromoteHeader<T>(RarCrcBinaryReader reader)
where T : RarHeader, new()
{
T header = new T();
Expand All @@ -65,9 +71,21 @@ internal T PromoteHeader<T>(MarkingBinaryReader reader)
reader.ReadBytes(headerSizeDiff);
}

VerifyHeaderCrc(reader.GetCrc());

return header;
}

private void VerifyHeaderCrc(ushort crc) {
if (HeaderType != HeaderType.MarkHeader)
{
if (crc != HeadCRC)
{
throw new InvalidFormatException("rar header crc mismatch");
}
}
}

protected virtual void PostReadingBytes(MarkingBinaryReader reader)
{
}
Expand All @@ -77,7 +95,7 @@ protected virtual void PostReadingBytes(MarkingBinaryReader reader)
/// </summary>
protected long ReadBytes { get; private set; }

protected short HeadCRC { get; private set; }
protected ushort HeadCRC { get; private set; }

internal HeaderType HeaderType { get; private set; }

Expand Down
4 changes: 2 additions & 2 deletions src/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private RarHeader ReadNextHeader(Stream stream)
reader.InitializeAes(salt);
}
#else
var reader = new MarkingBinaryReader(stream);
var reader = new RarCrcBinaryReader(stream);

#endif

Expand Down Expand Up @@ -247,4 +247,4 @@ private RarHeader ReadNextHeader(Stream stream)
}
}
}
}
}
40 changes: 40 additions & 0 deletions src/SharpCompress/Common/Rar/RarCrcBinaryReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.IO;
using SharpCompress.Compressors.Rar;
using SharpCompress.IO;

namespace SharpCompress.Common.Rar {
internal class RarCrcBinaryReader : MarkingBinaryReader {
private uint currentCrc;

public RarCrcBinaryReader(Stream stream) : base(stream)
{
}

public ushort GetCrc()
{
return (ushort)~this.currentCrc;
}

public void ResetCrc()
{
this.currentCrc = 0xffffffff;
}

protected void UpdateCrc(byte b)
{
this.currentCrc = RarCRC.CheckCrc(this.currentCrc, b);
}

protected byte[] ReadBytesNoCrc(int count)
{
return base.ReadBytes(count);
}

public override byte[] ReadBytes(int count)
{
var result = base.ReadBytes(count);
this.currentCrc = RarCRC.CheckCrc(this.currentCrc, result, 0, result.Length);
return result;
}
}
}
27 changes: 24 additions & 3 deletions src/SharpCompress/Common/Rar/RarCryptoBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,36 @@

namespace SharpCompress.Common.Rar
{
internal class RarCryptoBinaryReader : MarkingBinaryReader
internal class RarCryptoBinaryReader : RarCrcBinaryReader
{
private RarRijndael rijndael;
private byte[] salt;
private readonly string password;
private readonly Queue<byte> data = new Queue<byte>();
private long readCount;

public RarCryptoBinaryReader(Stream stream, string password )
: base(stream)
{
this.password = password;
}

// track read count ourselves rather than using the underlying stream since we buffer
public override long CurrentReadByteCount {
get
{
return this.readCount;
}
protected set
{
// ignore
}
}

public override void Mark() {
this.readCount = 0;
}

protected bool UseEncryption
{
get { return salt != null; }
Expand All @@ -36,6 +53,7 @@ public override byte[] ReadBytes(int count)
{
return ReadAndDecryptBytes(count);
}
this.readCount += count;
return base.ReadBytes(count);
}

Expand All @@ -50,7 +68,7 @@ private byte[] ReadAndDecryptBytes(int count)
for (int i = 0; i < alignedSize / 16; i++)
{
//long ax = System.currentTimeMillis();
byte[] cipherText = base.ReadBytes(16);
byte[] cipherText = base.ReadBytesNoCrc(16);
var readBytes = rijndael.ProcessBlock(cipherText);
foreach (var readByte in readBytes)
data.Enqueue(readByte);
Expand All @@ -63,8 +81,11 @@ private byte[] ReadAndDecryptBytes(int count)

for (int i = 0; i < count; i++)
{
decryptedBytes[i] = data.Dequeue();
var b = data.Dequeue();
decryptedBytes[i] = b;
UpdateCrc(b);
}
this.readCount += count;
return decryptedBytes;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal class MultiVolumeReadOnlyStream : Stream

private long currentPartTotalReadBytes;
private long currentEntryTotalReadBytes;
private uint currentCrc;

internal MultiVolumeReadOnlyStream(IEnumerable<RarFilePart> parts, IExtractionListener streamListener)
{
Expand Down Expand Up @@ -59,6 +60,8 @@ private void InitializeNextFilePart()

currentPartTotalReadBytes = 0;

currentCrc = filePartEnumerator.Current.FileHeader.FileCRC;

streamListener.FireFilePartExtractionBegin(filePartEnumerator.Current.FilePartName,
filePartEnumerator.Current.FileHeader.CompressedSize,
filePartEnumerator.Current.FileHeader.UncompressedSize);
Expand Down Expand Up @@ -119,6 +122,8 @@ public override int Read(byte[] buffer, int offset, int count)

public override bool CanWrite { get { return false; } }

public uint CurrentCrc { get { return this.currentCrc; } }

public override void Flush()
{
throw new NotSupportedException();
Expand Down
4 changes: 4 additions & 0 deletions src/SharpCompress/Compressors/Rar/RarCRC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ internal static class RarCRC
{
private static readonly uint[] crcTab;

public static uint CheckCrc(uint startCrc, byte b) {
return (crcTab[((int) ((int) startCrc ^ (int) b)) & 0xff] ^ (startCrc >> 8));
}

public static uint CheckCrc(uint startCrc, byte[] data, int offset, int count)
{
int size = Math.Min(data.Length - offset, count);
Expand Down
42 changes: 42 additions & 0 deletions src/SharpCompress/Compressors/Rar/RarCrcStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Rar.Headers;

namespace SharpCompress.Compressors.Rar {
internal class RarCrcStream : RarStream {
private readonly MultiVolumeReadOnlyStream readStream;
private uint currentCrc;

public RarCrcStream(Unpack unpack, FileHeader fileHeader, MultiVolumeReadOnlyStream readStream) : base(unpack, fileHeader, readStream)
{
this.readStream = readStream;
ResetCrc();
}

public uint GetCrc()
{
return ~this.currentCrc;
}

public void ResetCrc()
{
this.currentCrc = 0xffffffff;
}


public override int Read(byte[] buffer, int offset, int count)
{
var result = base.Read(buffer, offset, count);
if (result != 0)
{
this.currentCrc = RarCRC.CheckCrc(this.currentCrc, buffer, offset, result);
}
else if (GetCrc() != this.readStream.CurrentCrc)
{
// NOTE: we use the last FileHeader in a multipart volume to check CRC
throw new InvalidFormatException("file crc mismatch");
}
return result;
}
}
}
4 changes: 2 additions & 2 deletions src/SharpCompress/IO/MarkingBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public MarkingBinaryReader(Stream stream)
{
}

public long CurrentReadByteCount { get; private set; }
public virtual long CurrentReadByteCount { get; protected set; }

public void Mark()
public virtual void Mark()
{
CurrentReadByteCount = 0;
}
Expand Down
4 changes: 2 additions & 2 deletions src/SharpCompress/Readers/Rar/RarReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ protected virtual IEnumerable<FilePart> CreateFilePartEnumerableForCurrentEntry(

protected override EntryStream GetEntryStream()
{
return CreateEntryStream(new RarStream(pack, Entry.FileHeader,
return CreateEntryStream(new RarCrcStream(pack, Entry.FileHeader,
new MultiVolumeReadOnlyStream(
CreateFilePartEnumerableForCurrentEntry().Cast<RarFilePart>(), this)));
}
}
}
}