Files
2026-06-04 11:42:34 +02:00

557 lines
15 KiB
C#

using System;
using System.Security.Cryptography;
namespace Mono.Security.Cryptography
{
// Token: 0x020000AE RID: 174
internal abstract class SymmetricTransform : IDisposable, ICryptoTransform
{
// Token: 0x0600097D RID: 2429 RVA: 0x00026B2C File Offset: 0x00024D2C
public SymmetricTransform(SymmetricAlgorithm symmAlgo, bool encryption, byte[] rgbIV)
{
this.algo = symmAlgo;
this.encrypt = encryption;
this.BlockSizeByte = this.algo.BlockSize >> 3;
if (rgbIV == null)
{
rgbIV = KeyBuilder.IV(this.BlockSizeByte);
}
else
{
rgbIV = (byte[])rgbIV.Clone();
}
if (rgbIV.Length < this.BlockSizeByte)
{
string text = Locale.GetText("IV is too small ({0} bytes), it should be {1} bytes long.", new object[] { rgbIV.Length, this.BlockSizeByte });
throw new CryptographicException(text);
}
this.temp = new byte[this.BlockSizeByte];
Buffer.BlockCopy(rgbIV, 0, this.temp, 0, Math.Min(this.BlockSizeByte, rgbIV.Length));
this.temp2 = new byte[this.BlockSizeByte];
this.FeedBackByte = this.algo.FeedbackSize >> 3;
if (this.FeedBackByte != 0)
{
this.FeedBackIter = this.BlockSizeByte / this.FeedBackByte;
}
this.workBuff = new byte[this.BlockSizeByte];
this.workout = new byte[this.BlockSizeByte];
}
// Token: 0x0600097E RID: 2430 RVA: 0x00026C58 File Offset: 0x00024E58
void IDisposable.Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
// Token: 0x0600097F RID: 2431 RVA: 0x00026C68 File Offset: 0x00024E68
~SymmetricTransform()
{
this.Dispose(false);
}
// Token: 0x06000980 RID: 2432 RVA: 0x00026CA4 File Offset: 0x00024EA4
protected virtual void Dispose(bool disposing)
{
if (!this.m_disposed)
{
if (disposing)
{
Array.Clear(this.temp, 0, this.BlockSizeByte);
this.temp = null;
Array.Clear(this.temp2, 0, this.BlockSizeByte);
this.temp2 = null;
}
this.m_disposed = true;
}
}
// Token: 0x17000111 RID: 273
// (get) Token: 0x06000981 RID: 2433 RVA: 0x00026CFC File Offset: 0x00024EFC
public virtual bool CanTransformMultipleBlocks
{
get
{
return true;
}
}
// Token: 0x17000112 RID: 274
// (get) Token: 0x06000982 RID: 2434 RVA: 0x00026D00 File Offset: 0x00024F00
public virtual bool CanReuseTransform
{
get
{
return false;
}
}
// Token: 0x17000113 RID: 275
// (get) Token: 0x06000983 RID: 2435 RVA: 0x00026D04 File Offset: 0x00024F04
public virtual int InputBlockSize
{
get
{
return this.BlockSizeByte;
}
}
// Token: 0x17000114 RID: 276
// (get) Token: 0x06000984 RID: 2436 RVA: 0x00026D0C File Offset: 0x00024F0C
public virtual int OutputBlockSize
{
get
{
return this.BlockSizeByte;
}
}
// Token: 0x06000985 RID: 2437 RVA: 0x00026D14 File Offset: 0x00024F14
protected virtual void Transform(byte[] input, byte[] output)
{
switch (this.algo.Mode)
{
case CipherMode.CBC:
this.CBC(input, output);
break;
case CipherMode.ECB:
this.ECB(input, output);
break;
case CipherMode.OFB:
this.OFB(input, output);
break;
case CipherMode.CFB:
this.CFB(input, output);
break;
case CipherMode.CTS:
this.CTS(input, output);
break;
default:
throw new NotImplementedException("Unkown CipherMode" + this.algo.Mode.ToString());
}
}
// Token: 0x06000986 RID: 2438
protected abstract void ECB(byte[] input, byte[] output);
// Token: 0x06000987 RID: 2439 RVA: 0x00026DB4 File Offset: 0x00024FB4
protected virtual void CBC(byte[] input, byte[] output)
{
if (this.encrypt)
{
for (int i = 0; i < this.BlockSizeByte; i++)
{
byte[] array = this.temp;
int num = i;
array[num] ^= input[i];
}
this.ECB(this.temp, output);
Buffer.BlockCopy(output, 0, this.temp, 0, this.BlockSizeByte);
}
else
{
Buffer.BlockCopy(input, 0, this.temp2, 0, this.BlockSizeByte);
this.ECB(input, output);
for (int j = 0; j < this.BlockSizeByte; j++)
{
int num2 = j;
output[num2] ^= this.temp[j];
}
Buffer.BlockCopy(this.temp2, 0, this.temp, 0, this.BlockSizeByte);
}
}
// Token: 0x06000988 RID: 2440 RVA: 0x00026E80 File Offset: 0x00025080
protected virtual void CFB(byte[] input, byte[] output)
{
if (this.encrypt)
{
for (int i = 0; i < this.FeedBackIter; i++)
{
this.ECB(this.temp, this.temp2);
for (int j = 0; j < this.FeedBackByte; j++)
{
output[j + i] = this.temp2[j] ^ input[j + i];
}
Buffer.BlockCopy(this.temp, this.FeedBackByte, this.temp, 0, this.BlockSizeByte - this.FeedBackByte);
Buffer.BlockCopy(output, i, this.temp, this.BlockSizeByte - this.FeedBackByte, this.FeedBackByte);
}
}
else
{
for (int k = 0; k < this.FeedBackIter; k++)
{
this.encrypt = true;
this.ECB(this.temp, this.temp2);
this.encrypt = false;
Buffer.BlockCopy(this.temp, this.FeedBackByte, this.temp, 0, this.BlockSizeByte - this.FeedBackByte);
Buffer.BlockCopy(input, k, this.temp, this.BlockSizeByte - this.FeedBackByte, this.FeedBackByte);
for (int l = 0; l < this.FeedBackByte; l++)
{
output[l + k] = this.temp2[l] ^ input[l + k];
}
}
}
}
// Token: 0x06000989 RID: 2441 RVA: 0x00026FE0 File Offset: 0x000251E0
protected virtual void OFB(byte[] input, byte[] output)
{
throw new CryptographicException("OFB isn't supported by the framework");
}
// Token: 0x0600098A RID: 2442 RVA: 0x00026FEC File Offset: 0x000251EC
protected virtual void CTS(byte[] input, byte[] output)
{
throw new CryptographicException("CTS isn't supported by the framework");
}
// Token: 0x0600098B RID: 2443 RVA: 0x00026FF8 File Offset: 0x000251F8
private void CheckInput(byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputBuffer == null)
{
throw new ArgumentNullException("inputBuffer");
}
if (inputOffset < 0)
{
throw new ArgumentOutOfRangeException("inputOffset", "< 0");
}
if (inputCount < 0)
{
throw new ArgumentOutOfRangeException("inputCount", "< 0");
}
if (inputOffset > inputBuffer.Length - inputCount)
{
throw new ArgumentException("inputBuffer", Locale.GetText("Overflow"));
}
}
// Token: 0x0600098C RID: 2444 RVA: 0x00027064 File Offset: 0x00025264
public virtual int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (this.m_disposed)
{
throw new ObjectDisposedException("Object is disposed");
}
this.CheckInput(inputBuffer, inputOffset, inputCount);
if (outputBuffer == null)
{
throw new ArgumentNullException("outputBuffer");
}
if (outputOffset < 0)
{
throw new ArgumentOutOfRangeException("outputOffset", "< 0");
}
int num = outputBuffer.Length - inputCount - outputOffset;
if (!this.encrypt && 0 > num && (this.algo.Padding == PaddingMode.None || this.algo.Padding == PaddingMode.Zeros))
{
throw new CryptographicException("outputBuffer", Locale.GetText("Overflow"));
}
if (this.KeepLastBlock)
{
if (0 > num + this.BlockSizeByte)
{
throw new CryptographicException("outputBuffer", Locale.GetText("Overflow"));
}
}
else if (0 > num)
{
if (inputBuffer.Length - inputOffset - outputBuffer.Length != this.BlockSizeByte)
{
throw new CryptographicException("outputBuffer", Locale.GetText("Overflow"));
}
inputCount = outputBuffer.Length - outputOffset;
}
return this.InternalTransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
// Token: 0x17000115 RID: 277
// (get) Token: 0x0600098D RID: 2445 RVA: 0x0002718C File Offset: 0x0002538C
private bool KeepLastBlock
{
get
{
return !this.encrypt && this.algo.Padding != PaddingMode.None && this.algo.Padding != PaddingMode.Zeros;
}
}
// Token: 0x0600098E RID: 2446 RVA: 0x000271CC File Offset: 0x000253CC
private int InternalTransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
int num = inputOffset;
int num2;
if (inputCount != this.BlockSizeByte)
{
if (inputCount % this.BlockSizeByte != 0)
{
throw new CryptographicException("Invalid input block size.");
}
num2 = inputCount / this.BlockSizeByte;
}
else
{
num2 = 1;
}
if (this.KeepLastBlock)
{
num2--;
}
int num3 = 0;
if (this.lastBlock)
{
this.Transform(this.workBuff, this.workout);
Buffer.BlockCopy(this.workout, 0, outputBuffer, outputOffset, this.BlockSizeByte);
outputOffset += this.BlockSizeByte;
num3 += this.BlockSizeByte;
this.lastBlock = false;
}
for (int i = 0; i < num2; i++)
{
Buffer.BlockCopy(inputBuffer, num, this.workBuff, 0, this.BlockSizeByte);
this.Transform(this.workBuff, this.workout);
Buffer.BlockCopy(this.workout, 0, outputBuffer, outputOffset, this.BlockSizeByte);
num += this.BlockSizeByte;
outputOffset += this.BlockSizeByte;
num3 += this.BlockSizeByte;
}
if (this.KeepLastBlock)
{
Buffer.BlockCopy(inputBuffer, num, this.workBuff, 0, this.BlockSizeByte);
this.lastBlock = true;
}
return num3;
}
// Token: 0x0600098F RID: 2447 RVA: 0x00027300 File Offset: 0x00025500
private void Random(byte[] buffer, int start, int length)
{
if (this._rng == null)
{
this._rng = RandomNumberGenerator.Create();
}
byte[] array = new byte[length];
this._rng.GetBytes(array);
Buffer.BlockCopy(array, 0, buffer, start, length);
}
// Token: 0x06000990 RID: 2448 RVA: 0x00027340 File Offset: 0x00025540
private void ThrowBadPaddingException(PaddingMode padding, int length, int position)
{
string text = string.Format(Locale.GetText("Bad {0} padding."), padding);
if (length >= 0)
{
text += string.Format(Locale.GetText(" Invalid length {0}."), length);
}
if (position >= 0)
{
text += string.Format(Locale.GetText(" Error found at position {0}."), position);
}
throw new CryptographicException(text);
}
// Token: 0x06000991 RID: 2449 RVA: 0x000273B0 File Offset: 0x000255B0
private byte[] FinalEncrypt(byte[] inputBuffer, int inputOffset, int inputCount)
{
int num = inputCount / this.BlockSizeByte * this.BlockSizeByte;
int num2 = inputCount - num;
int i = num;
switch (this.algo.Padding)
{
case PaddingMode.PKCS7:
case PaddingMode.ANSIX923:
case PaddingMode.ISO10126:
i += this.BlockSizeByte;
goto IL_A8;
}
if (inputCount == 0)
{
return new byte[0];
}
if (num2 != 0)
{
if (this.algo.Padding == PaddingMode.None)
{
throw new CryptographicException("invalid block length");
}
byte[] array = new byte[num + this.BlockSizeByte];
Buffer.BlockCopy(inputBuffer, inputOffset, array, 0, inputCount);
inputBuffer = array;
inputOffset = 0;
inputCount = array.Length;
i = inputCount;
}
IL_A8:
byte[] array2 = new byte[i];
int num3 = 0;
while (i > this.BlockSizeByte)
{
this.InternalTransformBlock(inputBuffer, inputOffset, this.BlockSizeByte, array2, num3);
inputOffset += this.BlockSizeByte;
num3 += this.BlockSizeByte;
i -= this.BlockSizeByte;
}
byte b = (byte)(this.BlockSizeByte - num2);
switch (this.algo.Padding)
{
case PaddingMode.PKCS7:
{
int num4 = array2.Length;
while (--num4 >= array2.Length - (int)b)
{
array2[num4] = b;
}
Buffer.BlockCopy(inputBuffer, inputOffset, array2, num, num2);
this.InternalTransformBlock(array2, num, this.BlockSizeByte, array2, num);
return array2;
}
case PaddingMode.ANSIX923:
array2[array2.Length - 1] = b;
Buffer.BlockCopy(inputBuffer, inputOffset, array2, num, num2);
this.InternalTransformBlock(array2, num, this.BlockSizeByte, array2, num);
return array2;
case PaddingMode.ISO10126:
this.Random(array2, array2.Length - (int)b, (int)(b - 1));
array2[array2.Length - 1] = b;
Buffer.BlockCopy(inputBuffer, inputOffset, array2, num, num2);
this.InternalTransformBlock(array2, num, this.BlockSizeByte, array2, num);
return array2;
}
this.InternalTransformBlock(inputBuffer, inputOffset, this.BlockSizeByte, array2, num3);
return array2;
}
// Token: 0x06000992 RID: 2450 RVA: 0x000275BC File Offset: 0x000257BC
private byte[] FinalDecrypt(byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputCount % this.BlockSizeByte > 0)
{
throw new CryptographicException("Invalid input block size.");
}
int num = inputCount;
if (this.lastBlock)
{
num += this.BlockSizeByte;
}
byte[] array = new byte[num];
int num2 = 0;
while (inputCount > 0)
{
int num3 = this.InternalTransformBlock(inputBuffer, inputOffset, this.BlockSizeByte, array, num2);
inputOffset += this.BlockSizeByte;
num2 += num3;
inputCount -= this.BlockSizeByte;
}
if (this.lastBlock)
{
this.Transform(this.workBuff, this.workout);
Buffer.BlockCopy(this.workout, 0, array, num2, this.BlockSizeByte);
num2 += this.BlockSizeByte;
this.lastBlock = false;
}
byte b = ((num <= 0) ? 0 : array[num - 1]);
switch (this.algo.Padding)
{
case PaddingMode.PKCS7:
{
if (b == 0 || (int)b > this.BlockSizeByte)
{
this.ThrowBadPaddingException(this.algo.Padding, (int)b, -1);
}
for (int i = (int)(b - 1); i > 0; i--)
{
if (array[num - 1 - i] != b)
{
this.ThrowBadPaddingException(this.algo.Padding, -1, i);
}
}
num -= (int)b;
break;
}
case PaddingMode.ANSIX923:
{
if (b == 0 || (int)b > this.BlockSizeByte)
{
this.ThrowBadPaddingException(this.algo.Padding, (int)b, -1);
}
for (int j = (int)(b - 1); j > 0; j--)
{
if (array[num - 1 - j] != 0)
{
this.ThrowBadPaddingException(this.algo.Padding, -1, j);
}
}
num -= (int)b;
break;
}
case PaddingMode.ISO10126:
if (b == 0 || (int)b > this.BlockSizeByte)
{
this.ThrowBadPaddingException(this.algo.Padding, (int)b, -1);
}
num -= (int)b;
break;
}
if (num > 0)
{
byte[] array2 = new byte[num];
Buffer.BlockCopy(array, 0, array2, 0, num);
Array.Clear(array, 0, array.Length);
return array2;
}
return new byte[0];
}
// Token: 0x06000993 RID: 2451 RVA: 0x000277F8 File Offset: 0x000259F8
public virtual byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
{
if (this.m_disposed)
{
throw new ObjectDisposedException("Object is disposed");
}
this.CheckInput(inputBuffer, inputOffset, inputCount);
if (this.encrypt)
{
return this.FinalEncrypt(inputBuffer, inputOffset, inputCount);
}
return this.FinalDecrypt(inputBuffer, inputOffset, inputCount);
}
// Token: 0x0400021E RID: 542
protected SymmetricAlgorithm algo;
// Token: 0x0400021F RID: 543
protected bool encrypt;
// Token: 0x04000220 RID: 544
private int BlockSizeByte;
// Token: 0x04000221 RID: 545
private byte[] temp;
// Token: 0x04000222 RID: 546
private byte[] temp2;
// Token: 0x04000223 RID: 547
private byte[] workBuff;
// Token: 0x04000224 RID: 548
private byte[] workout;
// Token: 0x04000225 RID: 549
private int FeedBackByte;
// Token: 0x04000226 RID: 550
private int FeedBackIter;
// Token: 0x04000227 RID: 551
private bool m_disposed;
// Token: 0x04000228 RID: 552
private bool lastBlock;
// Token: 0x04000229 RID: 553
private RandomNumberGenerator _rng;
}
}