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.
76 unsigned char *e_rotor
; /* [num_rotors][size] */
77 unsigned char *d_rotor
; /* [num_rotors][size] */
78 unsigned char *positions
; /* [num_rotors] */
79 unsigned char *advances
; /* [num_rotors] */
82 staticforward PyTypeObject Rotor_Type
;
84 #define is_rotor(v) ((v)->ob_type == &Rotor_Type)
87 /* This defines the necessary routines to manage rotor objects */
93 r
->seed
[0] = r
->key
[0];
94 r
->seed
[1] = r
->key
[1];
95 r
->seed
[2] = r
->key
[2];
99 /* Return the next random number in the range [0.0 .. 1.0) */
111 x
= 171 * (x
% 177) - 2 * (x
/177);
112 y
= 172 * (y
% 176) - 35 * (y
/176);
113 z
= 170 * (z
% 178) - 63 * (z
/178);
115 if (x
< 0) x
= x
+ 30269;
116 if (y
< 0) y
= y
+ 30307;
117 if (z
< 0) z
= z
+ 30323;
124 (((double)x
)/(double)30269.0) +
125 (((double)y
)/(double)30307.0) +
126 (((double)z
)/(double)30323.0)
128 val
= term
- (double)floor((double)term
);
141 return (short)((short)(r_random(r
) * (double)s
) % s
);
149 unsigned long k1
=995, k2
=576, k3
=767, k4
=671, k5
=463;
151 int len
= strlen(key
);
153 for (i
= 0; i
< len
; i
++) {
154 unsigned short ki
= Py_CHARMASK(key
[i
]);
156 k1
= (((k1
<<3 | k1
>>13) + ki
) & 65535);
157 k2
= (((k2
<<3 | k2
>>13) ^ ki
) & 65535);
158 k3
= (((k3
<<3 | k3
>>13) - ki
) & 65535);
159 k4
= ((ki
- (k4
<<3 | k4
>>13)) & 65535);
160 k5
= (((k5
<<3 | k5
>>13) ^ ~ki
) & 65535);
162 r
->key
[0] = (short)k1
;
163 r
->key
[1] = (short)(k2
|1);
164 r
->key
[2] = (short)k3
;
165 r
->key
[3] = (short)k4
;
166 r
->key
[4] = (short)k5
;
173 /* These define the interface to a rotor object */
175 rotorobj_new(num_rotors
, key
)
181 xp
= PyObject_NEW(Rotorobj
, &Rotor_Type
);
187 xp
->size_mask
= xp
->size
- 1;
189 xp
->rotors
= num_rotors
;
192 xp
->positions
= NULL
;
195 if (!(xp
->e_rotor
= PyMem_NEW(unsigned char, num_rotors
* xp
->size
)))
197 if (!(xp
->d_rotor
= PyMem_NEW(unsigned char, num_rotors
* xp
->size
)))
199 if (!(xp
->positions
= PyMem_NEW(unsigned char, num_rotors
)))
201 if (!(xp
->advances
= PyMem_NEW(unsigned char, num_rotors
)))
207 PyMem_XDEL(xp
->e_rotor
);
208 PyMem_XDEL(xp
->d_rotor
);
209 PyMem_XDEL(xp
->positions
);
210 PyMem_XDEL(xp
->advances
);
212 return (Rotorobj
*)PyErr_NoMemory();
216 /* These routines impliment the rotor itself */
218 /* Here is a fairly sophisticated {en,de}cryption system. It is based on
219 the idea of a "rotor" machine. A bunch of rotors, each with a
220 different permutation of the alphabet, rotate around a different amount
221 after encrypting one character. The current state of the rotors is
222 used to encrypt one character.
224 The code is smart enought to tell if your alphabet has a number of
225 characters equal to a power of two. If it does, it uses logical
226 operations, if not it uses div and mod (both require a division).
228 You will need to make two changes to the code 1) convert to c, and
229 customize for an alphabet of 255 chars 2) add a filter at the begining,
230 and end, which subtracts one on the way in, and adds one on the way
233 You might wish to do some timing studies. Another viable alternative
234 is to "byte stuff" the encrypted data of a normal (perhaps this one)
241 /* Note: the C code here is a fairly straightforward transliteration of a
242 * rotor implemented in lisp. The original lisp code has been removed from
243 * this file to for simplification, but I've kept the docstrings as
244 * comments in front of the functions.
248 /* Set ROTOR to the identity permutation */
250 RTR_make_id_rotor(r
, rtr
)
255 register int size
= r
->size
;
256 for (j
= 0; j
< size
; j
++) {
257 rtr
[j
] = (unsigned char)j
;
262 /* The current set of encryption rotors */
268 for (i
= 0; i
< r
->rotors
; i
++) {
269 RTR_make_id_rotor(r
, &(r
->e_rotor
[(i
*r
->size
)]));
273 /* The current set of decryption rotors */
279 for (i
= 0; i
< r
->rotors
; i
++) {
280 for (j
= 0; j
< r
->size
; j
++) {
281 r
->d_rotor
[((i
*r
->size
)+j
)] = (unsigned char)j
;
286 /* The positions of the rotors at this time */
292 for (i
= 0; i
< r
->rotors
; i
++) {
297 /* The number of positions to advance the rotors at a time */
303 for (i
= 0; i
< r
->rotors
; i
++) {
308 /* Permute the E rotor, and make the D rotor its inverse
309 * see Knuth for explanation of algorithm.
312 RTR_permute_rotor(r
, e
, d
)
320 RTR_make_id_rotor(r
,e
);
325 e
[q
] = (unsigned char)e
[i
];
326 e
[i
] = (unsigned char)j
;
327 d
[j
] = (unsigned char)i
;
329 e
[0] = (unsigned char)e
[0];
330 d
[(e
[0])] = (unsigned char)0;
333 /* Given KEY (a list of 5 16 bit numbers), initialize the rotor machine.
334 * Set the advancement, position, and permutation of the rotors
346 for (i
= 0; i
< r
->rotors
; i
++) {
347 r
->positions
[i
] = (unsigned char) r_rand(r
,r
->size
);
348 r
->advances
[i
] = (1+(2*(r_rand(r
,r
->size
/2))));
350 &(r
->e_rotor
[(i
*r
->size
)]),
351 &(r
->d_rotor
[(i
*r
->size
)]));
356 /* Change the RTR-positions vector, using the RTR-advances vector */
361 register int i
=0, temp
=0;
363 while (i
< r
->rotors
) {
364 temp
= r
->positions
[i
] + r
->advances
[i
];
365 r
->positions
[i
] = temp
& r
->size_mask
;
366 if ((temp
>= r
->size
) && (i
< (r
->rotors
- 1))) {
367 r
->positions
[(i
+1)] = 1 + r
->positions
[(i
+1)];
372 while (i
< r
->rotors
) {
373 temp
= r
->positions
[i
] + r
->advances
[i
];
374 r
->positions
[i
] = temp
%r
->size
;
375 if ((temp
>= r
->size
) && (i
< (r
->rotors
- 1))) {
376 r
->positions
[(i
+1)] = 1 + r
->positions
[(i
+1)];
383 /* Encrypt the character P with the current rotor machine */
390 register unsigned char tp
=p
;
392 while (i
< r
->rotors
) {
393 tp
= r
->e_rotor
[(i
*r
->size
) +
394 (((r
->positions
[i
] ^ tp
) &
399 while (i
< r
->rotors
) {
400 tp
= r
->e_rotor
[(i
*r
->size
) +
401 (((r
->positions
[i
] ^ tp
) %
402 (unsigned int) r
->size
))];
407 return ((unsigned char)tp
);
410 /* Decrypt the character C with the current rotor machine */
416 register int i
= r
->rotors
- 1;
417 register unsigned char tc
= c
;
421 tc
= (r
->positions
[i
] ^
422 r
->d_rotor
[(i
*r
->size
)+tc
]) & r
->size_mask
;
427 tc
= (r
->positions
[i
] ^
428 r
->d_rotor
[(i
*r
->size
)+tc
]) %
429 (unsigned int) r
->size
;
437 /* Perform a rotor encryption of the region from BEG to END by KEY */
439 RTR_e_region(r
, beg
, len
, doinit
)
446 if (doinit
|| r
->isinited
== FALSE
)
448 for (i
= 0; i
< len
; i
++) {
449 beg
[i
] = RTR_e_char(r
, beg
[i
]);
453 /* Perform a rotor decryption of the region from BEG to END by KEY */
455 RTR_d_region(r
, beg
, len
, doinit
)
462 if (doinit
|| r
->isinited
== FALSE
)
464 for (i
= 0; i
< len
; i
++) {
465 beg
[i
] = RTR_d_char(r
, beg
[i
]);
476 PyMem_XDEL(xp
->e_rotor
);
477 PyMem_XDEL(xp
->d_rotor
);
478 PyMem_XDEL(xp
->positions
);
479 PyMem_XDEL(xp
->advances
);
484 rotorobj_encrypt(self
, args
)
490 PyObject
*rtn
= NULL
;
493 if (!PyArg_Parse(args
, "s#", &string
, &len
))
495 if (!(tmp
= PyMem_NEW(char, len
+5))) {
499 memset(tmp
, '\0', len
+1);
500 memcpy(tmp
, string
, len
);
501 RTR_e_region(self
, (unsigned char *)tmp
, len
, TRUE
);
502 rtn
= PyString_FromStringAndSize(tmp
, len
);
508 rotorobj_encrypt_more(self
, args
)
514 PyObject
*rtn
= NULL
;
517 if (!PyArg_Parse(args
, "s#", &string
, &len
))
519 if (!(tmp
= PyMem_NEW(char, len
+5))) {
523 memset(tmp
, '\0', len
+1);
524 memcpy(tmp
, string
, len
);
525 RTR_e_region(self
, (unsigned char *)tmp
, len
, FALSE
);
526 rtn
= PyString_FromStringAndSize(tmp
, len
);
532 rotorobj_decrypt(self
, args
)
538 PyObject
*rtn
= NULL
;
541 if (!PyArg_Parse(args
, "s#", &string
, &len
))
543 if (!(tmp
= PyMem_NEW(char, len
+5))) {
547 memset(tmp
, '\0', len
+1);
548 memcpy(tmp
, string
, len
);
549 RTR_d_region(self
, (unsigned char *)tmp
, len
, TRUE
);
550 rtn
= PyString_FromStringAndSize(tmp
, len
);
556 rotorobj_decrypt_more(self
, args
)
562 PyObject
*rtn
= NULL
;
565 if (!PyArg_Parse(args
, "s#", &string
, &len
))
567 if (!(tmp
= PyMem_NEW(char, len
+5))) {
571 memset(tmp
, '\0', len
+1);
572 memcpy(tmp
, string
, len
);
573 RTR_d_region(self
, (unsigned char *)tmp
, len
, FALSE
);
574 rtn
= PyString_FromStringAndSize(tmp
, len
);
580 rotorobj_setkey(self
, args
)
586 if (!PyArg_ParseTuple(args
, "s", &key
))
594 static struct PyMethodDef
595 rotorobj_methods
[] = {
596 {"encrypt", (PyCFunction
)rotorobj_encrypt
},
597 {"encryptmore", (PyCFunction
)rotorobj_encrypt_more
},
598 {"decrypt", (PyCFunction
)rotorobj_decrypt
},
599 {"decryptmore", (PyCFunction
)rotorobj_decrypt_more
},
600 {"setkey", (PyCFunction
)rotorobj_setkey
, 1},
601 {NULL
, NULL
} /* sentinel */
605 /* Return a rotor object's named attribute. */
607 rotorobj_getattr(s
, name
)
611 return Py_FindMethod(rotorobj_methods
, (PyObject
*)s
, name
);
615 statichere PyTypeObject Rotor_Type
= {
616 PyObject_HEAD_INIT(&PyType_Type
)
619 sizeof(Rotorobj
), /*tp_size*/
622 (destructor
)rotor_dealloc
, /*tp_dealloc*/
624 (getattrfunc
)rotorobj_getattr
, /*tp_getattr*/
633 rotor_rotor(self
, args
)
642 if (!PyArg_ParseTuple(args
, "s#|i", &string
, &len
, &num_rotors
))
645 r
= rotorobj_new(num_rotors
, string
);
646 return (PyObject
*)r
;
651 static struct PyMethodDef
653 {"newrotor", rotor_rotor
, 1},
654 {NULL
, NULL
} /* sentinel */
661 (void)Py_InitModule("rotor", rotor_methods
);