mirror of
https://github.com/StudentBlake/XCI-Explorer
synced 2024-11-22 12:13:03 +00:00
142 lines
5 KiB
C#
142 lines
5 KiB
C#
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("key1");
|
|
}
|
|
if (key2 == null)
|
|
{
|
|
throw new ArgumentNullException("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;
|
|
}
|
|
}
|
|
}
|
|
}
|