RarCryptoBinaryReader.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #if !NO_CRYPTO
  2. using System.Collections.Generic;
  3. using System.IO;
  4. namespace SharpCompress.Common.Rar
  5. {
  6. internal class RarCryptoBinaryReader : RarCrcBinaryReader
  7. {
  8. private RarRijndael _rijndael;
  9. private byte[] _salt;
  10. private readonly string _password;
  11. private readonly Queue<byte> _data = new Queue<byte>();
  12. private long _readCount;
  13. public RarCryptoBinaryReader(Stream stream, string password)
  14. : base(stream)
  15. {
  16. _password = password;
  17. // coderb: not sure why this was being done at this logical point
  18. //SkipQueue();
  19. byte[] salt = ReadBytes(8);
  20. InitializeAes(salt);
  21. }
  22. // track read count ourselves rather than using the underlying stream since we buffer
  23. public override long CurrentReadByteCount
  24. {
  25. get => _readCount;
  26. protected set
  27. {
  28. // ignore
  29. }
  30. }
  31. public override void Mark()
  32. {
  33. _readCount = 0;
  34. }
  35. private bool UseEncryption => _salt != null;
  36. internal void InitializeAes(byte[] salt)
  37. {
  38. _salt = salt;
  39. _rijndael = RarRijndael.InitializeFrom(_password, salt);
  40. }
  41. public override byte ReadByte()
  42. {
  43. if (UseEncryption)
  44. {
  45. return ReadAndDecryptBytes(1)[0];
  46. }
  47. _readCount++;
  48. return base.ReadByte();
  49. }
  50. public override byte[] ReadBytes(int count)
  51. {
  52. if (UseEncryption)
  53. {
  54. return ReadAndDecryptBytes(count);
  55. }
  56. _readCount += count;
  57. return base.ReadBytes(count);
  58. }
  59. private byte[] ReadAndDecryptBytes(int count)
  60. {
  61. int queueSize = _data.Count;
  62. int sizeToRead = count - queueSize;
  63. if (sizeToRead > 0)
  64. {
  65. int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf);
  66. for (int i = 0; i < alignedSize / 16; i++)
  67. {
  68. //long ax = System.currentTimeMillis();
  69. byte[] cipherText = ReadBytesNoCrc(16);
  70. var readBytes = _rijndael.ProcessBlock(cipherText);
  71. foreach (var readByte in readBytes)
  72. _data.Enqueue(readByte);
  73. }
  74. }
  75. var decryptedBytes = new byte[count];
  76. for (int i = 0; i < count; i++)
  77. {
  78. var b = _data.Dequeue();
  79. decryptedBytes[i] = b;
  80. UpdateCrc(b);
  81. }
  82. _readCount += count;
  83. return decryptedBytes;
  84. }
  85. public void ClearQueue()
  86. {
  87. _data.Clear();
  88. }
  89. public void SkipQueue()
  90. {
  91. var position = BaseStream.Position;
  92. BaseStream.Position = position + _data.Count;
  93. ClearQueue();
  94. }
  95. }
  96. }
  97. #endif