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
43 public sealed class RC2CryptoServiceProvider : RC2 {
44 private bool _useSalt;
46 public RC2CryptoServiceProvider ()
50 public override int EffectiveKeySize {
51 get { return base.EffectiveKeySize; }
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")]
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 int t1 = rc2Algo.EffectiveKeySize;
99 key = KeyBuilder.Key (rc2Algo.KeySize >> 3);
101 key = (byte[]) key.Clone ();
102 t1 = Math.Min (t1, key.Length << 3);
106 if (!KeySizes.IsLegalKeySize (rc2Algo.LegalKeySizes, (t << 3))) {
107 string msg = Locale.GetText ("Key is too small ({0} bytes), it should be between {1} and {2} bytes long.",
109 throw new CryptographicException (msg);
112 // Expand key into a byte array, then convert to word
113 // array since we always access the key in 16bit chunks.
114 byte[] L = new byte [128];
116 int t8 = ((t1 + 7) >> 3); // divide by 8
117 int tm = 255 % (2 << (8 + t1 - (t8 << 3) - 1));
119 for (int i=0; i < t; i++)
121 for (int i=t; i < 128; i++)
122 L [i] = (byte) (pitable [(L [i-1] + L [i-t]) & 0xff]);
124 L [128-t8] = pitable [L [128-t8] & tm];
126 for (int i=127-t8; i >= 0; i--)
127 L [i] = pitable [L [i+1] ^ L [i+t8]];
131 for (int i=0; i < 64; i++)
132 K [i] = (UInt16) (L [pos++] + (L [pos++] << 8));
135 protected override void ECB (byte[] input, byte[] output)
137 // unrolled loop, eliminated mul
138 R0 = (UInt16) (input [0] | (input [1] << 8));
139 R1 = (UInt16) (input [2] | (input [3] << 8));
140 R2 = (UInt16) (input [4] | (input [5] << 8));
141 R3 = (UInt16) (input [6] | (input [7] << 8));
145 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
147 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
148 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
150 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
151 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
153 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
154 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
156 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
157 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
160 // inline Mash(); j == 20
166 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix(); Mix();
168 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
169 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
171 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
172 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
174 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
175 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
177 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
178 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
181 // inline Mash(); j == 44
187 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
189 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
190 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
192 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
193 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
195 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
196 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
198 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
199 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
204 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
206 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
207 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
209 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
210 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
212 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
213 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
215 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
216 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
225 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix(); RMix();
227 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
228 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
230 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
231 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
233 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
234 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
236 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
237 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
246 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
248 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
249 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
251 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
252 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
254 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
255 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
257 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
258 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
263 output[0] = (byte) R0;
264 output[1] = (byte) (R0 >> 8);
265 output[2] = (byte) R1;
266 output[3] = (byte) (R1 >> 8);
267 output[4] = (byte) R2;
268 output[5] = (byte) (R2 >> 8);
269 output[6] = (byte) R3;
270 output[7] = (byte) (R3 >> 8);
273 static readonly byte[] pitable = {
274 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed,
275 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
276 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e,
277 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
278 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13,
279 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
280 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b,
281 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
282 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c,
283 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
284 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1,
285 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
286 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57,
287 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
288 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7,
289 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
290 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7,
291 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
292 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74,
293 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
294 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc,
295 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
296 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a,
297 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
298 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae,
299 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
300 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c,
301 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
302 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0,
303 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
304 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77,
305 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad