Merge pull request #2820 from kumpera/license-change-rebased
[mono.git] / mcs / class / corlib / CommonCrypto / RC4CommonCrypto.cs
1 // A CommonCrypto-based implementation of RC4(tm)
2 //
3 // Authors:
4 //      Sebastien Pouliot  <sebastien@xamarin.com>
5 //
6 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
7 // Copyright 2012-2014 Xamarin Inc.
8
9 using System;
10 using System.Security.Cryptography;
11
12 using Crimson.CommonCrypto;
13
14 #if MONOTOUCH || XAMMAC
15 using Mono.Security.Cryptography;
16
17 namespace Mono.Security.Cryptography {
18
19 #if !INSIDE_CORLIB
20         public
21 #endif
22         sealed partial class ARC4Managed : RC4, ICryptoTransform {
23                 
24                 IntPtr handle;
25                 
26                 public ARC4Managed ()
27                 {
28                 }
29                 
30                 ~ARC4Managed ()
31                 {
32                         Dispose (false);
33                 }
34 #else
35 namespace Crimson.Security.Cryptography {
36
37         public abstract class RC4 : SymmetricAlgorithm {
38
39                 private static KeySizes[] s_legalBlockSizes = {
40                         new KeySizes (64, 64, 0)
41                 };
42
43                 private static KeySizes[] s_legalKeySizes = {
44                         new KeySizes (40, 512, 8)  
45                 };
46         
47                 public RC4 () 
48                 {
49                         KeySizeValue = 128;
50                         BlockSizeValue = 64;
51                         FeedbackSizeValue = BlockSizeValue;
52                         LegalBlockSizesValue = s_legalBlockSizes;
53                         LegalKeySizesValue = s_legalKeySizes;
54                 }
55
56                 // required for compatibility with .NET 2.0
57                 public override byte[] IV {
58                         get { return new byte [0]; }
59                         set { ; }
60                 }
61
62                 new static public RC4 Create() 
63                 {
64                         return Create ("RC4");
65                 }
66
67                 new static public RC4 Create (string algName) 
68                 {
69                         object o = CryptoConfig.CreateFromName (algName);
70                         return (RC4) o ?? new RC4CommonCrypto ();
71                 }
72         }
73
74         public sealed class RC4CommonCrypto : RC4, ICryptoTransform {
75                 
76                 IntPtr handle;
77                 
78                 public RC4CommonCrypto ()
79                 {
80                 }
81                 
82                 ~RC4CommonCrypto ()
83                 {
84                         Dispose (false);
85                 }
86 #endif
87                 
88                 public bool CanReuseTransform {
89                         get { return false; }
90                 }
91
92                 public bool CanTransformMultipleBlocks {
93                         get { return true; }
94                 }
95                 
96                 public int InputBlockSize {
97                         get { return 1; }
98                 }
99
100                 public int OutputBlockSize {
101                         get { return 1; }
102                 }
103                 
104                 public override byte[] Key {
105                         get {
106                                 return base.Key;
107                         }
108                         set {
109                                 if (value == null)
110                                         throw new ArgumentNullException ("Key");
111
112                                 int length = (value.Length << 3);
113                                 KeySizeValue = length;
114                                 KeyValue = (byte[]) value.Clone ();
115                         }
116                 }
117                 
118                 protected override void Dispose (bool disposing)
119                 {
120                         if (handle != IntPtr.Zero) {
121                                 Cryptor.CCCryptorRelease (handle);
122                                 handle = IntPtr.Zero;
123                         }
124                         base.Dispose (disposing);
125                         GC.SuppressFinalize (this);
126                 }
127                 
128                 public override void GenerateIV ()
129                 {
130                         // not used for a stream cipher
131                         IVValue = new byte [0];
132                 }
133                 
134                 public override void GenerateKey ()
135                 {
136                         KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
137                 }
138                 
139                 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV) 
140                 {
141                         KeyValue = rgbKey;
142                         IVValue = rgbIV;
143                         return this;
144                 }
145                 
146                 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV) 
147                 {
148                         KeyValue = rgbKey;
149                         IVValue = rgbIV;
150                         return this;
151                 }
152
153                 private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
154                 {
155                         if (inputBuffer == null)
156                                 throw new ArgumentNullException ("inputBuffer");
157                         if (inputOffset < 0)
158                                 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
159                         if (inputCount < 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");
164                 }
165
166                 public unsafe int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) 
167                 {
168                         CheckInput (inputBuffer, inputOffset, inputCount);
169                         if (inputCount == 0)
170                                 return 0;
171
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");
182                         
183                         if (handle == IntPtr.Zero)
184                                 handle = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.RC4, CCOptions.None, KeyValue, IVValue);
185
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 ());
194                         }
195                         return (int) out_len;
196                 }
197                 
198                 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
199                 {
200                         CheckInput (inputBuffer, inputOffset, inputCount);
201                         try {
202                                 byte[] output = new byte [inputCount];
203                                 TransformBlock (inputBuffer, inputOffset, inputCount, output, 0);
204                                 return output;
205                         }
206                         finally {
207                                 Cryptor.CCCryptorRelease (handle);
208                                 handle = IntPtr.Zero;
209                         }
210                 }
211         }
212 }