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; } }