2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / class / corlib / System.Security.Cryptography / RC2CryptoServiceProvider.cs
blobade2b040e3e26e9c0efa94126e78a9fd894af2d5
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)
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.
31 using System.Globalization;
32 using System.Runtime.InteropServices;
34 using Mono.Security.Cryptography;
36 namespace System.Security.Cryptography {
38 // References:
39 // a. IETF RFC2286: A Description of the RC2(r) Encryption Algorithm
40 // http://www.ietf.org/rfc/rfc2268.txt
42 [ComVisible (true)]
43 public sealed class RC2CryptoServiceProvider : RC2 {
44 private bool _useSalt;
46 public RC2CryptoServiceProvider ()
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"));
57 base.EffectiveKeySize = value;
61 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
63 return new RC2Transform (this, false, rgbKey, rgbIV);
66 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
68 return new RC2Transform (this, true, rgbKey, rgbIV);
71 public override void GenerateIV ()
73 IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
76 public override void GenerateKey ()
78 KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
80 [MonoTODO ("Use salt in algorithm")]
81 [ComVisible (false)]
82 public bool UseSalt {
83 get { return _useSalt; }
84 set { _useSalt = value; }
88 internal class RC2Transform : SymmetricTransform {
90 private UInt16 R0, R1, R2, R3; // state
91 private UInt16[] K; // expanded key
92 private int j; // Key indexer
94 public RC2Transform (RC2 rc2Algo, bool encryption, byte[] key, byte[] iv)
95 : base (rc2Algo, encryption, iv)
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);
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);
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];
120 int t8 = ((t1 + 7) >> 3); // divide by 8
121 int tm = 255 % (2 << (8 + t1 - (t8 << 3) - 1));
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]);
128 L [128-t8] = pitable [L [128-t8] & tm];
130 for (int i=127-t8; i >= 0; i--)
131 L [i] = pitable [L [i+1] ^ L [i+t8]];
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));
139 protected override void ECB (byte[] input, byte[] output)
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));
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));
154 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
155 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
157 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
158 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
160 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
161 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
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];
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));
175 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
176 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
178 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
179 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
181 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
182 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
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];
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));
196 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
197 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
199 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
200 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
202 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
203 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
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));
213 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
214 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
216 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
217 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
219 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
220 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
223 // inline RMash();
224 R3 -= K [R2 & 63];
225 R2 -= K [R1 & 63];
226 R1 -= K [R0 & 63];
227 R0 -= K [R3 & 63];
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));
234 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
235 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
237 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
238 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
240 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
241 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
244 // inline RMash();
245 R3 -= K [R2 & 63];
246 R2 -= K [R1 & 63];
247 R1 -= K [R0 & 63];
248 R0 -= K [R3 & 63];
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));
255 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
256 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
258 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
259 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
261 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
262 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
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);
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