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