xref: /inferno-os/utils/idea/idea.c (revision 9dc22068e29604f4b484e746112a9a4efe6fd57f)
1 /*
2  * Copyright © 2002 Vita Nuova Holdings Limited.  All rights reserved.
3  */
4 #include <lib9.h>
5 #include <bio.h>
6 
7 /* CBC, ECB, integrate, SSL */
8 
9 #define KEYLEN	52
10 
11 #define	MODA	0x10000
12 #define	MODM	0x10001
13 #define	MASKA	(MODA-1)
14 
15 #define 	OP1(x, y)		((x) ^ (y))
16 #define	OP2(x, y)		(((x) + (y)) & MASKA)
17 #define 	OP3(x, y)		mod(x, y)
18 
19 #define	OP2INV(x)	(-(x))
20 #define	OP3INV(x)	inv(x)
21 
22 #define BIGEND(k, i)	((k[i]<<8)|k[i+1])
23 #define MSB(x)		((x)>>8)
24 #define LSB(x)		((x)&0xff)
25 
26 static ushort
27 mod(ushort x, ushort y)
28 {
29 	ushort q, r;
30 	uint z;
31 
32 	if (x == 0)
33 		return 1-y;
34 	if (y == 0)
35 		return 1-x;
36 	z = (uint)x*(uint)y;
37 	q = z >> 16;
38 	r = z & MASKA;
39 	return r-q+(r<q);
40 }
41 
42 static ushort
43 inv(ushort x)
44 {
45 	int q, r0, r1, r2, v0, v1, v2;
46 
47 	if (x <= 1)
48 		return x;
49 	r0 = MODM;
50 	r1 = x;
51 	v0 = 0;
52 	v1 = 1;
53 	while (r1 != 0) {
54 		q = r0/r1;
55 		r2 = r0-q*r1;
56 		v2 = v0-q*v1;
57 		r0 = r1;
58 		r1 = r2;
59 		v0 = v1;
60 		v1 = v2;
61 	}
62 	if (v0 < 0)
63 		v0 += MODM;
64 	return v0 & MASKA;
65 }
66 
67 static void
68 idea_key_setup_decrypt(ushort ek[KEYLEN], ushort dk[KEYLEN])
69 {
70 	int i;
71 
72 	for (i = 0; i < 54; i += 6) {
73 		dk[i] = OP3INV(ek[48-i]);
74 		dk[i+1] = OP2INV(ek[50-i]);
75 		dk[i+2] = OP2INV(ek[49-i]);
76 		dk[i+3] = OP3INV(ek[51-i]);
77 		if (i < 48) {
78 			dk[i+4] = ek[46-i];
79 			dk[i+5] = ek[47-i];
80 		}
81 	}
82 }
83 
84 void
85 idea_key_setup(uchar key[16], ushort ek[2*KEYLEN])
86 {
87 	int i, j;
88 	ushort tmp, *e = ek;
89 
90 	for (i = 0; i < 8; i++)
91 		ek[i] = BIGEND(key, 2*i);
92 	for (i = 8, j = 1; i < KEYLEN; i++, j++) {
93 		ek[i] = (e[j&7]<<9)|(e[(j+1)&7]>>7);
94 		if (((i+1) & 7) == 0)
95 			e += 8;
96 	}
97 	tmp = ek[49];
98 	ek[49] = ek[50];
99 	ek[50] = tmp;
100 	idea_key_setup_decrypt(ek, &ek[KEYLEN]);
101 }
102 
103 void
104 idea_cipher(ushort key[2*KEYLEN], uchar text[8], int decrypting)
105 {
106 	int i;
107 	ushort *k;
108 	ushort x[4];
109 	ushort tmp, yout, zout;
110 
111 	k = decrypting ? &key[KEYLEN] : key;
112 	for (i = 0; i < 4; i++)
113 		x[i] = BIGEND(text, 2*i);
114 	for (i = 0; i < 17; i++) {
115 		if (!(i&1)) {		/* odd round */
116 			x[0] = OP3(x[0], k[3*i]);
117 			tmp = OP2(x[2], k[3*i+2]);
118 			x[2] = OP2(x[1], k[3*i+1]);
119 			x[3] = OP3(x[3], k[3*i+3]);
120 			x[1] = tmp;
121 		}
122 		else {
123 			tmp = OP3(k[3*i+1], OP1(x[0], x[1]));
124 			yout = OP3(OP2(tmp, OP1(x[2], x[3])), k[3*i+2]);
125 			zout = OP2(tmp, yout);
126 			x[0] = OP1(x[0], yout);
127 			x[1] = OP1(x[1], yout);
128 			x[2] = OP1(x[2], zout);
129 			x[3] = OP1(x[3], zout);
130 		}
131 	}
132 	for (i = 0; i < 4; i++) {
133 		text[2*i] = MSB(x[i]);
134 		text[2*i+1] = LSB(x[i]);
135 	}
136 }
137 
138 static void
139 decerr(char *s)
140 {
141 	fprint(2, "decrypt error: %s (wrong password ?)\n", s);
142 	exits("decrypt");
143 }
144 
145 void
146 main(int argc, char **argv)
147 {
148 /*
149 	uchar key[] = { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
150 			        0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 };
151 	uchar plain[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 };
152 	uchar cipher[] = { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 };
153 	uchar tmp[8];
154 */
155 	ushort edkey[2*KEYLEN];
156 	uchar obuf[8], buf[8], key[16];
157 	long i, m, n, om;
158 	int dec, stdin = 0, stdout = 1;
159 	Biobuf *bin, *bout;
160 
161 /*
162 	memcpy(tmp, plain, 8);
163 	idea_key_setup(key, edkey);
164 	idea_cipher(edkey, tmp, 0);
165 	if (memcmp(tmp, cipher, 8)) {
166 		print("encrypt wrong\n");
167 		exits("");
168 	}
169 	idea_cipher(edkey, tmp, 1);
170 	if (memcmp(tmp, plain, 8)) {
171 		print("decrypt wrong\n");
172 		exits("");
173 	}
174 */
175 
176 	if((argc != 3 && argc != 4) || (strcmp(argv[1], "-e") != 0 && strcmp(argv[1], "-d") != 0) || strlen(argv[2]) != 16){
177 		fprint(2, "usage: idea -[e | d] <16 char key> [inputfile]\n");
178 		exits("usage");
179 	}
180 	dec = strcmp(argv[1], "-d") == 0;
181 	if(argc == 4){
182 		char s[128];
183 
184 		stdin = open(argv[3], OREAD);
185 		if(stdin < 0){
186 			fprint(2, "cannot open %s\n", argv[3]);
187 			exits("");
188 		}
189 		strcpy(s, argv[3]);
190 		if(dec){
191 			if(strcmp(s+strlen(s)-3, ".id") != 0){
192 				fprint(2, "input file not a .id file\n");
193 				exits("");
194 			}
195 			s[strlen(s)-3] = '\0';
196 		}
197 		else
198 			strcat(s, ".id");
199 		stdout = create(s, OWRITE, 0666);
200 		if(stdout < 0){
201 			fprint(2, "cannot create %s\n", s);
202 			exits("");
203 		}
204 	}
205 	for(i = 0; i < 16; i++)
206 		key[i] = argv[2][i];
207 	idea_key_setup(key, edkey);
208 	m = om = 0;
209 	bin = (Biobuf*)malloc(sizeof(Biobuf));
210 	bout = (Biobuf*)malloc(sizeof(Biobuf));
211 	Binit(bin, stdin, OREAD);
212 	Binit(bout, stdout, OWRITE);
213 	for(;;){
214 		n = Bread(bin, &buf[m], 8-m);
215 		if(n <= 0)
216 			break;
217 		m += n;
218 		if(m == 8){
219 			idea_cipher(edkey, buf, dec);
220 			if(dec){	/* leave last block around */
221 				if(om > 0)
222 					Bwrite(bout, obuf, 8);
223 				memcpy(obuf, buf, 8);
224 				om = 8;
225 			}
226 			else
227 				Bwrite(bout, buf, 8);
228 			m = 0;
229 		}
230 	}
231 	if(dec){
232 		if(om != 8)
233 			decerr("no last block");
234 		if(m != 0)
235 			decerr("last block not 8 bytes long");
236 		m = obuf[7];
237 		if(m < 0 || m > 7)
238 			decerr("bad modulus");
239 		for(i = m; i < 8-1; i++)
240 			if(obuf[i] != 0)
241 				decerr("byte not 0");
242 		Bwrite(bout, obuf, m);
243 	}
244 	else{
245 		for(i = m; i < 8; i++)
246 			buf[i] = 0;
247 		buf[7] = m;
248 		idea_cipher(edkey, buf, dec);
249 		Bwrite(bout, buf, 8);
250 	}
251 	Bflush(bout);
252 	Bterm(bin);
253 	Bterm(bout);
254 }
255