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