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 // (C) 2004 Novell (http://www.novell.com)
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Globalization;
38 using Mono.Security.Cryptography;
40 namespace System.Security.Cryptography {
43 // a. IETF RFC2286: A Description of the RC2(r) Encryption Algorithm
44 // http://www.ietf.org/rfc/rfc2268.txt
46 public sealed class RC2CryptoServiceProvider : RC2 {
48 public RC2CryptoServiceProvider ()
52 public override int EffectiveKeySize {
53 get { return base.EffectiveKeySize; }
55 if (value != KeySizeValue) {
56 throw new CryptographicException (
57 Locale.GetText ("Effective key size must match key size for compatibility"));
59 base.EffectiveKeySize = value;
63 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
67 return new RC2Transform (this, false);
70 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
74 return new RC2Transform (this, true);
77 public override void GenerateIV ()
79 IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
82 public override void GenerateKey ()
84 KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
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) : base (rc2Algo, encryption, rc2Algo.IV)
96 byte[] key = rc2Algo.Key;
97 int t1 = rc2Algo.EffectiveKeySize;
98 // Expand key into a byte array, then convert to word
99 // array since we always access the key in 16bit chunks.
100 byte[] L = new byte [128];
103 int t8 = ((t1 + 7) >> 3); // divide by 8
104 int tm = 255 % (2 << (8 + t1 - (t8 << 3) - 1));
106 for (int i=0; i < t; i++)
108 for (int i=t; i < 128; i++)
109 L [i] = (byte) (pitable [(L [i-1] + L [i-t]) & 0xff]);
111 L [128-t8] = pitable [L [128-t8] & tm];
113 for (int i=127-t8; i >= 0; i--)
114 L [i] = pitable [L [i+1] ^ L [i+t8]];
118 for (int i=0; i < 64; i++)
119 K [i] = (UInt16) (L [pos++] + (L [pos++] << 8));
122 protected override void ECB (byte[] input, byte[] output)
124 // unrolled loop, eliminated mul
125 R0 = (UInt16) (input [0] | (input [1] << 8));
126 R1 = (UInt16) (input [2] | (input [3] << 8));
127 R2 = (UInt16) (input [4] | (input [5] << 8));
128 R3 = (UInt16) (input [6] | (input [7] << 8));
132 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
134 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
135 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
137 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
138 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
140 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
141 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
143 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
144 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
147 // inline Mash(); j == 20
153 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix(); Mix();
155 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
156 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
158 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
159 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
161 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
162 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
164 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
165 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
168 // inline Mash(); j == 44
174 // inline, but looped, Mix(); Mix(); Mix(); Mix(); Mix();
176 R0 += (UInt16) (K[j++] + (R3 & R2) + ((~R3) & R1));
177 R0 = (UInt16) ((R0 << 1) | (R0 >> 15));
179 R1 += (UInt16) (K[j++] + (R0 & R3) + ((~R0) & R2));
180 R1 = (UInt16) ((R1 << 2) | (R1 >> 14));
182 R2 += (UInt16) (K[j++] + (R1 & R0) + ((~R1) & R3));
183 R2 = (UInt16) ((R2 << 3) | (R2 >> 13));
185 R3 += (UInt16) (K[j++] + (R2 & R1) + ((~R2) & R0));
186 R3 = (UInt16) ((R3 << 5) | (R3 >> 11));
191 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
193 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
194 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
196 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
197 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
199 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
200 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
202 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
203 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
212 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix(); RMix();
214 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
215 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
217 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
218 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
220 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
221 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
223 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
224 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
233 // inline, but looped, RMix(); RMix(); RMix(); RMix(); RMix();
235 R3 = (UInt16) ((R3 >> 5) | (R3 << 11));
236 R3 -= (UInt16) (K[j--] + (R2 & R1) + ((~R2) & R0));
238 R2 = (UInt16) ((R2 >> 3) | (R2 << 13));
239 R2 -= (UInt16) (K[j--] + (R1 & R0) + ((~R1) & R3));
241 R1 = (UInt16) ((R1 >> 2) | (R1 << 14));
242 R1 -= (UInt16) (K[j--] + (R0 & R3) + ((~R0) & R2));
244 R0 = (UInt16) ((R0 >> 1) | (R0 << 15));
245 R0 -= (UInt16) (K[j--] + (R3 & R2) + ((~R3) & R1));
250 output[0] = (byte) R0;
251 output[1] = (byte) (R0 >> 8);
252 output[2] = (byte) R1;
253 output[3] = (byte) (R1 >> 8);
254 output[4] = (byte) R2;
255 output[5] = (byte) (R2 >> 8);
256 output[6] = (byte) R3;
257 output[7] = (byte) (R3 >> 8);
260 static readonly byte[] pitable = {
261 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed,
262 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
263 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e,
264 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
265 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13,
266 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
267 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b,
268 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
269 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c,
270 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
271 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1,
272 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
273 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57,
274 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
275 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7,
276 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
277 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7,
278 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
279 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74,
280 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
281 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc,
282 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
283 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a,
284 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
285 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae,
286 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
287 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c,
288 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
289 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0,
290 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
291 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77,
292 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad