1 | /******************************************************************************
|
---|
2 | *
|
---|
3 | * Copyright (c) 1998,99 by Mindbright Technology AB, Stockholm, Sweden.
|
---|
4 | * www.mindbright.se, [email protected]
|
---|
5 | *
|
---|
6 | * This program is free software; you can redistribute it and/or modify
|
---|
7 | * it under the terms of the GNU General Public License as published by
|
---|
8 | * the Free Software Foundation; either version 2 of the License, or
|
---|
9 | * (at your option) any later version.
|
---|
10 | *
|
---|
11 | * This program is distributed in the hope that it will be useful,
|
---|
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | * GNU General Public License for more details.
|
---|
15 | *
|
---|
16 | *****************************************************************************
|
---|
17 | * $Author: mats $
|
---|
18 | * $Date: 1999/10/25 12:05:26 $
|
---|
19 | * $Name: rel1-2-1 $
|
---|
20 | *****************************************************************************/
|
---|
21 | /*
|
---|
22 | * !!! Author's comment: The contents of this file is heavily based
|
---|
23 | * upon Tatu Ylonen's c-code (from the ssh1 package). His comments follows:
|
---|
24 | * ...
|
---|
25 | * This code is based on Xuejia Lai: On the Design and Security of Block
|
---|
26 | * Ciphers, ETH Series in Information Processing, vol. 1, Hartung-Gorre
|
---|
27 | * Verlag, Konstanz, Switzerland, 1992. Another source was Bruce
|
---|
28 | * Schneier: Applied Cryptography, John Wiley & Sons, 1994.
|
---|
29 | *
|
---|
30 | * The IDEA mathematical formula may be covered by one or more of the
|
---|
31 | * following patents: PCT/CH91/00117, EP 0 482 154 B1, US Pat. 5,214,703.
|
---|
32 | */
|
---|
33 |
|
---|
34 | package mindbright.security;
|
---|
35 |
|
---|
36 | import java.math.BigInteger;
|
---|
37 |
|
---|
38 | public final class IDEA extends Cipher {
|
---|
39 |
|
---|
40 | protected int[] key_schedule = new int[52];
|
---|
41 | protected int IV0 = 0;
|
---|
42 | protected int IV1 = 0;
|
---|
43 |
|
---|
44 | public synchronized void encrypt(byte[] src, int srcOff, byte[] dest, int destOff, int len) {
|
---|
45 | int[] out = new int[2];
|
---|
46 | int iv0 = IV0;
|
---|
47 | int iv1 = IV1;
|
---|
48 | int end = srcOff + len;
|
---|
49 |
|
---|
50 | for(int si = srcOff, di = destOff; si < end; si += 8, di += 8) {
|
---|
51 | encrypt(iv0, iv1, out);
|
---|
52 | iv0 = out[0];
|
---|
53 | iv1 = out[1];
|
---|
54 | iv0 ^= ((src[si + 3] & 0xff) | ((src[si + 2] & 0xff) << 8) |
|
---|
55 | ((src[si + 1] & 0xff) << 16) | ((src[si] & 0xff) << 24));
|
---|
56 | iv1 ^= ((src[si + 7] & 0xff) | ((src[si + 6] & 0xff) << 8) |
|
---|
57 | ((src[si + 5] & 0xff) << 16) | ((src[si + 4] & 0xff) << 24));
|
---|
58 |
|
---|
59 | if(di + 8 <= end) {
|
---|
60 | dest[di+3] = (byte)( iv0 & 0xff);
|
---|
61 | dest[di+2] = (byte)((iv0 >>> 8 ) & 0xff);
|
---|
62 | dest[di+1] = (byte)((iv0 >>> 16) & 0xff);
|
---|
63 | dest[di] = (byte)((iv0 >>> 24) & 0xff);
|
---|
64 | dest[di+7] = (byte)( iv1 & 0xff);
|
---|
65 | dest[di+6] = (byte)((iv1 >>> 8 ) & 0xff);
|
---|
66 | dest[di+5] = (byte)((iv1 >>> 16) & 0xff);
|
---|
67 | dest[di+4] = (byte)((iv1 >>> 24) & 0xff);
|
---|
68 | } else {
|
---|
69 | switch(end - di) {
|
---|
70 | case 7:
|
---|
71 | dest[di+6] = (byte)((iv1 >>> 8) & 0xff);
|
---|
72 | case 6:
|
---|
73 | dest[di+5] = (byte)((iv1 >>> 16) & 0xff);
|
---|
74 | case 5:
|
---|
75 | dest[di+4] = (byte)((iv1 >>> 24) & 0xff);
|
---|
76 | case 4:
|
---|
77 | dest[di+3] = (byte)( iv0 & 0xff);
|
---|
78 | case 3:
|
---|
79 | dest[di+2] = (byte)((iv0 >>> 8) & 0xff);
|
---|
80 | case 2:
|
---|
81 | dest[di+1] = (byte)((iv0 >>> 16) & 0xff);
|
---|
82 | case 1:
|
---|
83 | dest[di] = (byte)((iv0 >>> 24) & 0xff);
|
---|
84 | }
|
---|
85 | }
|
---|
86 | }
|
---|
87 | IV0 = iv0;
|
---|
88 | IV1 = iv1;
|
---|
89 | }
|
---|
90 |
|
---|
91 | public synchronized void decrypt(byte[] src, int srcOff, byte[] dest, int destOff, int len) {
|
---|
92 | int[] out = new int[2];
|
---|
93 | int iv0 = IV0;
|
---|
94 | int iv1 = IV1;
|
---|
95 | int plain0, plain1;
|
---|
96 | int end = srcOff + len;
|
---|
97 |
|
---|
98 | for(int si = srcOff, di = destOff; si < end; si += 8, di += 8) {
|
---|
99 | decrypt(iv0, iv1, out);
|
---|
100 | iv0 = ((src[si + 3] & 0xff) | ((src[si + 2] & 0xff) << 8) |
|
---|
101 | ((src[si + 1] & 0xff) << 16) | ((src[si] & 0xff) << 24));
|
---|
102 | iv1 = ((src[si + 7] & 0xff) | ((src[si + 6] & 0xff) << 8) |
|
---|
103 | ((src[si + 5] & 0xff) << 16) | ((src[si + 4] & 0xff) << 24));
|
---|
104 | plain0 = out[0] ^ iv0;
|
---|
105 | plain1 = out[1] ^ iv1;
|
---|
106 |
|
---|
107 | if(di + 8 <= end) {
|
---|
108 | dest[di+3] = (byte)( plain0 & 0xff);
|
---|
109 | dest[di+2] = (byte)((plain0 >>> 8 ) & 0xff);
|
---|
110 | dest[di+1] = (byte)((plain0 >>> 16) & 0xff);
|
---|
111 | dest[di] = (byte)((plain0 >>> 24) & 0xff);
|
---|
112 | dest[di+7] = (byte)( plain1 & 0xff);
|
---|
113 | dest[di+6] = (byte)((plain1 >>> 8 ) & 0xff);
|
---|
114 | dest[di+5] = (byte)((plain1 >>> 16) & 0xff);
|
---|
115 | dest[di+4] = (byte)((plain1 >>> 24) & 0xff);
|
---|
116 | } else {
|
---|
117 | switch(end - di) {
|
---|
118 | case 7:
|
---|
119 | dest[di+6] = (byte)((plain1 >>> 8) & 0xff);
|
---|
120 | case 6:
|
---|
121 | dest[di+5] = (byte)((plain1 >>> 16) & 0xff);
|
---|
122 | case 5:
|
---|
123 | dest[di+4] = (byte)((plain1 >>> 24) & 0xff);
|
---|
124 | case 4:
|
---|
125 | dest[di+3] = (byte)( plain0 & 0xff);
|
---|
126 | case 3:
|
---|
127 | dest[di+2] = (byte)((plain0 >>> 8) & 0xff);
|
---|
128 | case 2:
|
---|
129 | dest[di+1] = (byte)((plain0 >>> 16) & 0xff);
|
---|
130 | case 1:
|
---|
131 | dest[di] = (byte)((plain0 >>> 24) & 0xff);
|
---|
132 | }
|
---|
133 | }
|
---|
134 | }
|
---|
135 | IV0 = iv0;
|
---|
136 | IV1 = iv1;
|
---|
137 | }
|
---|
138 |
|
---|
139 | public void setKey(byte[] key) {
|
---|
140 | int i, ki = 0, j = 0;
|
---|
141 | for(i = 0; i < 8; i++)
|
---|
142 | key_schedule[i] = ((key[2 * i] & 0xff) << 8) | (key[(2 * i) + 1] & 0xff);
|
---|
143 |
|
---|
144 | for(i = 8, j = 0; i < 52; i++) {
|
---|
145 | j++;
|
---|
146 | key_schedule[ki + j + 7] = ((key_schedule[ki + (j & 7)] << 9) |
|
---|
147 | (key_schedule[ki + ((j + 1) & 7)] >>> 7)) & 0xffff;
|
---|
148 | ki += j & 8;
|
---|
149 | j &= 7;
|
---|
150 | }
|
---|
151 | }
|
---|
152 |
|
---|
153 | public final void encrypt(int l, int r, int[] out) {
|
---|
154 | int t1 = 0, t2 = 0, x1, x2, x3, x4, ki = 0;
|
---|
155 |
|
---|
156 | x1 = (l >>> 16);
|
---|
157 | x2 = (l & 0xffff);
|
---|
158 | x3 = (r >>> 16);
|
---|
159 | x4 = (r & 0xffff);
|
---|
160 |
|
---|
161 | for(int round = 0; round < 8; round++) {
|
---|
162 | x1 = mulop(x1 & 0xffff, key_schedule[ki++]);
|
---|
163 | x2 = (x2 + key_schedule[ki++]);
|
---|
164 | x3 = (x3 + key_schedule[ki++]);
|
---|
165 | x4 = mulop(x4 & 0xffff, key_schedule[ki++]);
|
---|
166 |
|
---|
167 | t1 = (x1 ^ x3);
|
---|
168 | t2 = (x2 ^ x4);
|
---|
169 | t1 = mulop(t1 & 0xffff, key_schedule[ki++]);
|
---|
170 | t2 = (t1 + t2);
|
---|
171 | t2 = mulop(t2 & 0xffff, key_schedule[ki++]);
|
---|
172 | t1 = (t1 + t2);
|
---|
173 |
|
---|
174 | x1 = (x1 ^ t2);
|
---|
175 | x4 = (x4 ^ t1);
|
---|
176 | t1 = (t1 ^ x2);
|
---|
177 | x2 = (t2 ^ x3);
|
---|
178 | x3 = t1;
|
---|
179 | }
|
---|
180 |
|
---|
181 | t2 = x2;
|
---|
182 | x1 = mulop(x1 & 0xffff, key_schedule[ki++]);
|
---|
183 | x2 = (t1 + key_schedule[ki++]);
|
---|
184 | x3 = ((t2 + key_schedule[ki++]) & 0xffff);
|
---|
185 | x4 = mulop(x4 & 0xffff, key_schedule[ki]);
|
---|
186 |
|
---|
187 |
|
---|
188 | out[0] = (x1 << 16) | (x2 & 0xffff);
|
---|
189 | out[1] = (x3 << 16) | (x4 & 0xffff);
|
---|
190 | }
|
---|
191 |
|
---|
192 | public final void decrypt(int l, int r, int[] out) {
|
---|
193 | encrypt(l, r, out);
|
---|
194 | }
|
---|
195 |
|
---|
196 | public static final int mulop(int a, int b) {
|
---|
197 | int ab = a * b;
|
---|
198 | if(ab != 0) {
|
---|
199 | int lo = ab & 0xffff;
|
---|
200 | int hi = (ab >>> 16) & 0xffff;
|
---|
201 | return ((lo - hi) + ((lo < hi) ? 1 : 0));
|
---|
202 | }
|
---|
203 | if(a == 0)
|
---|
204 | return (1 - b);
|
---|
205 | return (1 - a);
|
---|
206 | }
|
---|
207 |
|
---|
208 | /* !!! REMOVE DEBUG !!!
|
---|
209 |
|
---|
210 | public static void main(String[] argv) {
|
---|
211 | byte[] key = {
|
---|
212 | (byte)0xd3, (byte)0x96, (byte)0xcf, (byte)0x07, (byte)0xfa, (byte)0xa2, (byte)0x64,
|
---|
213 | (byte)0xfe, (byte)0xf3, (byte)0xa2, (byte)0x06, (byte)0x07, (byte)0x1a, (byte)0xb6,
|
---|
214 | (byte)0x13, (byte)0xf6
|
---|
215 | };
|
---|
216 |
|
---|
217 | byte[] txt = {
|
---|
218 | (byte)0x2e, (byte)0xbe, (byte)0xc5, (byte)0xac, (byte)0x02, (byte)0xa1, (byte)0xd5,
|
---|
219 | (byte)0x7f, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1f, (byte)0x43,
|
---|
220 | (byte)0x6f, (byte)0x72, (byte)0x72, (byte)0x75, (byte)0x70, (byte)0x74, (byte)0x65,
|
---|
221 | (byte)0x64, (byte)0x20, (byte)0x63, (byte)0x68, (byte)0x65, (byte)0x63, (byte)0x6b,
|
---|
222 | (byte)0x20, (byte)0x62, (byte)0x79, (byte)0x74, (byte)0x65, (byte)0x73, (byte)0x20,
|
---|
223 | (byte)0x6f, (byte)0x6e, (byte)0x20, (byte)0x69, (byte)0x6e, (byte)0x70, (byte)0x75,
|
---|
224 | (byte)0x74, (byte)0x2e, (byte)0x91, (byte)0x9a, (byte)0x57, (byte)0xdd
|
---|
225 | };
|
---|
226 |
|
---|
227 | byte[] enc;
|
---|
228 | byte[] dec;
|
---|
229 |
|
---|
230 | System.out.println("key: " + printHex(key));
|
---|
231 | System.out.println("txt: " + printHex(txt));
|
---|
232 |
|
---|
233 | IDEA cipher = new IDEA();
|
---|
234 | cipher.setKey(key);
|
---|
235 |
|
---|
236 | for(int i = 0; i < 52; i++) {
|
---|
237 | if((i & 0x7) == 0)
|
---|
238 | System.out.println("");
|
---|
239 | System.out.print(" " + cipher.key_schedule[i]);
|
---|
240 | }
|
---|
241 |
|
---|
242 | enc = cipher.encrypt(txt);
|
---|
243 | System.out.println("enc: " + printHex(enc));
|
---|
244 |
|
---|
245 | cipher = new IDEA();
|
---|
246 | cipher.setKey(key);
|
---|
247 | dec = cipher.decrypt(enc);
|
---|
248 |
|
---|
249 | System.out.println("dec: " + printHex(dec));
|
---|
250 | }
|
---|
251 |
|
---|
252 | static String printHex(byte[] buf) {
|
---|
253 | byte[] out = new byte[buf.length + 1];
|
---|
254 | out[0] = 0;
|
---|
255 | System.arraycopy(buf, 0, out, 1, buf.length);
|
---|
256 | BigInteger big = new BigInteger(out);
|
---|
257 | return big.toString(16);
|
---|
258 | }
|
---|
259 |
|
---|
260 | */
|
---|
261 |
|
---|
262 | }
|
---|
263 |
|
---|