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 hardware 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 initialized 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.
75 unsigned char *e_rotor
; /* [num_rotors][size] */
76 unsigned char *d_rotor
; /* [num_rotors][size] */
77 unsigned char *positions
; /* [num_rotors] */
78 unsigned char *advances
; /* [num_rotors] */
81 staticforward PyTypeObject Rotor_Type
;
83 #define is_rotor(v) ((v)->ob_type == &Rotor_Type)
86 /* This defines the necessary routines to manage rotor objects */
91 r
->seed
[0] = r
->key
[0];
92 r
->seed
[1] = r
->key
[1];
93 r
->seed
[2] = r
->key
[2];
97 /* Return the next random number in the range [0.0 .. 1.0) */
108 x
= 171 * (x
% 177) - 2 * (x
/177);
109 y
= 172 * (y
% 176) - 35 * (y
/176);
110 z
= 170 * (z
% 178) - 63 * (z
/178);
112 if (x
< 0) x
= x
+ 30269;
113 if (y
< 0) y
= y
+ 30307;
114 if (z
< 0) z
= z
+ 30323;
121 (((double)x
)/(double)30269.0) +
122 (((double)y
)/(double)30307.0) +
123 (((double)z
)/(double)30323.0)
125 val
= term
- (double)floor((double)term
);
134 r_rand(Rotorobj
*r
, short s
)
136 return (short)((short)(r_random(r
) * (double)s
) % s
);
140 set_key(Rotorobj
*r
, char *key
)
142 unsigned long k1
=995, k2
=576, k3
=767, k4
=671, k5
=463;
144 size_t len
= strlen(key
);
146 for (i
= 0; i
< len
; i
++) {
147 unsigned short ki
= Py_CHARMASK(key
[i
]);
149 k1
= (((k1
<<3 | k1
>>13) + ki
) & 65535);
150 k2
= (((k2
<<3 | k2
>>13) ^ ki
) & 65535);
151 k3
= (((k3
<<3 | k3
>>13) - ki
) & 65535);
152 k4
= ((ki
- (k4
<<3 | k4
>>13)) & 65535);
153 k5
= (((k5
<<3 | k5
>>13) ^ ~ki
) & 65535);
155 r
->key
[0] = (short)k1
;
156 r
->key
[1] = (short)(k2
|1);
157 r
->key
[2] = (short)k3
;
158 r
->key
[3] = (short)k4
;
159 r
->key
[4] = (short)k5
;
166 /* These define the interface to a rotor object */
168 rotorobj_new(int num_rotors
, char *key
)
172 xp
= PyObject_New(Rotorobj
, &Rotor_Type
);
178 xp
->size_mask
= xp
->size
- 1;
180 xp
->rotors
= num_rotors
;
183 xp
->positions
= NULL
;
186 if (!(xp
->e_rotor
= PyMem_NEW(unsigned char, num_rotors
* xp
->size
)))
188 if (!(xp
->d_rotor
= PyMem_NEW(unsigned char, num_rotors
* xp
->size
)))
190 if (!(xp
->positions
= PyMem_NEW(unsigned char, num_rotors
)))
192 if (!(xp
->advances
= PyMem_NEW(unsigned char, num_rotors
)))
199 PyMem_DEL(xp
->e_rotor
);
201 PyMem_DEL(xp
->d_rotor
);
203 PyMem_DEL(xp
->positions
);
205 PyMem_DEL(xp
->advances
);
207 return (Rotorobj
*)PyErr_NoMemory();
211 /* These routines implement the rotor itself */
213 /* Here is a fairly sophisticated {en,de}cryption system. It is based on
214 the idea of a "rotor" machine. A bunch of rotors, each with a
215 different permutation of the alphabet, rotate around a different amount
216 after encrypting one character. The current state of the rotors is
217 used to encrypt one character.
219 The code is smart enough to tell if your alphabet has a number of
220 characters equal to a power of two. If it does, it uses logical
221 operations, if not it uses div and mod (both require a division).
223 You will need to make two changes to the code 1) convert to c, and
224 customize for an alphabet of 255 chars 2) add a filter at the begining,
225 and end, which subtracts one on the way in, and adds one on the way
228 You might wish to do some timing studies. Another viable alternative
229 is to "byte stuff" the encrypted data of a normal (perhaps this one)
236 /* Note: the C code here is a fairly straightforward transliteration of a
237 * rotor implemented in lisp. The original lisp code has been removed from
238 * this file to for simplification, but I've kept the docstrings as
239 * comments in front of the functions.
243 /* Set ROTOR to the identity permutation */
245 RTR_make_id_rotor(Rotorobj
*r
, unsigned char *rtr
)
248 register int size
= r
->size
;
249 for (j
= 0; j
< size
; j
++) {
250 rtr
[j
] = (unsigned char)j
;
255 /* The current set of encryption rotors */
257 RTR_e_rotors(Rotorobj
*r
)
260 for (i
= 0; i
< r
->rotors
; i
++) {
261 RTR_make_id_rotor(r
, &(r
->e_rotor
[(i
*r
->size
)]));
265 /* The current set of decryption rotors */
267 RTR_d_rotors(Rotorobj
*r
)
270 for (i
= 0; i
< r
->rotors
; i
++) {
271 for (j
= 0; j
< r
->size
; j
++) {
272 r
->d_rotor
[((i
*r
->size
)+j
)] = (unsigned char)j
;
277 /* The positions of the rotors at this time */
279 RTR_positions(Rotorobj
*r
)
282 for (i
= 0; i
< r
->rotors
; i
++) {
287 /* The number of positions to advance the rotors at a time */
289 RTR_advances(Rotorobj
*r
)
292 for (i
= 0; i
< r
->rotors
; i
++) {
297 /* Permute the E rotor, and make the D rotor its inverse
298 * see Knuth for explanation of algorithm.
301 RTR_permute_rotor(Rotorobj
*r
, unsigned char *e
, unsigned char *d
)
306 RTR_make_id_rotor(r
,e
);
311 e
[q
] = (unsigned char)e
[i
];
312 e
[i
] = (unsigned char)j
;
313 d
[j
] = (unsigned char)i
;
315 e
[0] = (unsigned char)e
[0];
316 d
[(e
[0])] = (unsigned char)0;
319 /* Given KEY (a list of 5 16 bit numbers), initialize the rotor machine.
320 * Set the advancement, position, and permutation of the rotors
323 RTR_init(Rotorobj
*r
)
331 for (i
= 0; i
< r
->rotors
; i
++) {
332 r
->positions
[i
] = (unsigned char) r_rand(r
, (short)r
->size
);
333 r
->advances
[i
] = (1+(2*(r_rand(r
, (short)(r
->size
/2)))));
335 &(r
->e_rotor
[(i
*r
->size
)]),
336 &(r
->d_rotor
[(i
*r
->size
)]));
341 /* Change the RTR-positions vector, using the RTR-advances vector */
343 RTR_advance(Rotorobj
*r
)
345 register int i
=0, temp
=0;
347 while (i
< r
->rotors
) {
348 temp
= r
->positions
[i
] + r
->advances
[i
];
349 r
->positions
[i
] = temp
& r
->size_mask
;
350 if ((temp
>= r
->size
) && (i
< (r
->rotors
- 1))) {
351 r
->positions
[(i
+1)] = 1 + r
->positions
[(i
+1)];
356 while (i
< r
->rotors
) {
357 temp
= r
->positions
[i
] + r
->advances
[i
];
358 r
->positions
[i
] = temp
%r
->size
;
359 if ((temp
>= r
->size
) && (i
< (r
->rotors
- 1))) {
360 r
->positions
[(i
+1)] = 1 + r
->positions
[(i
+1)];
367 /* Encrypt the character P with the current rotor machine */
369 RTR_e_char(Rotorobj
*r
, unsigned char p
)
372 register unsigned char tp
=p
;
374 while (i
< r
->rotors
) {
375 tp
= r
->e_rotor
[(i
*r
->size
) +
376 (((r
->positions
[i
] ^ tp
) &
381 while (i
< r
->rotors
) {
382 tp
= r
->e_rotor
[(i
*r
->size
) +
383 (((r
->positions
[i
] ^ tp
) %
384 (unsigned int) r
->size
))];
389 return ((unsigned char)tp
);
392 /* Decrypt the character C with the current rotor machine */
394 RTR_d_char(Rotorobj
*r
, unsigned char c
)
396 register int i
= r
->rotors
- 1;
397 register unsigned char tc
= c
;
401 tc
= (r
->positions
[i
] ^
402 r
->d_rotor
[(i
*r
->size
)+tc
]) & r
->size_mask
;
407 tc
= (r
->positions
[i
] ^
408 r
->d_rotor
[(i
*r
->size
)+tc
]) %
409 (unsigned int) r
->size
;
417 /* Perform a rotor encryption of the region from BEG to END by KEY */
419 RTR_e_region(Rotorobj
*r
, unsigned char *beg
, int len
, int doinit
)
422 if (doinit
|| r
->isinited
== FALSE
)
424 for (i
= 0; i
< len
; i
++) {
425 beg
[i
] = RTR_e_char(r
, beg
[i
]);
429 /* Perform a rotor decryption of the region from BEG to END by KEY */
431 RTR_d_region(Rotorobj
*r
, unsigned char *beg
, int len
, int doinit
)
434 if (doinit
|| r
->isinited
== FALSE
)
436 for (i
= 0; i
< len
; i
++) {
437 beg
[i
] = RTR_d_char(r
, beg
[i
]);
445 rotor_dealloc(Rotorobj
*xp
)
448 PyMem_DEL(xp
->e_rotor
);
450 PyMem_DEL(xp
->d_rotor
);
452 PyMem_DEL(xp
->positions
);
454 PyMem_DEL(xp
->advances
);
459 rotorobj_encrypt(Rotorobj
*self
, PyObject
*args
)
463 PyObject
*rtn
= NULL
;
466 if (!PyArg_Parse(args
, "s#", &string
, &len
))
468 if (!(tmp
= PyMem_NEW(char, len
+5))) {
472 memset(tmp
, '\0', len
+1);
473 memcpy(tmp
, string
, len
);
474 RTR_e_region(self
, (unsigned char *)tmp
, len
, TRUE
);
475 rtn
= PyString_FromStringAndSize(tmp
, len
);
481 rotorobj_encrypt_more(Rotorobj
*self
, PyObject
*args
)
485 PyObject
*rtn
= NULL
;
488 if (!PyArg_Parse(args
, "s#", &string
, &len
))
490 if (!(tmp
= PyMem_NEW(char, len
+5))) {
494 memset(tmp
, '\0', len
+1);
495 memcpy(tmp
, string
, len
);
496 RTR_e_region(self
, (unsigned char *)tmp
, len
, FALSE
);
497 rtn
= PyString_FromStringAndSize(tmp
, len
);
503 rotorobj_decrypt(Rotorobj
*self
, PyObject
*args
)
507 PyObject
*rtn
= NULL
;
510 if (!PyArg_Parse(args
, "s#", &string
, &len
))
512 if (!(tmp
= PyMem_NEW(char, len
+5))) {
516 memset(tmp
, '\0', len
+1);
517 memcpy(tmp
, string
, len
);
518 RTR_d_region(self
, (unsigned char *)tmp
, len
, TRUE
);
519 rtn
= PyString_FromStringAndSize(tmp
, len
);
525 rotorobj_decrypt_more(Rotorobj
*self
, PyObject
*args
)
529 PyObject
*rtn
= NULL
;
532 if (!PyArg_Parse(args
, "s#", &string
, &len
))
534 if (!(tmp
= PyMem_NEW(char, len
+5))) {
538 memset(tmp
, '\0', len
+1);
539 memcpy(tmp
, string
, len
);
540 RTR_d_region(self
, (unsigned char *)tmp
, len
, FALSE
);
541 rtn
= PyString_FromStringAndSize(tmp
, len
);
547 rotorobj_setkey(Rotorobj
*self
, PyObject
*args
)
551 if (!PyArg_ParseTuple(args
, "s:setkey", &key
))
559 static struct PyMethodDef
560 rotorobj_methods
[] = {
561 {"encrypt", (PyCFunction
)rotorobj_encrypt
},
562 {"encryptmore", (PyCFunction
)rotorobj_encrypt_more
},
563 {"decrypt", (PyCFunction
)rotorobj_decrypt
},
564 {"decryptmore", (PyCFunction
)rotorobj_decrypt_more
},
565 {"setkey", (PyCFunction
)rotorobj_setkey
, 1},
566 {NULL
, NULL
} /* sentinel */
570 /* Return a rotor object's named attribute. */
572 rotorobj_getattr(Rotorobj
*s
, char *name
)
574 return Py_FindMethod(rotorobj_methods
, (PyObject
*)s
, name
);
578 statichere PyTypeObject Rotor_Type
= {
579 PyObject_HEAD_INIT(NULL
)
582 sizeof(Rotorobj
), /*tp_size*/
585 (destructor
)rotor_dealloc
, /*tp_dealloc*/
587 (getattrfunc
)rotorobj_getattr
, /*tp_getattr*/
596 rotor_rotor(PyObject
*self
, PyObject
*args
)
603 if (!PyArg_ParseTuple(args
, "s#|i:newrotor", &string
, &len
, &num_rotors
))
606 r
= rotorobj_new(num_rotors
, string
);
607 return (PyObject
*)r
;
612 static struct PyMethodDef
614 {"newrotor", rotor_rotor
, 1},
615 {NULL
, NULL
} /* sentinel */
622 Rotor_Type
.ob_type
= &PyType_Type
;
623 (void)Py_InitModule("rotor", rotor_methods
);