Arc4Cipher.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. namespace Renci.SshNet.Security.Cryptography.Ciphers
  3. {
  4. /// <summary>
  5. /// Implements ARCH4 cipher algorithm
  6. /// </summary>
  7. public sealed class Arc4Cipher : StreamCipher
  8. {
  9. private static readonly int STATE_LENGTH = 256;
  10. /// <summary>
  11. /// Holds the state of the RC4 engine
  12. /// </summary>
  13. private byte[] _engineState;
  14. private int _x;
  15. private int _y;
  16. private byte[] _workingKey;
  17. /// <summary>
  18. /// Gets the minimum data size.
  19. /// </summary>
  20. /// <value>
  21. /// The minimum data size.
  22. /// </value>
  23. public override byte MinimumSize
  24. {
  25. get { return 0; }
  26. }
  27. /// <summary>
  28. /// Initializes a new instance of the <see cref="Arc4Cipher" /> class.
  29. /// </summary>
  30. /// <param name="key">The key.</param>
  31. /// <param name="dischargeFirstBytes">if set to <c>true</c> will disharged first 1536 bytes.</param>
  32. /// <exception cref="ArgumentNullException"><paramref name="key" /> is null.</exception>
  33. public Arc4Cipher(byte[] key, bool dischargeFirstBytes)
  34. : base(key)
  35. {
  36. this._workingKey = key;
  37. SetKey(this._workingKey);
  38. // The first 1536 bytes of keystream
  39. // generated by the cipher MUST be discarded, and the first byte of the
  40. // first encrypted packet MUST be encrypted using the 1537th byte of
  41. // keystream.
  42. if (dischargeFirstBytes)
  43. this.Encrypt(new byte[1536]);
  44. }
  45. /// <summary>
  46. /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
  47. /// </summary>
  48. /// <param name="inputBuffer">The input data to encrypt.</param>
  49. /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
  50. /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
  51. /// <param name="outputBuffer">The output to which to write encrypted data.</param>
  52. /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
  53. /// <returns>
  54. /// The number of bytes encrypted.
  55. /// </returns>
  56. public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  57. {
  58. return this.ProcessBytes(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
  59. }
  60. /// <summary>
  61. /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
  62. /// </summary>
  63. /// <param name="inputBuffer">The input data to decrypt.</param>
  64. /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
  65. /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
  66. /// <param name="outputBuffer">The output to which to write decrypted data.</param>
  67. /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
  68. /// <returns>
  69. /// The number of bytes decrypted.
  70. /// </returns>
  71. public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  72. {
  73. return this.ProcessBytes(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
  74. }
  75. /// <summary>
  76. /// Encrypts the specified input.
  77. /// </summary>
  78. /// <param name="input">The input.</param>
  79. /// <returns>
  80. /// Encrypted data.
  81. /// </returns>
  82. /// <exception cref="System.NotImplementedException"></exception>
  83. public override byte[] Encrypt(byte[] input)
  84. {
  85. var output = new byte[input.Length];
  86. this.ProcessBytes(input, 0, input.Length, output, 0);
  87. return output;
  88. }
  89. /// <summary>
  90. /// Decrypts the specified input.
  91. /// </summary>
  92. /// <param name="input">The input.</param>
  93. /// <returns>
  94. /// Decrypted data.
  95. /// </returns>
  96. /// <exception cref="System.NotImplementedException"></exception>
  97. public override byte[] Decrypt(byte[] input)
  98. {
  99. var output = new byte[input.Length];
  100. this.ProcessBytes(input, 0, input.Length, output, 0);
  101. return output;
  102. }
  103. private int ProcessBytes(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  104. {
  105. if ((inputOffset + inputCount) > inputBuffer.Length)
  106. {
  107. throw new IndexOutOfRangeException("input buffer too short");
  108. }
  109. if ((outputOffset + inputCount) > outputBuffer.Length)
  110. {
  111. throw new IndexOutOfRangeException("output buffer too short");
  112. }
  113. for (int i = 0; i < inputCount; i++)
  114. {
  115. this._x = (this._x + 1) & 0xff;
  116. this._y = (this._engineState[this._x] + this._y) & 0xff;
  117. // swap
  118. byte tmp = this._engineState[this._x];
  119. this._engineState[this._x] = this._engineState[this._y];
  120. this._engineState[this._y] = tmp;
  121. // xor
  122. outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ this._engineState[(this._engineState[this._x] + this._engineState[this._y]) & 0xff]);
  123. }
  124. return inputCount;
  125. }
  126. private void SetKey(byte[] keyBytes)
  127. {
  128. this._workingKey = keyBytes;
  129. this._x = 0;
  130. this._y = 0;
  131. if (this._engineState == null)
  132. {
  133. this._engineState = new byte[STATE_LENGTH];
  134. }
  135. // reset the state of the engine
  136. for (var i = 0; i < STATE_LENGTH; i++)
  137. {
  138. this._engineState[i] = (byte) i;
  139. }
  140. int i1 = 0;
  141. int i2 = 0;
  142. for (var i = 0; i < STATE_LENGTH; i++)
  143. {
  144. i2 = ((keyBytes[i1] & 0xff) + this._engineState[i] + i2) & 0xff;
  145. // do the byte-swap inline
  146. byte tmp = this._engineState[i];
  147. this._engineState[i] = this._engineState[i2];
  148. this._engineState[i2] = tmp;
  149. i1 = (i1 + 1) % keyBytes.Length;
  150. }
  151. }
  152. }
  153. }