From e1511bf3badaa9473e4656c5265dd5b73c822bf0 Mon Sep 17 00:00:00 2001 From: Hamdanil Rasyid Date: Sun, 14 Jul 2013 19:04:22 +0800 Subject: [PATCH] Decrypt stream (in addition to header) --- .../Common/Rar/Headers/RarHeaderFactory.cs | 3 +- SharpCompress/Common/Rar/RarCryptoWrapper.cs | 186 ++++++++++++++++++ SharpCompress/SharpCompress.csproj | 1 + 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 SharpCompress/Common/Rar/RarCryptoWrapper.cs diff --git a/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs b/SharpCompress/Common/Rar/Headers/RarHeaderFactory.cs index 7b05a2ef..cd43590e 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 @@ -181,7 +182,7 @@ namespace SharpCompress.Common.Rar.Headers { ReadOnlySubStream ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize); - fh.PackedStream = ms; + fh.PackedStream = new RarCryptoWrapper(ms) { Salt = fh.Salt}; } break; default: diff --git a/SharpCompress/Common/Rar/RarCryptoWrapper.cs b/SharpCompress/Common/Rar/RarCryptoWrapper.cs new file mode 100644 index 00000000..f7a858e4 --- /dev/null +++ b/SharpCompress/Common/Rar/RarCryptoWrapper.cs @@ -0,0 +1,186 @@ +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 RarCryptoWrapper : Stream + { + private readonly Stream _actualStream; + private byte[] _salt; + private Rijndael _rijndael; + private string _password = "test"; + private byte[] _aesInitializationVector = new byte[CryptoBlockSize]; + private byte[] _aesKey = new byte[CryptoBlockSize]; + private Queue _data = new Queue(); + private const int CryptoBlockSize = 16; + + public RarCryptoWrapper(Stream actualStream) + { + _actualStream = actualStream; + } + + internal byte[] Salt + { + get { return _salt; } + set + { + _salt = value; + if (value != null) InitializeAes(); + + } + } + + private void InitializeAes() + { + _rijndael = new RijndaelManaged() { Padding = PaddingMode.None }; + 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]; + } + + var sha = new SHA1Managed(); + + const int noOfRounds = (1 << 18); + IList bytes = new List(); + byte[] digest; + 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()); + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + _aesKey[i * 4 + j] = (byte) + (((digest[i * 4] * 0x1000000) & 0xff000000 | + ((digest[i * 4 + 1] * 0x10000) & 0xff0000) | + ((digest[i * 4 + 2] * 0x100) & 0xff00) | + digest[i * 4 + 3] & 0xff) >> (j * 8)); + + _rijndael.IV = new byte[CryptoBlockSize]; + _rijndael.Key = _aesKey; + _rijndael.BlockSize = CryptoBlockSize * 8; + } + + 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[CryptoBlockSize]; + _actualStream.Read(cipherText, 0, CryptoBlockSize); + + byte[] plainText = new byte[CryptoBlockSize]; + var decryptor = _rijndael.CreateDecryptor(); + using (MemoryStream msDecrypt = new MemoryStream(cipherText)) + { + using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) + { + csDecrypt.ReadFully(plainText); + } + } + + + for (int j = 0; j < plainText.Length; j++) + { + _data.Enqueue((byte) (plainText[j] ^ _aesInitializationVector[j%16])); //32:114, 33:101 + + } + + for (int j = 0; j < _aesInitializationVector.Length; j++) + { + _aesInitializationVector[j] = cipherText[j]; + } + } + + for (int i = 0; i < count; i++) + { + buffer[i] = _data.Dequeue(); + Console.Write(buffer[i].ToString("x2") + " "); + } + } + 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) + { + _rijndael.Dispose(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/SharpCompress/SharpCompress.csproj b/SharpCompress/SharpCompress.csproj index f7d1cf1d..4a24be2e 100644 --- a/SharpCompress/SharpCompress.csproj +++ b/SharpCompress/SharpCompress.csproj @@ -127,6 +127,7 @@ +