1 // A CommonCrypto-based implementation of RC4(tm)
4 // Sebastien Pouliot <sebastien@xamarin.com>
6 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
7 // Copyright 2012-2014 Xamarin Inc.
10 using System.Security.Cryptography;
12 using Crimson.CommonCrypto;
14 #if MONOTOUCH || XAMMAC
15 using Mono.Security.Cryptography;
17 namespace Mono.Security.Cryptography {
22 sealed partial class ARC4Managed : RC4, ICryptoTransform {
35 namespace Crimson.Security.Cryptography {
37 public abstract class RC4 : SymmetricAlgorithm {
39 private static KeySizes[] s_legalBlockSizes = {
40 new KeySizes (64, 64, 0)
43 private static KeySizes[] s_legalKeySizes = {
44 new KeySizes (40, 512, 8)
51 FeedbackSizeValue = BlockSizeValue;
52 LegalBlockSizesValue = s_legalBlockSizes;
53 LegalKeySizesValue = s_legalKeySizes;
56 // required for compatibility with .NET 2.0
57 public override byte[] IV {
58 get { return new byte [0]; }
62 new static public RC4 Create()
64 return Create ("RC4");
67 new static public RC4 Create (string algName)
69 object o = CryptoConfig.CreateFromName (algName);
70 return (RC4) o ?? new RC4CommonCrypto ();
74 public sealed class RC4CommonCrypto : RC4, ICryptoTransform {
78 public RC4CommonCrypto ()
88 public bool CanReuseTransform {
92 public bool CanTransformMultipleBlocks {
96 public int InputBlockSize {
100 public int OutputBlockSize {
104 public override byte[] Key {
110 throw new ArgumentNullException ("Key");
112 int length = (value.Length << 3);
113 KeySizeValue = length;
114 KeyValue = (byte[]) value.Clone ();
118 protected override void Dispose (bool disposing)
120 if (handle != IntPtr.Zero) {
121 Cryptor.CCCryptorRelease (handle);
122 handle = IntPtr.Zero;
124 base.Dispose (disposing);
125 GC.SuppressFinalize (this);
128 public override void GenerateIV ()
130 // not used for a stream cipher
131 IVValue = new byte [0];
134 public override void GenerateKey ()
136 KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
139 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
146 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
153 private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
155 if (inputBuffer == null)
156 throw new ArgumentNullException ("inputBuffer");
158 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
160 throw new ArgumentOutOfRangeException ("inputCount", "< 0");
161 // ordered to avoid possible integer overflow
162 if (inputOffset > inputBuffer.Length - inputCount)
163 throw new ArgumentException ("inputBuffer", "Overflow");
166 public unsafe int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
168 CheckInput (inputBuffer, inputOffset, inputCount);
172 // check output parameters
173 if (outputBuffer == null)
174 throw new ArgumentNullException ("outputBuffer");
175 if (outputOffset < 0)
176 throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
177 // ordered to avoid possible integer overflow
178 if (outputOffset > outputBuffer.Length - inputCount)
179 throw new ArgumentException ("outputBuffer", "Overflow");
180 if (outputBuffer.Length == 0)
181 throw new CryptographicException ("output buffer too small");
183 if (handle == IntPtr.Zero)
184 handle = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.RC4, CCOptions.None, KeyValue, IVValue);
186 IntPtr len = IntPtr.Zero;
187 IntPtr in_len = (IntPtr) (inputBuffer.Length - inputOffset);
188 IntPtr out_len = (IntPtr) (outputBuffer.Length - outputOffset);
189 fixed (byte* input = &inputBuffer [0])
190 fixed (byte* output = &outputBuffer [0]) {
191 CCCryptorStatus s = Cryptor.CCCryptorUpdate (handle, (IntPtr) (input + inputOffset), in_len, (IntPtr) (output + outputOffset), out_len, ref len);
192 if ((len != out_len) || (s != CCCryptorStatus.Success))
193 throw new CryptographicUnexpectedOperationException (s.ToString ());
195 return (int) out_len;
198 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
200 CheckInput (inputBuffer, inputOffset, inputCount);
202 byte[] output = new byte [inputCount];
203 TransformBlock (inputBuffer, inputOffset, inputCount, output, 0);
207 Cryptor.CCCryptorRelease (handle);
208 handle = IntPtr.Zero;