2 // System.Security.Cryptography.RC2CryptoServiceProvider.cs
5 // Andrew Birkett (andy@nobugs.org)
6 // Sebastien Pouliot (sebastien@ximian.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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 {
39 // a. IETF RFC2286: A Description of the RC2(r) Encryption Algorithm
40 // http://www.ietf.org/rfc/rfc2268.txt
45 public sealed class RC2CryptoServiceProvider : RC2 {
47 private bool _useSalt;
49 public RC2CryptoServiceProvider ()
53 public override int EffectiveKeySize {
54 get { return base.EffectiveKeySize; }
56 if (value != KeySizeValue) {
58 throw new CryptographicUnexpectedOperationException (
60 throw new CryptographicException (
62 Locale.GetText ("Effective key size must match key size for compatibility"));
64 base.EffectiveKeySize = value;
68 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
70 return new RC2Transform (this, false, rgbKey, rgbIV);
73 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
75 return new RC2Transform (this, true, rgbKey, rgbIV);
78 public override void GenerateIV ()
80 IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
83 public override void GenerateKey ()
85 KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
88 [MonoTODO ("Use salt in algorithm")]
91 get { return _useSalt; }
92 set { _useSalt = value; }
97 internal class RC2Transform : SymmetricTransform {
99 private UInt16 R0, R1, R2, R3; // state
100 private UInt16[] K; // expanded key
101 private int j; // Key indexer
103 public RC2Transform (RC2 rc2Algo, bool encryption, byte[] key, byte[] iv)
104 : base (rc2Algo, encryption, iv)
108 throw new ArgumentNullException ("key");
110 int t1 = rc2Algo.EffectiveKeySize;
112 key = KeyBuilder.Key (rc2Algo.KeySize >> 3);
114 key = (byte[]) key.Clone ();
115 t1 = Math.Min (t1, key.Length << 3);
119 if (!KeySizes.IsLegalKeySize (rc2Algo.LegalKeySizes, (t << 3))) {
120 string msg = Locale.GetText ("Key is too small ({0} bytes), it should be between {1} and {2} bytes long.",
122 throw new CryptographicException (msg);
125 // Expand key into a byte array, then convert to word
126 // array since we always access the key in 16bit chunks.
127 byte[] L = new byte [128];
129 int t8 = ((t1 + 7) >> 3); // divide by 8
130 int tm = 255 % (2 << (8 + t1 - (t8 << 3) - 1));
132 for (int i=0; i < t; i++)
134 for (int i=t; i < 128; i++)
135 L [i] = (byte) (pitable [(L [i-1] + L [i-t]) & 0xff]);
137 L [128-t8] = pitable [L [128-t8] & tm];
139 for (int i=127-t8; i >= 0; i--)
140 L [i] = pitable [L [i+1] ^ L [i+t8]];
144 for (int i=0; i < 64; i++)
145 K [i] = (UInt16) (L [pos++] + (L [pos++] << 8));
148 protected override void ECB (byte[] input, byte[] output)
150 // unrolled loop, eliminated mul
151 R0 = (UInt16) (input [0] | (input [1] << 8));
152 R1 = (UInt16) (input [2] | (input [3] << 8));
153 R2 = (UInt16) (input [4] | (input [5] << 8));
154 R3 = (UInt16) (input [6] | (input [7] << 8));
158 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
160 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
161 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
163 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
164 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
166 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
167 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
169 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
170 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
173 // inline Mash(); j == 20
179 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix(); Mix();
181 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
182 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
184 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
185 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
187 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
188 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
190 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
191 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
194 // inline Mash(); j == 44
200 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
202 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
203 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
205 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
206 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
208 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
209 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
211 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
212 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
217 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
219 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
220 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
222 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
223 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
225 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
226 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
228 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
229 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
238 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix(); RMix();
240 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
241 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
243 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
244 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
246 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
247 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
249 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
250 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
259 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
261 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
262 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
264 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
265 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
267 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
268 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
270 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
271 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
276 output[0] = (byte) R0;
277 output[1] = (byte) (R0 >> 8);
278 output[2] = (byte) R1;
279 output[3] = (byte) (R1 >> 8);
280 output[4] = (byte) R2;
281 output[5] = (byte) (R2 >> 8);
282 output[6] = (byte) R3;
283 output[7] = (byte) (R3 >> 8);
286 static readonly byte[] pitable = {
287 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed,
288 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
289 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e,
290 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
291 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13,
292 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
293 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b,
294 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
295 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c,
296 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
297 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1,
298 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
299 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57,
300 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
301 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7,
302 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
303 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7,
304 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
305 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74,
306 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
307 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc,
308 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
309 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a,
310 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
311 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae,
312 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
313 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c,
314 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
315 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0,
316 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
317 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77,
318 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad