blob: 2950a9320255430cda0f412dc9bea576bca4851f [file] [log] [blame]
Guido van Rossum50098201992-07-31 15:10:13 +00001/***********************************************************
2Copyright 1992 by Lance Ellinghouse (lance@markv.com).
3
4Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
5Netherlands.
6
7 All Rights Reserved
8
9Permission to use, copy, modify, and distribute this software and its
10documentation for any purpose and without fee is hereby granted,
11provided that the above copyright notice appear in all copies and that
12both that copyright notice and this permission notice appear in
13supporting documentation, and that the names of Stichting Mathematisch
14Centrum or CWI not be used in advertising or publicity pertaining to
15distribution of the software without specific, written prior permission.
16
17STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
18THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
20FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
23OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25******************************************************************/
26
27/* This creates an encryption and decryption engine I am calling
28 a rotor due to the original design was a harware rotor with
29 contacts used in Germany during WWII.
30
31Rotor Module:
32
33- rotor.newrotor('key') -> rotorobject (default of 6 rotors)
34- rotor.newrotor('key', num_rotors) -> rotorobject
35
36Rotor Objects:
37
38- ro.encrypt('string') -> encrypted string
39- ro.decrypt('encrypted string') -> unencrypted string
40
41NOTE: you MUST use the SAME key in rotor.newrotor()
42 if you wish to decrypt an encrypted string.
43 Also, the encrypted string is NOT 0-127 ASCII.
44 It is considered BINARY data.
45
46*/
47
48/* Rotor objects */
49
50#include "allobjects.h"
51#include "modsupport.h"
52#include <stdio.h>
53#include <math.h>
54
55typedef struct {
56 OB_HEAD
57 int seed[3];
58 short key[5];
59 int size;
60 int size_mask;
61 int rotors;
62 unsigned char *e_rotor; /* [num_rotors][size] */
63 unsigned char *d_rotor; /* [num_rotors][size] */
64 unsigned char *positions; /* [num_rotors] */
65 unsigned char *advances; /* [num_rotors] */
66} rotorobject;
67
68extern typeobject Rotortype; /* Really static, forward */
69
70#define is_rotorobject(v) ((v)->ob_type == &Rotortype)
71
72/*
73 This defines the necessary routines to manage rotor objects
74*/
75
76static void set_seed( r )
77rotorobject *r;
78{
79 r->seed[0] = r->key[0];
80 r->seed[1] = r->key[1];
81 r->seed[2] = r->key[2];
82}
83
84/* Return the next random number in the range [0.0 .. 1.0) */
85static float r_random( r )
86rotorobject *r;
87{
88 int x, y, z;
89 float val, term;
90
91 x = r->seed[0];
92 y = r->seed[1];
93 z = r->seed[2];
94
95 x = 171 * (x % 177) - 2 * (x/177);
96 y = 172 * (y % 176) - 35 * (y/176);
97 z = 170 * (z % 178) - 63 * (z/178);
98
99 if (x < 0) x = x + 30269;
100 if (y < 0) y = y + 30307;
101 if (z < 0) z = z + 30323;
102
103 r->seed[0] = x;
104 r->seed[1] = y;
105 r->seed[2] = z;
106
107 term = (float)(
108 (((float)x)/(float)30269.0) +
109 (((float)y)/(float)30307.0) +
110 (((float)z)/(float)30323.0)
111 );
112 val = term - (float)floor((double)term);
113
114 if (val >= 1.0) val = 0.0;
115
116 return val;
117}
118
119static short r_rand(r,s)
120rotorobject *r;
121short s;
122{
123 short tmp = (short)((short)(r_random(r) * (float)s) % s);
124 return tmp;
125}
126
127static void set_key(r, key)
128rotorobject *r;
129char *key;
130{
131 int k1=995, k2=576, k3=767, k4=671, k5=463;
132 int i;
133 int len=strlen(key);
134 for (i=0;i<len;i++) {
135 k1 = (((k1<<3 | k1<<-13) + key[i]) & 65535);
136 k2 = (((k2<<3 | k2<<-13) ^ key[i]) & 65535);
137 k3 = (((k3<<3 | k3<<-13) - key[i]) & 65535);
138 k4 = ((key[i] - (k4<<3 | k4<<-13)) & 65535);
139 k5 = (((k5<<3 | k5<<-13) ^ ~key[i]) & 65535);
140 }
141 r->key[0] = (short)k1;
142 r->key[1] = (short)(k2|1);
143 r->key[2] = (short)k3;
144 r->key[3] = (short)k4;
145 r->key[4] = (short)k5;
146
147 set_seed(r);
148}
149
150/* These define the interface to a rotor object */
151static rotorobject *
152newrotorobject(num_rotors, key)
153 int num_rotors;
154 char *key;
155{
156 rotorobject *xp;
157 xp = NEWOBJ(rotorobject, &Rotortype);
158 if (xp == NULL)
159 return NULL;
160 set_key(xp,key);
161
162 xp->size = 256;
163 xp->size_mask = xp->size - 1;
164 xp->size_mask = 0;
165 xp->rotors = num_rotors;
166
167 xp->e_rotor = (unsigned char *)malloc((num_rotors * (xp->size * sizeof(char))));
168 if (xp->e_rotor == (unsigned char *)NULL) {
169 err_nomem();
170 DEL(xp);
171 xp = (object *)NULL;
172 goto done;
173 }
174 xp->d_rotor = (unsigned char *)malloc((num_rotors * (xp->size * sizeof(char))));
175 if (xp->d_rotor == (unsigned char *)NULL) {
176 err_nomem();
177 free(xp->e_rotor);
178 DEL(xp);
179 xp = (object *)NULL;
180 goto done;
181 }
182 xp->positions = (unsigned char *)malloc(num_rotors * sizeof(char));
183 if (xp->positions == (unsigned char *)NULL) {
184 err_nomem();
185 free(xp->e_rotor);
186 free(xp->d_rotor);
187 DEL(xp);
188 xp = (object *)NULL;
189 goto done;
190 }
191 xp->advances = (unsigned char *)malloc(num_rotors * sizeof(char));
192 if (xp->advances == (unsigned char *)NULL) {
193 err_nomem();
194 free(xp->e_rotor);
195 free(xp->d_rotor);
196 free(xp->positions);
197 DEL(xp);
198 xp = (object *)NULL;
199 goto done;
200 }
201done:
202 return xp;
203}
204
205/* These routines impliment the rotor itself */
206
207/* Here is a fairly sofisticated {en,de}cryption system. It is bassed
208on the idea of a "rotor" machine. A bunch of rotors, each with a
209different permutation of the alphabet, rotate around a different
210amount after encrypting one character. The current state of the
211rotors is used to encrypt one character.
212
213 The code is smart enought to tell if your alphabet has a number of
214characters equal to a power of two. If it does, it uses logical
215operations, if not it uses div and mod (both require a division).
216
217 You will need to make two changes to the code 1) convert to c, and
218customize for an alphabet of 255 chars 2) add a filter at the
219begining, and end, which subtracts one on the way in, and adds one on
220the way out.
221
222 You might wish to do some timing studies. Another viable
223alternative is to "byte stuff" the encrypted data of a normal (perhaps
224this one) encryption routine.
225
226j'
227*/
228
229/*(defun RTR-make-id-rotor (rotor)
230 "Set ROTOR to the identity permutation"
231 (let ((j 0))
232 (while (< j RTR-size)
233 (aset rotor j j)
234 (setq j (+ 1 j)))
235 rotor))*/
236static void RTR_make_id_rotor(r, rtr)
237 rotorobject *r;
238 unsigned char *rtr;
239{
240 register int j;
241 register int size = r->size;
242 for (j=0;j<size;j++) {
243 rtr[j] = (unsigned char)j;
244 }
245}
246
247
248/*(defvar RTR-e-rotors
249 (let ((rv (make-vector RTR-number-of-rotors 0))
250 (i 0)
251 tr)
252 (while (< i RTR-number-of-rotors)
253 (setq tr (make-vector RTR-size 0))
254 (RTR-make-id-rotor tr)
255 (aset rv i tr)
256 (setq i (+ 1 i)))
257 rv)
258 "The current set of encryption rotors")*/
259static void RTR_e_rotors(r)
260 rotorobject *r;
261{
262 int i;
263 for (i=0;i<r->rotors;i++) {
264 RTR_make_id_rotor(r,&(r->e_rotor[(i*r->size)]));
265 }
266}
267
268/*(defvar RTR-d-rotors
269 (let ((rv (make-vector RTR-number-of-rotors 0))
270 (i 0)
271 tr)
272 (while (< i RTR-number-of-rotors)
273 (setq tr (make-vector RTR-size 0))
274 (setq j 0)
275 (while (< j RTR-size)
276 (aset tr j j)
277 (setq j (+ 1 j)))
278 (aset rv i tr)
279 (setq i (+ 1 i)))
280 rv)
281 "The current set of decryption rotors")*/
282static void RTR_d_rotors(r)
283 rotorobject *r;
284{
285 register int i, j;
286 for (i=0;i<r->rotors;i++) {
287 for (j=0;j<r->size;j++) {
288 r->d_rotor[((i*r->size)+j)] = (unsigned char)j;
289 }
290 }
291}
292
293/*(defvar RTR-positions (make-vector RTR-number-of-rotors 1)
294 "The positions of the rotors at this time")*/
295static void RTR_positions(r)
296 rotorobject *r;
297{
298 int i;
299 for (i=0;i<r->rotors;i++) {
300 r->positions[i] = 1;
301 }
302}
303
304/*(defvar RTR-advances (make-vector RTR-number-of-rotors 1)
305 "The number of positions to advance the rotors at a time")*/
306static void RTR_advances(r)
307 rotorobject *r;
308{
309 int i;
310 for (i=0;i<r->rotors;i++) {
311 r->advances[i] = 1;
312 }
313}
314
315/*(defun RTR-permute-rotor (e d)
316 "Permute the E rotor, and make the D rotor its inverse"
317 ;; see Knuth for explaination of algorythm.
318 (RTR-make-id-rotor e)
319 (let ((i RTR-size)
320 q j)
321 (while (<= 2 i)
322 (setq q (fair16 i)) ; a little tricky, decrement here
323 (setq i (- i 1)) ; since we have origin 0 array's
324 (setq j (aref e q))
325 (aset e q (aref e i))
326 (aset e i j)
327 (aset d j i))
328 (aset e 0 (aref e 0)) ; don't forget e[0] and d[0]
329 (aset d (aref e 0) 0)))*/
330static void RTR_permute_rotor(r, e, d)
331 rotorobject *r;
332 unsigned char *e;
333 unsigned char *d;
334{
335 short i = r->size;
336 short q;
337 unsigned char j;
338 RTR_make_id_rotor(r,e);
339 while (2 <= i) {
340 q = r_rand(r,i);
341 i--;
342 j = e[q];
343 e[q] = (unsigned char)e[i];
344 e[i] = (unsigned char)j;
345 d[j] = (unsigned char)i;
346 }
347 e[0] = (unsigned char)e[0];
348 d[(e[0])] = (unsigned char)0;
349}
350
351/*(defun RTR-init (key)
352 "Given KEY (a list of 5 16 bit numbers), initialize the rotor machine.
353Set the advancement, position, and permutation of the rotors"
354 (R16-set-state key)
355 (let (i)
356 (setq i 0)
357 (while (< i RTR-number-of-rotors)
358 (aset RTR-positions i (fair16 RTR-size))
359 (aset RTR-advances i (+ 1 (* 2 (fair16 (/ RTR-size 2)))))
360 (message "Initializing rotor %d..." i)
361 (RTR-permute-rotor (aref RTR-e-rotors i) (aref RTR-d-rotors i))
362 (setq i (+ 1 i)))))*/
363static void RTR_init(r)
364 rotorobject *r;
365{
366 int i;
367 set_seed(r);
368 RTR_positions(r);
369 RTR_advances(r);
370 RTR_e_rotors(r);
371 RTR_d_rotors(r);
372 for(i=0;i<r->rotors;i++) {
373 r->positions[i] = r_rand(r,r->size);
374 r->advances[i] = (1+(2*(r_rand(r,r->size/2))));
375 RTR_permute_rotor(r,&(r->e_rotor[(i*r->size)]),&(r->d_rotor[(i*r->size)]));
376 }
377}
378
379/*(defun RTR-advance ()
380 "Change the RTR-positions vector, using the RTR-advances vector"
381 (let ((i 0)
382 (temp 0))
383 (if RTR-size-mask
384 (while (< i RTR-number-of-rotors)
385 (setq temp (+ (aref RTR-positions i) (aref RTR-advances i)))
386 (aset RTR-positions i (logand temp RTR-size-mask))
387 (if (and (>= temp RTR-size)
388 (< i (- RTR-number-of-rotors 1)))
389 (aset RTR-positions (+ i 1)
390 (+ 1 (aref RTR-positions (+ i 1)))))
391 (setq i (+ i 1)))
392 (while (< i RTR-number-of-rotors)
393 (setq temp (+ (aref RTR-positions i) (aref RTR-advances i)))
394 (aset RTR-positions i (% temp RTR-size))
395 (if (and (>= temp RTR-size)
396 (< i (- RTR-number-of-rotors 1)))
397 (aset RTR-positions (+ i 1)
398 (+ 1 (aref RTR-positions (+ i 1)))))
399 (setq i (+ i 1))))))*/
400static void RTR_advance(r)
401 rotorobject *r;
402{
403 register int i=0, temp=0;
404 if (r->size_mask) {
405 while (i<r->rotors) {
406 temp = r->positions[i] + r->advances[i];
407 r->positions[i] = temp & r->size_mask;
408 if ((temp >= r->size) && (i < (r->rotors - 1))) {
409 r->positions[(i+1)] = 1 + r->positions[(i+1)];
410 }
411 i++;
412 }
413 } else {
414 while (i<r->rotors) {
415 temp = r->positions[i] + r->advances[i];
416 r->positions[i] = temp%r->size;
417 if ((temp >= r->size) && (i < (r->rotors - 1))) {
418 r->positions[(i+1)] = 1 + r->positions[(i+1)];
419 }
420 i++;
421 }
422 }
423}
424
425/*(defun RTR-e-char (p)
426 "Encrypt the character P with the current rotor machine"
427 (let ((i 0))
428 (if RTR-size-mask
429 (while (< i RTR-number-of-rotors)
430 (setq p (aref (aref RTR-e-rotors i)
431 (logand (logxor (aref RTR-positions i)
432 p)
433 RTR-size-mask)))
434 (setq i (+ 1 i)))
435 (while (< i RTR-number-of-rotors)
436 (setq p (aref (aref RTR-e-rotors i)
437 (% (logxor (aref RTR-positions i)
438 p)
439 RTR-size)))
440 (setq i (+ 1 i))))
441 (RTR-advance)
442 p))*/
443static unsigned char RTR_e_char(r, p)
444 rotorobject *r;
445 unsigned char p;
446{
447 register int i=0;
448 register unsigned char tp=p;
449 if (r->size_mask) {
450 while (i < r->rotors) {
451 tp = r->e_rotor[(i*r->size)+(((r->positions[i] ^ tp) & r->size_mask))];
452 i++;
453 }
454 } else {
455 while (i < r->rotors) {
456 tp = r->e_rotor[(i*r->size)+(((r->positions[i] ^ tp) % r->size))];
457 i++;
458 }
459 }
460 RTR_advance(r);
461 return ((unsigned char)tp);
462}
463
464/*(defun RTR-d-char (c)
465 "Decrypt the character C with the current rotor machine"
466 (let ((i (- RTR-number-of-rotors 1)))
467 (if RTR-size-mask
468 (while (<= 0 i)
469 (setq c (logand (logxor (aref RTR-positions i)
470 (aref (aref RTR-d-rotors i)
471 c))
472 RTR-size-mask))
473 (setq i (- i 1)))
474 (while (<= 0 i)
475 (setq c (% (logxor (aref RTR-positions i)
476 (aref (aref RTR-d-rotors i)
477 c))
478 RTR-size))
479 (setq i (- i 1))))
480 (RTR-advance)
481 c))*/
482static unsigned char RTR_d_char(r, c)
483 rotorobject *r;
484 unsigned char c;
485{
486 register int i=r->rotors - 1;
487 register unsigned char tc=c;
488 if (r->size_mask) {
489 while (0 <= i) {
490 tc = (r->positions[i] ^ r->d_rotor[(i*r->size)+tc]) & r->size_mask;
491 i--;
492 }
493 } else {
494 while (0 <= i) {
495 tc = (r->positions[i] ^ r->d_rotor[(i*r->size)+tc]) % r->size;
496 i--;
497 }
498 }
499 RTR_advance(r);
500 return(tc);
501}
502
503/*(defun RTR-e-region (beg end key)
504 "Perform a rotor encryption of the region from BEG to END by KEY"
505 (save-excursion
506 (let ((tenth (/ (- end beg) 10)))
507 (RTR-init key)
508 (goto-char beg)
509 ;; ### make it stop evry 10% or so to tell us
510 (while (< (point) end)
511 (let ((fc (following-char)))
512 (insert-char (RTR-e-char fc) 1)
513 (delete-char 1))))))*/
514static void RTR_e_region(r, beg, len)
515 rotorobject *r;
516 unsigned char *beg;
517 int len;
518{
519 register int i;
520 RTR_init(r);
521 for (i=0;i<len;i++) {
522 beg[i]=RTR_e_char(r,beg[i]);
523 }
524}
525
526/*(defun RTR-d-region (beg end key)
527 "Perform a rotor decryption of the region from BEG to END by KEY"
528 (save-excursion
529 (progn
530 (RTR-init key)
531 (goto-char beg)
532 (while (< (point) end)
533 (let ((fc (following-char)))
534 (insert-char (RTR-d-char fc) 1)
535 (delete-char 1))))))*/
536void static RTR_d_region(r, beg, len)
537 rotorobject *r;
538 unsigned char *beg;
539 int len;
540{
541 register int i;
542 RTR_init(r);
543 for (i=0;i<len;i++) {
544 beg[i]=RTR_d_char(r,beg[i]);
545 }
546}
547
548
549/*(defun RTR-key-string-to-ints (key)
550 "Convert a string into a list of 4 numbers"
551 (let ((k1 995)
552 (k2 576)
553 (k3 767)
554 (k4 671)
555 (k5 463)
556 (i 0))
557 (while (< i (length key))
558 (setq k1 (logand (+ (logior (lsh k1 3) (lsh k1 -13)) (aref key i)) 65535))
559 (setq k2 (logand (logxor (logior (lsh k2 3) (lsh k2 -13)) (aref key i)) 65535))
560 (setq k3 (logand (- (logior (lsh k3 3) (lsh k3 -13)) (aref key i)) 65535))
561 (setq k4 (logand (- (aref key i) (logior (lsh k4 3) (lsh k4 -13))) 65535))
562 (setq k5 (logand (logxor (logior (lsh k5 3) (lsh k5 -13)) (lognot (aref key i))) 65535))
563 (setq i (+ i 1)))
564 (list k1 (logior 1 k2) k3 k4 k5)))*/
565/* This is done in set_key() above */
566
567/*(defun encrypt-region (beg end key)
568 "Interactivly encrypt the region"
569 (interactive "r\nsKey:")
570 (RTR-e-region beg end (RTR-key-string-to-ints key)))*/
571static void encrypt_region(r, region, len)
572 rotorobject *r;
573 unsigned char *region;
574 int len;
575{
576 RTR_e_region(r,region,len);
577}
578
579/*(defun decrypt-region (beg end key)
580 "Interactivly decrypt the region"
581 (interactive "r\nsKey:")
582 (RTR-d-region beg end (RTR-key-string-to-ints key)))*/
583static void decrypt_region(r, region, len)
584 rotorobject *r;
585 unsigned char *region;
586 int len;
587{
588 RTR_d_region(r,region,len);
589}
590
591/* Rotor methods */
592
593static void
594rotor_dealloc(xp)
595 rotorobject *xp;
596{
597 free(xp->e_rotor);
598 free(xp->d_rotor);
599 free(xp->positions);
600 free(xp->advances);
601 DEL(xp);
602}
603
604static object *
605rotor_encrypt(self, args)
606 rotorobject *self;
607 object *args;
608{
609 char *string = (char *)NULL;
610 int len = 0;
611 object *rtn = (object *)NULL;
612 char *tmp;
613
614 if (!getargs(args,"s#",&string, &len))
615 return NULL;
616 if (!(tmp = (char *)malloc(len+5))) {
617 err_nomem();
618 return NULL;
619 }
620 memset(tmp,'\0',len+1);
621 memcpy(tmp,string,len);
622 RTR_e_region(self,tmp,len);
623 rtn = newsizedstringobject(tmp,len);
624 free(tmp);
625 return(rtn);
626}
627
628static object *
629rotor_decrypt(self, args)
630 rotorobject *self;
631 object *args;
632{
633 char *string = (char *)NULL;
634 int len = 0;
635 object *rtn = (object *)NULL;
636 char *tmp;
637
638 if (!getargs(args,"s#",&string, &len))
639 return NULL;
640 if (!(tmp = (char *)malloc(len+5))) {
641 err_nomem();
642 return NULL;
643 }
644 memset(tmp,'\0',len+1);
645 memcpy(tmp,string,len);
646 RTR_d_region(self,tmp,len);
647 rtn = newsizedstringobject(tmp,len);
648 free(tmp);
649 return(rtn);
650}
651
652static object *
653rotor_setkey(self, args)
654 rotorobject *self;
655 object *args;
656{
657 char *key;
658 char *string;
659
660 if (getargs(args,"s",&string))
661 set_key(self,string);
662 INCREF(None);
663 return None;
664}
665
666static struct methodlist rotor_methods[] = {
667 {"encrypt", rotor_encrypt},
668 {"decrypt", rotor_decrypt},
669 {"setkey", rotor_setkey},
670 {NULL, NULL} /* sentinel */
671};
672
673
674/* Return a rotor object's named attribute. */
675static object *
676rotor_getattr(s, name)
677 rotorobject *s;
678 char *name;
679{
680 return findmethod(rotor_methods, (object *) s, name);
681}
682
683static typeobject Rotortype = {
684 OB_HEAD_INIT(&Typetype)
685 0, /*ob_size*/
686 "rotor", /*tp_name*/
687 sizeof(rotorobject), /*tp_size*/
688 0, /*tp_itemsize*/
689 /* methods */
690 rotor_dealloc, /*tp_dealloc*/
691 0, /*tp_print*/
692 rotor_getattr, /*tp_getattr*/
693 0, /*tp_setattr*/
694 0, /*tp_compare*/
695 0, /*tp_repr*/
696};
697
698
699object *rotor_rotor(self, args)
700object *args;
701{
702 char *string;
703 rotorobject *r;
704 int len;
705 int num_rotors;
706
707 if (getargs(args,"s#", &string, &len)) {
708 num_rotors = 6;
709 } else {
710 err_clear();
711 if (!getargs(args,"(s#i)", &string, &len, &num_rotors))
712 return NULL;
713 }
714 r = newrotorobject(num_rotors, string);
715 return (object *)r;
716}
717
718static struct methodlist rotor_rotor_methods[] = {
719 {"newrotor", rotor_rotor},
720 {NULL, NULL} /* Sentinel */
721};
722
723
724/* Initialize this module.
725 This is called when the first 'import rotor' is done,
726 via a table in config.c, if config.c is compiled with USE_ROTOR
727 defined. */
728
729void
730initrotor()
731{
732 object *m;
733
734 m = initmodule("rotor", rotor_rotor_methods);
735}