1 /***********************************************************
2 Copyright 1994 by Lance Ellinghouse,
3 Cathedral City, California Republic, United States of America.
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the name of Lance Ellinghouse
12 not be used in advertising or publicity pertaining to distribution
13 of the software without specific, written prior permission.
15 LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL,
18 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
19 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* This creates an encryption and decryption engine I am calling
26 a rotor due to the original design was a harware rotor with
27 contacts used in Germany during WWII.
31 - rotor.newrotor('key') -> rotorobject (default of 6 rotors)
32 - rotor.newrotor('key', num_rotors) -> rotorobject
36 - ro.setkey('string') -> None (resets the key as defined in newrotor().
37 - ro.encrypt('string') -> encrypted string
38 - ro.decrypt('encrypted string') -> unencrypted string
40 - ro.encryptmore('string') -> encrypted string
41 - ro.decryptmore('encrypted string') -> unencrypted string
43 NOTE: the {en,de}cryptmore() methods use the setup that was
44 established via the {en,de}crypt calls. They will NOT
45 re-initalize the rotors unless: 1) They have not been
46 initalized with {en,de}crypt since the last setkey() call;
47 2) {en,de}crypt has not been called for this rotor yet.
49 NOTE: you MUST use the SAME key in rotor.newrotor()
50 if you wish to decrypt an encrypted string.
51 Also, the encrypted string is NOT 0-127 ASCII.
52 It is considered BINARY data.
73 unsigned char *e_rotor
; /* [num_rotors][size] */
74 unsigned char *d_rotor
; /* [num_rotors][size] */
75 unsigned char *positions
; /* [num_rotors] */
76 unsigned char *advances
; /* [num_rotors] */
79 staticforward PyTypeObject PyRotor_Type
;
81 #define PyRotor_Check(v) ((v)->ob_type == &PyRotor_Type)
84 This defines the necessary routines to manage rotor objects
87 static void set_seed( r
)
90 r
->seed
[0] = r
->key
[0];
91 r
->seed
[1] = r
->key
[1];
92 r
->seed
[2] = r
->key
[2];
96 /* Return the next random number in the range [0.0 .. 1.0) */
97 static float r_random( r
)
107 x
= 171 * (x
% 177) - 2 * (x
/177);
108 y
= 172 * (y
% 176) - 35 * (y
/176);
109 z
= 170 * (z
% 178) - 63 * (z
/178);
111 if (x
< 0) x
= x
+ 30269;
112 if (y
< 0) y
= y
+ 30307;
113 if (z
< 0) z
= z
+ 30323;
120 (((float)x
)/(float)30269.0) +
121 (((float)y
)/(float)30307.0) +
122 (((float)z
)/(float)30323.0)
124 val
= term
- (float)floor((double)term
);
126 if (val
>= 1.0) val
= 0.0;
131 static short r_rand(r
,s
)
135 /*short tmp = (short)((int)(r_random(r) * (float)32768.0) % 32768);*/
136 short tmp
= (short)((short)(r_random(r
) * (float)s
) % s
);
140 static void set_key(r
, key
)
144 #ifdef BUGGY_CODE_BW_COMPAT
145 /* See comments below */
146 int k1
=995, k2
=576, k3
=767, k4
=671, k5
=463;
148 unsigned long k1
=995, k2
=576, k3
=767, k4
=671, k5
=463;
152 for (i
=0;i
<len
;i
++) {
153 #ifdef BUGGY_CODE_BW_COMPAT
154 /* This is the code as it was originally released.
155 It causes warnings on many systems and can generate
156 different results as well. If you have files
157 encrypted using an older version you may want to
158 #define BUGGY_CODE_BW_COMPAT so as to be able to
160 k1
= (((k1
<<3 | k1
<<-13) + key
[i
]) & 65535);
161 k2
= (((k2
<<3 | k2
<<-13) ^ key
[i
]) & 65535);
162 k3
= (((k3
<<3 | k3
<<-13) - key
[i
]) & 65535);
163 k4
= ((key
[i
] - (k4
<<3 | k4
<<-13)) & 65535);
164 k5
= (((k5
<<3 | k5
<<-13) ^ ~key
[i
]) & 65535);
166 /* This code should be more portable */
167 k1
= (((k1
<<3 | k1
>>13) + key
[i
]) & 65535);
168 k2
= (((k2
<<3 | k2
>>13) ^ key
[i
]) & 65535);
169 k3
= (((k3
<<3 | k3
>>13) - key
[i
]) & 65535);
170 k4
= ((key
[i
] - (k4
<<3 | k4
>>13)) & 65535);
171 k5
= (((k5
<<3 | k5
>>13) ^ ~key
[i
]) & 65535);
174 r
->key
[0] = (short)k1
;
175 r
->key
[1] = (short)(k2
|1);
176 r
->key
[2] = (short)k3
;
177 r
->key
[3] = (short)k4
;
178 r
->key
[4] = (short)k5
;
183 /* These define the interface to a rotor object */
184 static PyRotorObject
*
185 PyRotor_New(num_rotors
, key
)
190 xp
= PyObject_NEW(PyRotorObject
, &PyRotor_Type
);
196 xp
->size_mask
= xp
->size
- 1;
198 xp
->rotors
= num_rotors
;
201 xp
->positions
= NULL
;
205 (unsigned char *)malloc((num_rotors
* (xp
->size
* sizeof(char))));
206 if (xp
->e_rotor
== (unsigned char *)NULL
)
209 (unsigned char *)malloc((num_rotors
* (xp
->size
* sizeof(char))));
210 if (xp
->d_rotor
== (unsigned char *)NULL
)
212 xp
->positions
= (unsigned char *)malloc(num_rotors
* sizeof(char));
213 if (xp
->positions
== (unsigned char *)NULL
)
215 xp
->advances
= (unsigned char *)malloc(num_rotors
* sizeof(char));
216 if (xp
->advances
== (unsigned char *)NULL
)
221 return (PyRotorObject
*)PyErr_NoMemory();
224 /* These routines impliment the rotor itself */
226 /* Here is a fairly sofisticated {en,de}cryption system. It is bassed
227 on the idea of a "rotor" machine. A bunch of rotors, each with a
228 different permutation of the alphabet, rotate around a different
229 amount after encrypting one character. The current state of the
230 rotors is used to encrypt one character.
232 The code is smart enought to tell if your alphabet has a number of
233 characters equal to a power of two. If it does, it uses logical
234 operations, if not it uses div and mod (both require a division).
236 You will need to make two changes to the code 1) convert to c, and
237 customize for an alphabet of 255 chars 2) add a filter at the
238 begining, and end, which subtracts one on the way in, and adds one on
241 You might wish to do some timing studies. Another viable
242 alternative is to "byte stuff" the encrypted data of a normal (perhaps
243 this one) encryption routine.
248 /*(defun RTR-make-id-rotor (rotor)
249 "Set ROTOR to the identity permutation"
251 (while (< j RTR-size)
255 static void RTR_make_id_rotor(r
, rtr
)
260 register int size
= r
->size
;
261 for (j
=0;j
<size
;j
++) {
262 rtr
[j
] = (unsigned char)j
;
267 /*(defvar RTR-e-rotors
268 (let ((rv (make-vector RTR-number-of-rotors 0))
271 (while (< i RTR-number-of-rotors)
272 (setq tr (make-vector RTR-size 0))
273 (RTR-make-id-rotor tr)
277 "The current set of encryption rotors")*/
278 static void RTR_e_rotors(r
)
282 for (i
=0;i
<r
->rotors
;i
++) {
283 RTR_make_id_rotor(r
,&(r
->e_rotor
[(i
*r
->size
)]));
287 /*(defvar RTR-d-rotors
288 (let ((rv (make-vector RTR-number-of-rotors 0))
291 (while (< i RTR-number-of-rotors)
292 (setq tr (make-vector RTR-size 0))
294 (while (< j RTR-size)
300 "The current set of decryption rotors")*/
301 static void RTR_d_rotors(r
)
305 for (i
=0;i
<r
->rotors
;i
++) {
306 for (j
=0;j
<r
->size
;j
++) {
307 r
->d_rotor
[((i
*r
->size
)+j
)] = (unsigned char)j
;
312 /*(defvar RTR-positions (make-vector RTR-number-of-rotors 1)
313 "The positions of the rotors at this time")*/
314 static void RTR_positions(r
)
318 for (i
=0;i
<r
->rotors
;i
++) {
323 /*(defvar RTR-advances (make-vector RTR-number-of-rotors 1)
324 "The number of positions to advance the rotors at a time")*/
325 static void RTR_advances(r
)
329 for (i
=0;i
<r
->rotors
;i
++) {
334 /*(defun RTR-permute-rotor (e d)
335 "Permute the E rotor, and make the D rotor its inverse"
336 ;; see Knuth for explaination of algorythm.
337 (RTR-make-id-rotor e)
341 (setq q (fair16 i)) ; a little tricky, decrement here
342 (setq i (- i 1)) ; since we have origin 0 array's
344 (aset e q (aref e i))
347 (aset e 0 (aref e 0)) ; don't forget e[0] and d[0]
348 (aset d (aref e 0) 0)))*/
349 static void RTR_permute_rotor(r
, e
, d
)
357 RTR_make_id_rotor(r
,e
);
362 e
[q
] = (unsigned char)e
[i
];
363 e
[i
] = (unsigned char)j
;
364 d
[j
] = (unsigned char)i
;
366 e
[0] = (unsigned char)e
[0];
367 d
[(e
[0])] = (unsigned char)0;
370 /*(defun RTR-init (key)
371 "Given KEY (a list of 5 16 bit numbers), initialize the rotor machine.
372 Set the advancement, position, and permutation of the rotors"
376 (while (< i RTR-number-of-rotors)
377 (aset RTR-positions i (fair16 RTR-size))
378 (aset RTR-advances i (+ 1 (* 2 (fair16 (/ RTR-size 2)))))
379 (message "Initializing rotor %d..." i)
380 (RTR-permute-rotor (aref RTR-e-rotors i) (aref RTR-d-rotors i))
381 (setq i (+ 1 i)))))*/
382 static void RTR_init(r
)
391 for(i
=0;i
<r
->rotors
;i
++) {
392 r
->positions
[i
] = r_rand(r
,r
->size
);
393 r
->advances
[i
] = (1+(2*(r_rand(r
,r
->size
/2))));
394 RTR_permute_rotor(r
,&(r
->e_rotor
[(i
*r
->size
)]),&(r
->d_rotor
[(i
*r
->size
)]));
399 /*(defun RTR-advance ()
400 "Change the RTR-positions vector, using the RTR-advances vector"
404 (while (< i RTR-number-of-rotors)
405 (setq temp (+ (aref RTR-positions i) (aref RTR-advances i)))
406 (aset RTR-positions i (logand temp RTR-size-mask))
407 (if (and (>= temp RTR-size)
408 (< i (- RTR-number-of-rotors 1)))
409 (aset RTR-positions (+ i 1)
410 (+ 1 (aref RTR-positions (+ i 1)))))
412 (while (< i RTR-number-of-rotors)
413 (setq temp (+ (aref RTR-positions i) (aref RTR-advances i)))
414 (aset RTR-positions i (% temp RTR-size))
415 (if (and (>= temp RTR-size)
416 (< i (- RTR-number-of-rotors 1)))
417 (aset RTR-positions (+ i 1)
418 (+ 1 (aref RTR-positions (+ i 1)))))
419 (setq i (+ i 1))))))*/
420 static void RTR_advance(r
)
423 register int i
=0, temp
=0;
425 while (i
<r
->rotors
) {
426 temp
= r
->positions
[i
] + r
->advances
[i
];
427 r
->positions
[i
] = temp
& r
->size_mask
;
428 if ((temp
>= r
->size
) && (i
< (r
->rotors
- 1))) {
429 r
->positions
[(i
+1)] = 1 + r
->positions
[(i
+1)];
434 while (i
<r
->rotors
) {
435 temp
= r
->positions
[i
] + r
->advances
[i
];
436 r
->positions
[i
] = temp
%r
->size
;
437 if ((temp
>= r
->size
) && (i
< (r
->rotors
- 1))) {
438 r
->positions
[(i
+1)] = 1 + r
->positions
[(i
+1)];
445 /*(defun RTR-e-char (p)
446 "Encrypt the character P with the current rotor machine"
449 (while (< i RTR-number-of-rotors)
450 (setq p (aref (aref RTR-e-rotors i)
451 (logand (logxor (aref RTR-positions i)
455 (while (< i RTR-number-of-rotors)
456 (setq p (aref (aref RTR-e-rotors i)
457 (% (logxor (aref RTR-positions i)
463 static unsigned char RTR_e_char(r
, p
)
468 register unsigned char tp
=p
;
470 while (i
< r
->rotors
) {
471 tp
= r
->e_rotor
[(i
*r
->size
)+(((r
->positions
[i
] ^ tp
) & r
->size_mask
))];
475 while (i
< r
->rotors
) {
476 tp
= r
->e_rotor
[(i
*r
->size
)+(((r
->positions
[i
] ^ tp
) % (unsigned int) r
->size
))];
481 return ((unsigned char)tp
);
484 /*(defun RTR-d-char (c)
485 "Decrypt the character C with the current rotor machine"
486 (let ((i (- RTR-number-of-rotors 1)))
489 (setq c (logand (logxor (aref RTR-positions i)
490 (aref (aref RTR-d-rotors i)
495 (setq c (% (logxor (aref RTR-positions i)
496 (aref (aref RTR-d-rotors i)
502 static unsigned char RTR_d_char(r
, c
)
506 register int i
=r
->rotors
- 1;
507 register unsigned char tc
=c
;
510 tc
= (r
->positions
[i
] ^ r
->d_rotor
[(i
*r
->size
)+tc
]) & r
->size_mask
;
515 tc
= (r
->positions
[i
] ^ r
->d_rotor
[(i
*r
->size
)+tc
]) % (unsigned int) r
->size
;
523 /*(defun RTR-e-region (beg end key)
524 "Perform a rotor encryption of the region from BEG to END by KEY"
526 (let ((tenth (/ (- end beg) 10)))
529 ;; ### make it stop evry 10% or so to tell us
530 (while (< (point) end)
531 (let ((fc (following-char)))
532 (insert-char (RTR-e-char fc) 1)
533 (delete-char 1))))))*/
534 static void RTR_e_region(r
, beg
, len
, doinit
)
541 if (doinit
|| r
->isinited
== FALSE
)
543 for (i
=0;i
<len
;i
++) {
544 beg
[i
]=RTR_e_char(r
,beg
[i
]);
548 /*(defun RTR-d-region (beg end key)
549 "Perform a rotor decryption of the region from BEG to END by KEY"
554 (while (< (point) end)
555 (let ((fc (following-char)))
556 (insert-char (RTR-d-char fc) 1)
557 (delete-char 1))))))*/
558 static void RTR_d_region(r
, beg
, len
, doinit
)
565 if (doinit
|| r
->isinited
== FALSE
)
567 for (i
=0;i
<len
;i
++) {
568 beg
[i
]=RTR_d_char(r
,beg
[i
]);
573 /*(defun RTR-key-string-to-ints (key)
574 "Convert a string into a list of 4 numbers"
581 (while (< i (length key))
582 (setq k1 (logand (+ (logior (lsh k1 3) (lsh k1 -13)) (aref key i)) 65535))
583 (setq k2 (logand (logxor (logior (lsh k2 3) (lsh k2 -13)) (aref key i)) 65535))
584 (setq k3 (logand (- (logior (lsh k3 3) (lsh k3 -13)) (aref key i)) 65535))
585 (setq k4 (logand (- (aref key i) (logior (lsh k4 3) (lsh k4 -13))) 65535))
586 (setq k5 (logand (logxor (logior (lsh k5 3) (lsh k5 -13)) (lognot (aref key i))) 65535))
588 (list k1 (logior 1 k2) k3 k4 k5)))*/
589 /* This is done in set_key() above */
592 /*(defun encrypt-region (beg end key)
593 "Interactivly encrypt the region"
594 (interactive "r\nsKey:")
595 (RTR-e-region beg end (RTR-key-string-to-ints key)))*/
596 static void encrypt_region(r
, region
, len
)
598 unsigned char *region
;
601 RTR_e_region(r
,region
,len
,TRUE
);
604 /*(defun decrypt-region (beg end key)
605 "Interactivly decrypt the region"
606 (interactive "r\nsKey:")
607 (RTR-d-region beg end (RTR-key-string-to-ints key)))*/
608 static void decrypt_region(r
, region
, len
)
610 unsigned char *region
;
613 RTR_d_region(r
,region
,len
,TRUE
);
623 PyMem_XDEL(xp
->e_rotor
);
624 PyMem_XDEL(xp
->d_rotor
);
625 PyMem_XDEL(xp
->positions
);
626 PyMem_XDEL(xp
->advances
);
631 PyRotor_Encrypt(self
, args
)
635 char *string
= (char *)NULL
;
637 PyObject
* rtn
= (PyObject
* )NULL
;
640 if (!PyArg_Parse(args
,"s#",&string
, &len
))
642 if (!(tmp
= (char *)malloc(len
+5))) {
646 memset(tmp
,'\0',len
+1);
647 memcpy(tmp
,string
,len
);
648 RTR_e_region(self
,(unsigned char *)tmp
,len
, TRUE
);
649 rtn
= PyString_FromStringAndSize(tmp
,len
);
655 PyRotor_EncryptMore(self
, args
)
659 char *string
= (char *)NULL
;
661 PyObject
* rtn
= (PyObject
* )NULL
;
664 if (!PyArg_Parse(args
,"s#",&string
, &len
))
666 if (!(tmp
= (char *)malloc(len
+5))) {
670 memset(tmp
,'\0',len
+1);
671 memcpy(tmp
,string
,len
);
672 RTR_e_region(self
,(unsigned char *)tmp
,len
, FALSE
);
673 rtn
= PyString_FromStringAndSize(tmp
,len
);
679 PyRotor_Decrypt(self
, args
)
683 char *string
= (char *)NULL
;
685 PyObject
* rtn
= (PyObject
* )NULL
;
688 if (!PyArg_Parse(args
,"s#",&string
, &len
))
690 if (!(tmp
= (char *)malloc(len
+5))) {
694 memset(tmp
,'\0',len
+1);
695 memcpy(tmp
,string
,len
);
696 RTR_d_region(self
,(unsigned char *)tmp
,len
, TRUE
);
697 rtn
= PyString_FromStringAndSize(tmp
,len
);
703 PyRotor_DecryptMore(self
, args
)
707 char *string
= (char *)NULL
;
709 PyObject
* rtn
= (PyObject
* )NULL
;
712 if (!PyArg_Parse(args
,"s#",&string
, &len
))
714 if (!(tmp
= (char *)malloc(len
+5))) {
718 memset(tmp
,'\0',len
+1);
719 memcpy(tmp
,string
,len
);
720 RTR_d_region(self
,(unsigned char *)tmp
,len
, FALSE
);
721 rtn
= PyString_FromStringAndSize(tmp
,len
);
727 PyRotor_SetKey(self
, args
)
733 if (PyArg_Parse(args
,"s",&string
))
734 set_key(self
,string
);
739 static struct PyMethodDef PyRotor_Methods
[] = {
740 {"encrypt", (PyCFunction
)PyRotor_Encrypt
},
741 {"encryptmore", (PyCFunction
)PyRotor_EncryptMore
},
742 {"decrypt", (PyCFunction
)PyRotor_Decrypt
},
743 {"decryptmore", (PyCFunction
)PyRotor_DecryptMore
},
744 {"setkey", (PyCFunction
)PyRotor_SetKey
},
745 {NULL
, NULL
} /* sentinel */
749 /* Return a rotor object's named attribute. */
751 PyRotor_GetAttr(s
, name
)
755 return Py_FindMethod(PyRotor_Methods
, (PyObject
* ) s
, name
);
758 statichere PyTypeObject PyRotor_Type
= {
759 PyObject_HEAD_INIT(&PyType_Type
)
762 sizeof(PyRotorObject
), /*tp_size*/
765 (destructor
)PyRotor_Dealloc
, /*tp_dealloc*/
767 (getattrfunc
)PyRotor_GetAttr
, /*tp_getattr*/
776 PyRotor_Rotor(self
, args
)
785 if (PyArg_Parse(args
,"s#", &string
, &len
)) {
789 if (!PyArg_Parse(args
,"(s#i)", &string
, &len
, &num_rotors
))
792 r
= PyRotor_New(num_rotors
, string
);
793 return (PyObject
* )r
;
796 static struct PyMethodDef PyRotor_Rotor_Methods
[] = {
797 {"newrotor", (PyCFunction
)PyRotor_Rotor
},
798 {NULL
, NULL
} /* Sentinel */
802 /* Initialize this module.
803 This is called when the first 'import rotor' is done,
804 via a table in config.c, if config.c is compiled with USE_ROTOR
812 m
= Py_InitModule("rotor", PyRotor_Rotor_Methods
);