2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Mono.Security / Mono.Security.Cryptography / ARC4Managed.cs
blob99e10ce2517d33069d233bc2e1256db87e655ace
1 //
2 // ARC4Managed.cs: Alleged RC4(tm) compatible symmetric stream cipher
3 // RC4 is a trademark of RSA Security
4 //
6 //
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:
14 //
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 //
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.
27 using System;
28 using System.Globalization;
29 using System.Security.Cryptography;
31 namespace Mono.Security.Cryptography {
33 // References:
34 // a. Usenet 1994 - RC4 Algorithm revealed
35 // http://www.qrst.de/html/dsds/rc4.htm
37 public class ARC4Managed : RC4, ICryptoTransform {
39 private byte[] key;
40 private byte[] state;
41 private byte x;
42 private byte y;
43 private bool m_disposed;
45 public ARC4Managed () : base ()
47 state = new byte [256];
48 m_disposed = false;
51 ~ARC4Managed ()
53 Dispose (true);
56 protected override void Dispose (bool disposing)
58 if (!m_disposed) {
59 x = 0;
60 y = 0;
61 if (key != null) {
62 Array.Clear (key, 0, key.Length);
63 key = null;
65 Array.Clear (state, 0, state.Length);
66 state = null;
67 GC.SuppressFinalize (this);
68 m_disposed = true;
72 public override byte[] Key {
73 get { return (byte[]) key.Clone (); }
74 set {
75 key = (byte[]) value.Clone ();
76 KeySetup (key);
80 public bool CanReuseTransform {
81 get { return false; }
84 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgvIV)
86 Key = rgbKey;
87 return (ICryptoTransform) this;
90 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgvIV)
92 Key = rgbKey;
93 return CreateEncryptor ();
96 public override void GenerateIV ()
98 // not used for a stream cipher
99 IV = new byte [0];
102 public override void GenerateKey ()
104 Key = KeyBuilder.Key (KeySizeValue >> 3);
107 public bool CanTransformMultipleBlocks {
108 get { return true; }
111 public int InputBlockSize {
112 get { return 1; }
115 public int OutputBlockSize {
116 get { return 1; }
119 private void KeySetup (byte[] key)
121 byte index1 = 0;
122 byte index2 = 0;
124 for (int counter = 0; counter < 256; counter++)
125 state [counter] = (byte) counter;
126 x = 0;
127 y = 0;
128 for (int counter = 0; counter < 256; counter++) {
129 index2 = (byte) (key [index1] + state [counter] + index2);
130 // swap byte
131 byte tmp = state [counter];
132 state [counter] = state [index2];
133 state [index2] = tmp;
134 index1 = (byte) ((index1 + 1) % key.Length);
138 private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
140 if (inputBuffer == null)
141 throw new ArgumentNullException ("inputBuffer");
142 if (inputOffset < 0)
143 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
144 if (inputCount < 0)
145 throw new ArgumentOutOfRangeException ("inputCount", "< 0");
146 // ordered to avoid possible integer overflow
147 if (inputOffset > inputBuffer.Length - inputCount)
148 throw new ArgumentException ("inputBuffer", Locale.GetText ("Overflow"));
151 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
153 CheckInput (inputBuffer, inputOffset, inputCount);
154 // check output parameters
155 if (outputBuffer == null)
156 throw new ArgumentNullException ("outputBuffer");
157 if (outputOffset < 0)
158 throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
159 // ordered to avoid possible integer overflow
160 if (outputOffset > outputBuffer.Length - inputCount)
161 throw new ArgumentException ("outputBuffer", Locale.GetText ("Overflow"));
163 return InternalTransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
166 private int InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
168 byte xorIndex;
169 for (int counter = 0; counter < inputCount; counter ++) {
170 x = (byte) (x + 1);
171 y = (byte) (state [x] + y);
172 // swap byte
173 byte tmp = state [x];
174 state [x] = state [y];
175 state [y] = tmp;
177 xorIndex = (byte) (state [x] + state [y]);
178 outputBuffer [outputOffset + counter] = (byte) (inputBuffer [inputOffset + counter] ^ state [xorIndex]);
180 return inputCount;
183 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
185 CheckInput (inputBuffer, inputOffset, inputCount);
187 byte[] output = new byte [inputCount];
188 InternalTransformBlock (inputBuffer, inputOffset, inputCount, output, 0);
189 return output;