-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathCryptStream.cs
120 lines (104 loc) · 2.76 KB
/
CryptStream.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System;
using System.IO;
namespace DtxCS
{
/// <summary>
/// Provides a means to decrypt an encrypted DTB file (or any other file using this crypt method).
/// </summary>
public class CryptStream : Stream
{
private long position;
private readonly int key;
private int curKey;
private long keypos;
private Stream file;
public CryptStream(Stream file)
{
file.Position = 0;
this.key = cryptRound(file.ReadInt32LE());
this.curKey = this.key;
this.file = file;
this.Length = file.Length - 4;
}
public override bool CanRead => true;
public override bool CanSeek => true;
public override bool CanWrite => false;
public override long Length { get; }
public override long Position
{
get
{
return position;
}
set
{
Seek(value, SeekOrigin.Begin);
}
}
private void updateKey()
{
if (keypos == position)
return;
if (keypos > position) // reset key (TODO: is there a better way to "re-wind" the key?)
{
keypos = 0;
curKey = key;
}
while (keypos < position)
{
curKey = cryptRound(curKey);
keypos++;
}
}
private int cryptRound(int key)
{
int ret = (key - ((key / 0x1F31D) * 0x1F31D)) * 0x41A7 - (key / 0x1F31D) * 0xB14;
if (ret <= 0)
ret += 0x7FFFFFFF;
return ret;
}
public override int Read(byte[] buffer, int offset, int count)
{
// ensure file is at correct offset
file.Seek(this.position + 4, SeekOrigin.Begin);
if (offset + count > buffer.Length)
{
throw new IndexOutOfRangeException("Attempt to fill buffer past its end");
}
if (this.Position == this.Length || this.Position + count > this.Length)
{
count = (int)(this.Length - this.Position);
//throw new System.IO.EndOfStreamException("Cannot read past end of file.");
}
int bytesRead = file.Read(buffer, offset, count);
for (uint i = 0; i < bytesRead; i++)
{
buffer[offset + i] ^= (byte)(this.curKey);
this.position++;
updateKey();
}
return bytesRead;
}
public override long Seek(long offset, SeekOrigin origin)
{
int adjust = origin == SeekOrigin.Current ? 0 : 4;
this.position = file.Seek(offset + adjust, origin) - 4;
updateKey();
return position;
}
#region Not Used
public override void Flush()
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
#endregion
}
}