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