2 // ARC4Managed.cs: Alleged RC4(tm) compatible symmetric stream cipher
3 // RC4 is a trademark of RSA Security
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System.Globalization;
29 using System.Security.Cryptography;
31 namespace Mono.Security.Cryptography {
34 // a. Usenet 1994 - RC4 Algorithm revealed
35 // http://www.qrst.de/html/dsds/rc4.htm
40 class ARC4Managed : RC4, ICryptoTransform {
46 private bool m_disposed;
48 public ARC4Managed () : base ()
50 state = new byte [256];
59 protected override void Dispose (bool disposing)
65 Array.Clear (key, 0, key.Length);
68 Array.Clear (state, 0, state.Length);
70 GC.SuppressFinalize (this);
75 public override byte[] Key {
79 return (byte[]) KeyValue.Clone ();
83 throw new ArgumentNullException ("Key");
84 KeyValue = key = (byte[]) value.Clone ();
89 public bool CanReuseTransform {
93 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgvIV)
96 return (ICryptoTransform) this;
99 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgvIV)
102 return CreateEncryptor ();
105 public override void GenerateIV ()
107 // not used for a stream cipher
111 public override void GenerateKey ()
113 KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
116 public bool CanTransformMultipleBlocks {
120 public int InputBlockSize {
124 public int OutputBlockSize {
128 private void KeySetup (byte[] key)
133 for (int counter = 0; counter < 256; counter++)
134 state [counter] = (byte) counter;
137 for (int counter = 0; counter < 256; counter++) {
138 index2 = (byte) (key [index1] + state [counter] + index2);
140 byte tmp = state [counter];
141 state [counter] = state [index2];
142 state [index2] = tmp;
143 index1 = (byte) ((index1 + 1) % key.Length);
147 private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
149 if (inputBuffer == null)
150 throw new ArgumentNullException ("inputBuffer");
152 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
154 throw new ArgumentOutOfRangeException ("inputCount", "< 0");
155 // ordered to avoid possible integer overflow
156 if (inputOffset > inputBuffer.Length - inputCount)
157 throw new ArgumentException (Locale.GetText ("Overflow"), "inputBuffer");
160 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
162 CheckInput (inputBuffer, inputOffset, inputCount);
163 // check output parameters
164 if (outputBuffer == null)
165 throw new ArgumentNullException ("outputBuffer");
166 if (outputOffset < 0)
167 throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
168 // ordered to avoid possible integer overflow
169 if (outputOffset > outputBuffer.Length - inputCount)
170 throw new ArgumentException (Locale.GetText ("Overflow"), "outputBuffer");
172 return InternalTransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
175 private int InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
178 for (int counter = 0; counter < inputCount; counter ++) {
180 y = (byte) (state [x] + y);
182 byte tmp = state [x];
183 state [x] = state [y];
186 xorIndex = (byte) (state [x] + state [y]);
187 outputBuffer [outputOffset + counter] = (byte) (inputBuffer [inputOffset + counter] ^ state [xorIndex]);
192 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
194 CheckInput (inputBuffer, inputOffset, inputCount);
196 byte[] output = new byte [inputCount];
197 InternalTransformBlock (inputBuffer, inputOffset, inputCount, output, 0);