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