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
37 public class ARC4Managed
: RC4
, ICryptoTransform
{
43 private bool m_disposed
;
45 public ARC4Managed () : base ()
47 state
= new byte [256];
56 protected override void Dispose (bool disposing
)
62 Array
.Clear (key
, 0, key
.Length
);
65 Array
.Clear (state
, 0, state
.Length
);
67 GC
.SuppressFinalize (this);
72 public override byte[] Key
{
73 get { return (byte[]) key.Clone (); }
75 key
= (byte[]) value.Clone ();
80 public bool CanReuseTransform
{
84 public override ICryptoTransform
CreateEncryptor (byte[] rgbKey
, byte[] rgvIV
)
87 return (ICryptoTransform
) this;
90 public override ICryptoTransform
CreateDecryptor (byte[] rgbKey
, byte[] rgvIV
)
93 return CreateEncryptor ();
96 public override void GenerateIV ()
98 // not used for a stream cipher
102 public override void GenerateKey ()
104 Key
= KeyBuilder
.Key (KeySizeValue
>> 3);
107 public bool CanTransformMultipleBlocks
{
111 public int InputBlockSize
{
115 public int OutputBlockSize
{
119 private void KeySetup (byte[] key
)
124 for (int counter
= 0; counter
< 256; counter
++)
125 state
[counter
] = (byte) counter
;
128 for (int counter
= 0; counter
< 256; counter
++) {
129 index2
= (byte) (key
[index1
] + state
[counter
] + index2
);
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");
143 throw new ArgumentOutOfRangeException ("inputOffset", "< 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
)
169 for (int counter
= 0; counter
< inputCount
; counter
++) {
171 y
= (byte) (state
[x
] + y
);
173 byte tmp
= state
[x
];
174 state
[x
] = state
[y
];
177 xorIndex
= (byte) (state
[x
] + state
[y
]);
178 outputBuffer
[outputOffset
+ counter
] = (byte) (inputBuffer
[inputOffset
+ counter
] ^ state
[xorIndex
]);
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);