New test.
[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                 private bool _useSalt;
48         
49                 public RC2CryptoServiceProvider ()
50                 {
51                 }
52         
53                 public override int EffectiveKeySize {
54                         get { return base.EffectiveKeySize; }
55                         set {
56                                 if (value != KeySizeValue) {
57 #if NET_1_1
58                                         throw new CryptographicUnexpectedOperationException (
59 #else
60                                         throw new CryptographicException (
61 #endif
62                                                 Locale.GetText ("Effective key size must match key size for compatibility"));
63                                 }
64                                 base.EffectiveKeySize = value; 
65                         }
66                 }
67         
68                 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
69                 {
70                         return new RC2Transform (this, false, rgbKey, rgbIV);
71                 }
72         
73                 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
74                 {
75                         return new RC2Transform (this, true, rgbKey, rgbIV);
76                 }
77         
78                 public override void GenerateIV ()
79                 {
80                         IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
81                 }
82         
83                 public override void GenerateKey ()
84                 {
85                         KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
86                 }
87 #if NET_2_0
88                 [MonoTODO ("Use salt in algorithm")]
89                 [ComVisible (false)]
90                 public bool UseSalt {
91                         get { return _useSalt; }
92                         set { _useSalt = value; }
93                 }
94 #endif
95         }
96         
97         internal class RC2Transform : SymmetricTransform {
98         
99                 private UInt16 R0, R1, R2, R3;  // state
100                 private UInt16[] K;             // expanded key
101                 private int j;                  // Key indexer
102         
103                 public RC2Transform (RC2 rc2Algo, bool encryption, byte[] key, byte[] iv)
104                         : base (rc2Algo, encryption, iv)
105                 {
106 #if ONLY_1_1
107                         if (key == null)
108                                 throw new ArgumentNullException ("key");
109 #endif
110                         int t1 = rc2Algo.EffectiveKeySize;
111                         if (key == null) {
112                                 key = KeyBuilder.Key (rc2Algo.KeySize >> 3);
113                         } else {
114                                 key = (byte[]) key.Clone ();
115                                 t1 = Math.Min (t1, key.Length << 3);
116                         }
117
118                         int t = key.Length;
119                         if (!KeySizes.IsLegalKeySize (rc2Algo.LegalKeySizes, (t << 3))) {
120                                 string msg = Locale.GetText ("Key is too small ({0} bytes), it should be between {1} and {2} bytes long.",
121                                         t, 5, 16);
122                                 throw new CryptographicException (msg);
123                         }
124
125                         // Expand key into a byte array, then convert to word
126                         // array since we always access the key in 16bit chunks.
127                         byte[] L = new byte [128];
128         
129                         int t8 = ((t1 + 7) >> 3); // divide by 8
130                         int tm = 255 % (2 << (8 + t1 - (t8 << 3) - 1));
131         
132                         for (int i=0; i < t; i++)
133                                 L [i] = key [i];
134                         for (int i=t; i < 128; i++) 
135                                 L [i] = (byte) (pitable [(L [i-1] + L [i-t]) & 0xff]);
136         
137                         L [128-t8] = pitable [L [128-t8] & tm];
138         
139                         for (int i=127-t8; i >= 0; i--) 
140                                 L [i] = pitable [L [i+1] ^ L [i+t8]];
141         
142                         K = new UInt16 [64];
143                         int pos = 0;
144                         for (int i=0; i < 64; i++) 
145                                 K [i] = (UInt16) (L [pos++] + (L [pos++] << 8));
146                 }
147         
148                 protected override void ECB (byte[] input, byte[] output) 
149                 {
150                         // unrolled loop, eliminated mul
151                         R0 = (UInt16) (input [0] | (input [1] << 8));
152                         R1 = (UInt16) (input [2] | (input [3] << 8));
153                         R2 = (UInt16) (input [4] | (input [5] << 8));
154                         R3 = (UInt16) (input [6] | (input [7] << 8));
155         
156                         if (encrypt) {
157                                 j = 0;
158                                 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
159                                 while (j <= 16) {
160                                         R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
161                                         R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
162         
163                                         R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
164                                         R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
165         
166                                         R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
167                                         R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
168         
169                                         R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
170                                         R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
171                                 }
172         
173                                 // inline Mash(); j == 20
174                                 R0 += K [R3 & 63];
175                                 R1 += K [R0 & 63];
176                                 R2 += K [R1 & 63];
177                                 R3 += K [R2 & 63];
178         
179                                 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix(); Mix();
180                                 while (j <= 40) {
181                                         R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
182                                         R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
183         
184                                         R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
185                                         R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
186         
187                                         R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
188                                         R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
189         
190                                         R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
191                                         R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
192                                 }
193         
194                                 // inline Mash(); j == 44
195                                 R0 += K [R3 & 63];
196                                 R1 += K [R0 & 63];
197                                 R2 += K [R1 & 63];
198                                 R3 += K [R2 & 63];
199         
200                                 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
201                                 while (j < 64) {
202                                         R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
203                                         R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
204         
205                                         R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
206                                         R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
207         
208                                         R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
209                                         R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
210         
211                                         R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
212                                         R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
213                                 }
214                         } 
215                         else {
216                                 j = 63;
217                                 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
218                                 while (j >= 44) {
219                                         R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
220                                         R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
221         
222                                         R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
223                                         R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
224         
225                                         R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
226                                         R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
227         
228                                         R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
229                                         R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
230                                 }
231         
232                                 // inline RMash();
233                                 R3 -= K [R2 & 63];
234                                 R2 -= K [R1 & 63];
235                                 R1 -= K [R0 & 63];
236                                 R0 -= K [R3 & 63];
237         
238                                 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix(); RMix();
239                                 while (j >= 20) {
240                                         R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
241                                         R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
242         
243                                         R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
244                                         R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
245         
246                                         R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
247                                         R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
248         
249                                         R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
250                                         R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
251                                 }
252         
253                                 // inline RMash();
254                                 R3 -= K [R2 & 63];
255                                 R2 -= K [R1 & 63];
256                                 R1 -= K [R0 & 63];
257                                 R0 -= K [R3 & 63];
258         
259                                 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
260                                 while (j >= 0) {
261                                         R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
262                                         R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
263         
264                                         R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
265                                         R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
266         
267                                         R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
268                                         R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
269         
270                                         R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
271                                         R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
272                                 }
273                         }
274         
275                         // unrolled loop
276                         output[0] = (byte) R0;
277                         output[1] = (byte) (R0 >> 8);
278                         output[2] = (byte) R1;
279                         output[3] = (byte) (R1 >> 8);
280                         output[4] = (byte) R2;
281                         output[5] = (byte) (R2 >> 8);
282                         output[6] = (byte) R3;
283                         output[7] = (byte) (R3 >> 8);
284                 }
285         
286                 static readonly byte[] pitable = {
287                         0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 
288                         0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
289                         0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 
290                         0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
291                         0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 
292                         0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
293                         0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 
294                         0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
295                         0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 
296                         0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
297                         0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 
298                         0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
299                         0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 
300                         0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
301                         0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 
302                         0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
303                         0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 
304                         0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
305                         0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 
306                         0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
307                         0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 
308                         0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
309                         0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 
310                         0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
311                         0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 
312                         0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
313                         0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 
314                         0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
315                         0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 
316                         0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
317                         0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 
318                         0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad 
319                 };
320         }
321 }