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