-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathXtsCryptoTransform.cs
141 lines (132 loc) · 4.47 KB
/
XtsCryptoTransform.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Security.Cryptography;
namespace XTSSharp;
public class XtsCryptoTransform : IDisposable
{
private readonly byte[] _cc = new byte[16];
private readonly bool _decrypting;
private readonly ICryptoTransform _key1;
private readonly ICryptoTransform _key2;
private readonly byte[] _pp = new byte[16];
private readonly byte[] _t = new byte[16];
private readonly byte[] _tweak = new byte[16];
public XtsCryptoTransform(ICryptoTransform key1, ICryptoTransform key2, bool decrypting)
{
if (key1 == null)
{
throw new ArgumentNullException(nameof(key1));
}
if (key2 == null)
{
throw new ArgumentNullException(nameof(key2));
}
_key1 = key1;
_key2 = key2;
_decrypting = decrypting;
}
public void Dispose()
{
_key1.Dispose();
_key2.Dispose();
}
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, ulong sector)
{
FillArrayFromSectorLittleEndian(_tweak, sector);
int num = inputCount >> 4;
int num2 = inputCount & 0xF;
_key2.TransformBlock(_tweak, 0, _tweak.Length, _t, 0);
int num3 = (num2 != 0) ? (num - 1) : num;
for (int i = 0; i < num3; i++)
{
TweakCrypt(inputBuffer, inputOffset, outputBuffer, outputOffset, _t);
inputOffset += 16;
outputOffset += 16;
}
if (num2 > 0)
{
if (_decrypting)
{
Buffer.BlockCopy(_t, 0, _cc, 0, 16);
MultiplyByX(_cc);
TweakCrypt(inputBuffer, inputOffset, _pp, 0, _cc);
int j;
for (j = 0; j < num2; j++)
{
_cc[j] = inputBuffer[16 + j + inputOffset];
outputBuffer[16 + j + outputOffset] = _pp[j];
}
for (; j < 16; j++)
{
_cc[j] = _pp[j];
}
TweakCrypt(_cc, 0, outputBuffer, outputOffset, _t);
}
else
{
TweakCrypt(inputBuffer, inputOffset, _cc, 0, _t);
int k;
for (k = 0; k < num2; k++)
{
_pp[k] = inputBuffer[16 + k + inputOffset];
outputBuffer[16 + k + outputOffset] = _cc[k];
}
for (; k < 16; k++)
{
_pp[k] = _cc[k];
}
TweakCrypt(_pp, 0, outputBuffer, outputOffset, _t);
}
}
return inputCount;
}
private static void FillArrayFromSectorBigEndian(byte[] value, ulong sector)
{
value[7] = (byte)((sector >> 56) & 0xFF);
value[6] = (byte)((sector >> 48) & 0xFF);
value[5] = (byte)((sector >> 40) & 0xFF);
value[4] = (byte)((sector >> 32) & 0xFF);
value[3] = (byte)((sector >> 24) & 0xFF);
value[2] = (byte)((sector >> 16) & 0xFF);
value[1] = (byte)((sector >> 8) & 0xFF);
value[0] = (byte)(sector & 0xFF);
}
private static void FillArrayFromSectorLittleEndian(byte[] value, ulong sector)
{
value[8] = (byte)((sector >> 56) & 0xFF);
value[9] = (byte)((sector >> 48) & 0xFF);
value[10] = (byte)((sector >> 40) & 0xFF);
value[11] = (byte)((sector >> 32) & 0xFF);
value[12] = (byte)((sector >> 24) & 0xFF);
value[13] = (byte)((sector >> 16) & 0xFF);
value[14] = (byte)((sector >> 8) & 0xFF);
value[15] = (byte)(sector & 0xFF);
}
private void TweakCrypt(byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, byte[] t)
{
for (int i = 0; i < 16; i++)
{
outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ t[i]);
}
_key1.TransformBlock(outputBuffer, outputOffset, 16, outputBuffer, outputOffset);
for (int j = 0; j < 16; j++)
{
outputBuffer[j + outputOffset] = (byte)(outputBuffer[j + outputOffset] ^ t[j]);
}
MultiplyByX(t);
}
private static void MultiplyByX(byte[] i)
{
byte b = 0;
byte b2 = 0;
for (int j = 0; j < 16; j++)
{
b2 = (byte)(i[j] >> 7);
i[j] = (byte)(((i[j] << 1) | b) & 0xFF);
b = b2;
}
if (b2 > 0)
{
i[0] ^= 135;
}
}
}