Moved ProviderCollectionTest.cs from System assembly to System.Configuration.
[mono.git] / mcs / class / corlib / System.Security.Cryptography / RC2CryptoServiceProvider.cs
1 //
2 // System.Security.Cryptography.RC2CryptoServiceProvider.cs
3 //
4 // Authors:
5 //      Andrew Birkett (andy@nobugs.org)
6 //      Sebastien Pouliot (sebastien@ximian.com)
7 //
8 // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Globalization;
32 using System.Runtime.InteropServices;
33
34 using Mono.Security.Cryptography;
35
36 namespace System.Security.Cryptography {
37
38         // References:
39         // a.   IETF RFC2286: A Description of the RC2(r) Encryption Algorithm
40         //      http://www.ietf.org/rfc/rfc2268.txt
41         
42 #if NET_2_0
43         [ComVisible (true)]
44 #endif
45         public sealed class RC2CryptoServiceProvider : RC2 {
46
47 #if NET_2_0
48                 private bool _useSalt;
49 #endif          
50         
51                 public RC2CryptoServiceProvider ()
52                 {
53                 }
54         
55                 public override int EffectiveKeySize {
56                         get { return base.EffectiveKeySize; }
57                         set {
58                                 if (value != KeySizeValue) {
59 #if NET_1_1
60                                         throw new CryptographicUnexpectedOperationException (
61 #else
62                                         throw new CryptographicException (
63 #endif
64                                                 Locale.GetText ("Effective key size must match key size for compatibility"));
65                                 }
66                                 base.EffectiveKeySize = value; 
67                         }
68                 }
69         
70                 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
71                 {
72                         return new RC2Transform (this, false, rgbKey, rgbIV);
73                 }
74         
75                 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
76                 {
77                         return new RC2Transform (this, true, rgbKey, rgbIV);
78                 }
79         
80                 public override void GenerateIV ()
81                 {
82                         IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
83                 }
84         
85                 public override void GenerateKey ()
86                 {
87                         KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
88                 }
89 #if NET_2_0
90                 [MonoTODO ("Use salt in algorithm")]
91                 [ComVisible (false)]
92                 public bool UseSalt {
93                         get { return _useSalt; }
94                         set { _useSalt = value; }
95                 }
96 #endif
97         }
98         
99         internal class RC2Transform : SymmetricTransform {
100         
101                 private UInt16 R0, R1, R2, R3;  // state
102                 private UInt16[] K;             // expanded key
103                 private int j;                  // Key indexer
104         
105                 public RC2Transform (RC2 rc2Algo, bool encryption, byte[] key, byte[] iv)
106                         : base (rc2Algo, encryption, iv)
107                 {
108 #if ONLY_1_1
109                         if (key == null)
110                                 throw new ArgumentNullException ("key");
111 #endif
112                         int t1 = rc2Algo.EffectiveKeySize;
113                         if (key == null) {
114                                 key = KeyBuilder.Key (rc2Algo.KeySize >> 3);
115                         } else {
116                                 key = (byte[]) key.Clone ();
117                                 t1 = Math.Min (t1, key.Length << 3);
118                         }
119
120                         int t = key.Length;
121                         if (!KeySizes.IsLegalKeySize (rc2Algo.LegalKeySizes, (t << 3))) {
122                                 string msg = Locale.GetText ("Key is too small ({0} bytes), it should be between {1} and {2} bytes long.",
123                                         t, 5, 16);
124                                 throw new CryptographicException (msg);
125                         }
126
127                         // Expand key into a byte array, then convert to word
128                         // array since we always access the key in 16bit chunks.
129                         byte[] L = new byte [128];
130         
131                         int t8 = ((t1 + 7) >> 3); // divide by 8
132                         int tm = 255 % (2 << (8 + t1 - (t8 << 3) - 1));
133         
134                         for (int i=0; i < t; i++)
135                                 L [i] = key [i];
136                         for (int i=t; i < 128; i++) 
137                                 L [i] = (byte) (pitable [(L [i-1] + L [i-t]) & 0xff]);
138         
139                         L [128-t8] = pitable [L [128-t8] & tm];
140         
141                         for (int i=127-t8; i >= 0; i--) 
142                                 L [i] = pitable [L [i+1] ^ L [i+t8]];
143         
144                         K = new UInt16 [64];
145                         int pos = 0;
146                         for (int i=0; i < 64; i++) 
147                                 K [i] = (UInt16) (L [pos++] + (L [pos++] << 8));
148                 }
149         
150                 protected override void ECB (byte[] input, byte[] output) 
151                 {
152                         // unrolled loop, eliminated mul
153                         R0 = (UInt16) (input [0] | (input [1] << 8));
154                         R1 = (UInt16) (input [2] | (input [3] << 8));
155                         R2 = (UInt16) (input [4] | (input [5] << 8));
156                         R3 = (UInt16) (input [6] | (input [7] << 8));
157         
158                         if (encrypt) {
159                                 j = 0;
160                                 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
161                                 while (j <= 16) {
162                                         R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
163                                         R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
164         
165                                         R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
166                                         R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
167         
168                                         R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
169                                         R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
170         
171                                         R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
172                                         R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
173                                 }
174         
175                                 // inline Mash(); j == 20
176                                 R0 += K [R3 & 63];
177                                 R1 += K [R0 & 63];
178                                 R2 += K [R1 & 63];
179                                 R3 += K [R2 & 63];
180         
181                                 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix(); Mix();
182                                 while (j <= 40) {
183                                         R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
184                                         R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
185         
186                                         R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
187                                         R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
188         
189                                         R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
190                                         R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
191         
192                                         R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
193                                         R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
194                                 }
195         
196                                 // inline Mash(); j == 44
197                                 R0 += K [R3 & 63];
198                                 R1 += K [R0 & 63];
199                                 R2 += K [R1 & 63];
200                                 R3 += K [R2 & 63];
201         
202                                 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
203                                 while (j < 64) {
204                                         R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
205                                         R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
206         
207                                         R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
208                                         R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
209         
210                                         R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
211                                         R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
212         
213                                         R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
214                                         R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
215                                 }
216                         } 
217                         else {
218                                 j = 63;
219                                 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
220                                 while (j >= 44) {
221                                         R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
222                                         R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
223         
224                                         R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
225                                         R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
226         
227                                         R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
228                                         R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
229         
230                                         R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
231                                         R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
232                                 }
233         
234                                 // inline RMash();
235                                 R3 -= K [R2 & 63];
236                                 R2 -= K [R1 & 63];
237                                 R1 -= K [R0 & 63];
238                                 R0 -= K [R3 & 63];
239         
240                                 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix(); RMix();
241                                 while (j >= 20) {
242                                         R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
243                                         R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
244         
245                                         R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
246                                         R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
247         
248                                         R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
249                                         R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
250         
251                                         R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
252                                         R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
253                                 }
254         
255                                 // inline RMash();
256                                 R3 -= K [R2 & 63];
257                                 R2 -= K [R1 & 63];
258                                 R1 -= K [R0 & 63];
259                                 R0 -= K [R3 & 63];
260         
261                                 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
262                                 while (j >= 0) {
263                                         R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
264                                         R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
265         
266                                         R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
267                                         R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
268         
269                                         R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
270                                         R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
271         
272                                         R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
273                                         R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
274                                 }
275                         }
276         
277                         // unrolled loop
278                         output[0] = (byte) R0;
279                         output[1] = (byte) (R0 >> 8);
280                         output[2] = (byte) R1;
281                         output[3] = (byte) (R1 >> 8);
282                         output[4] = (byte) R2;
283                         output[5] = (byte) (R2 >> 8);
284                         output[6] = (byte) R3;
285                         output[7] = (byte) (R3 >> 8);
286                 }
287         
288                 static readonly byte[] pitable = {
289                         0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 
290                         0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
291                         0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 
292                         0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
293                         0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 
294                         0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
295                         0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 
296                         0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
297                         0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 
298                         0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
299                         0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 
300                         0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
301                         0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 
302                         0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
303                         0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 
304                         0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
305                         0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 
306                         0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
307                         0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 
308                         0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
309                         0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 
310                         0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
311                         0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 
312                         0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
313                         0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 
314                         0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
315                         0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 
316                         0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
317                         0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 
318                         0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
319                         0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 
320                         0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad 
321                 };
322         }
323 }