You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
627 lines
15 KiB
627 lines
15 KiB
/*********************************************************** |
|
Copyright 1994 by Lance Ellinghouse, |
|
Cathedral City, California Republic, United States of America. |
|
|
|
All Rights Reserved |
|
|
|
Permission to use, copy, modify, and distribute this software and its |
|
documentation for any purpose and without fee is hereby granted, |
|
provided that the above copyright notice appear in all copies and that |
|
both that copyright notice and this permission notice appear in |
|
supporting documentation, and that the name of Lance Ellinghouse |
|
not be used in advertising or publicity pertaining to distribution |
|
of the software without specific, written prior permission. |
|
|
|
LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO |
|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
|
FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL, |
|
INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING |
|
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
|
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
|
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
|
|
******************************************************************/ |
|
|
|
/* This creates an encryption and decryption engine I am calling |
|
a rotor due to the original design was a hardware rotor with |
|
contacts used in Germany during WWII. |
|
|
|
Rotor Module: |
|
|
|
- rotor.newrotor('key') -> rotorobject (default of 6 rotors) |
|
- rotor.newrotor('key', num_rotors) -> rotorobject |
|
|
|
Rotor Objects: |
|
|
|
- ro.setkey('string') -> None (resets the key as defined in newrotor(). |
|
- ro.encrypt('string') -> encrypted string |
|
- ro.decrypt('encrypted string') -> unencrypted string |
|
|
|
- ro.encryptmore('string') -> encrypted string |
|
- ro.decryptmore('encrypted string') -> unencrypted string |
|
|
|
NOTE: the {en,de}cryptmore() methods use the setup that was |
|
established via the {en,de}crypt calls. They will NOT |
|
re-initalize the rotors unless: 1) They have not been |
|
initialized with {en,de}crypt since the last setkey() call; |
|
2) {en,de}crypt has not been called for this rotor yet. |
|
|
|
NOTE: you MUST use the SAME key in rotor.newrotor() |
|
if you wish to decrypt an encrypted string. |
|
Also, the encrypted string is NOT 0-127 ASCII. |
|
It is considered BINARY data. |
|
|
|
*/ |
|
|
|
/* Rotor objects */ |
|
|
|
#include "Python.h" |
|
|
|
#ifndef TRUE |
|
#define TRUE 1 |
|
#endif |
|
#ifndef FALSE |
|
#define FALSE 0 |
|
#endif |
|
|
|
typedef struct { |
|
PyObject_HEAD |
|
int seed[3]; |
|
short key[5]; |
|
int isinited; |
|
int size; |
|
int size_mask; |
|
int rotors; |
|
unsigned char *e_rotor; /* [num_rotors][size] */ |
|
unsigned char *d_rotor; /* [num_rotors][size] */ |
|
unsigned char *positions; /* [num_rotors] */ |
|
unsigned char *advances; /* [num_rotors] */ |
|
} Rotorobj; |
|
|
|
static PyTypeObject Rotor_Type; |
|
|
|
#define is_rotor(v) ((v)->ob_type == &Rotor_Type) |
|
|
|
|
|
/* This defines the necessary routines to manage rotor objects */ |
|
|
|
static void |
|
set_seed(Rotorobj *r) |
|
{ |
|
r->seed[0] = r->key[0]; |
|
r->seed[1] = r->key[1]; |
|
r->seed[2] = r->key[2]; |
|
r->isinited = FALSE; |
|
} |
|
|
|
/* Return the next random number in the range [0.0 .. 1.0) */ |
|
static double |
|
r_random(Rotorobj *r) |
|
{ |
|
int x, y, z; |
|
double val, term; |
|
|
|
x = r->seed[0]; |
|
y = r->seed[1]; |
|
z = r->seed[2]; |
|
|
|
x = 171 * (x % 177) - 2 * (x/177); |
|
y = 172 * (y % 176) - 35 * (y/176); |
|
z = 170 * (z % 178) - 63 * (z/178); |
|
|
|
if (x < 0) x = x + 30269; |
|
if (y < 0) y = y + 30307; |
|
if (z < 0) z = z + 30323; |
|
|
|
r->seed[0] = x; |
|
r->seed[1] = y; |
|
r->seed[2] = z; |
|
|
|
term = (double)( |
|
(((double)x)/(double)30269.0) + |
|
(((double)y)/(double)30307.0) + |
|
(((double)z)/(double)30323.0) |
|
); |
|
val = term - (double)floor((double)term); |
|
|
|
if (val >= 1.0) |
|
val = 0.0; |
|
|
|
return val; |
|
} |
|
|
|
static short |
|
r_rand(Rotorobj *r, short s) |
|
{ |
|
return (short)((short)(r_random(r) * (double)s) % s); |
|
} |
|
|
|
static void |
|
set_key(Rotorobj *r, char *key) |
|
{ |
|
unsigned long k1=995, k2=576, k3=767, k4=671, k5=463; |
|
size_t i; |
|
size_t len = strlen(key); |
|
|
|
for (i = 0; i < len; i++) { |
|
unsigned short ki = Py_CHARMASK(key[i]); |
|
|
|
k1 = (((k1<<3 | k1>>13) + ki) & 65535); |
|
k2 = (((k2<<3 | k2>>13) ^ ki) & 65535); |
|
k3 = (((k3<<3 | k3>>13) - ki) & 65535); |
|
k4 = ((ki - (k4<<3 | k4>>13)) & 65535); |
|
k5 = (((k5<<3 | k5>>13) ^ ~ki) & 65535); |
|
} |
|
r->key[0] = (short)k1; |
|
r->key[1] = (short)(k2|1); |
|
r->key[2] = (short)k3; |
|
r->key[3] = (short)k4; |
|
r->key[4] = (short)k5; |
|
|
|
set_seed(r); |
|
} |
|
|
|
|
|
|
|
/* These define the interface to a rotor object */ |
|
static Rotorobj * |
|
rotorobj_new(int num_rotors, char *key) |
|
{ |
|
Rotorobj *xp; |
|
|
|
xp = PyObject_New(Rotorobj, &Rotor_Type); |
|
if (xp == NULL) |
|
return NULL; |
|
set_key(xp, key); |
|
|
|
xp->size = 256; |
|
xp->size_mask = xp->size - 1; |
|
xp->size_mask = 0; |
|
xp->rotors = num_rotors; |
|
xp->e_rotor = NULL; |
|
xp->d_rotor = NULL; |
|
xp->positions = NULL; |
|
xp->advances = NULL; |
|
|
|
if (!(xp->e_rotor = PyMem_NEW(unsigned char, num_rotors * xp->size))) |
|
goto finally; |
|
if (!(xp->d_rotor = PyMem_NEW(unsigned char, num_rotors * xp->size))) |
|
goto finally; |
|
if (!(xp->positions = PyMem_NEW(unsigned char, num_rotors))) |
|
goto finally; |
|
if (!(xp->advances = PyMem_NEW(unsigned char, num_rotors))) |
|
goto finally; |
|
|
|
return xp; |
|
|
|
finally: |
|
if (xp->e_rotor) |
|
PyMem_DEL(xp->e_rotor); |
|
if (xp->d_rotor) |
|
PyMem_DEL(xp->d_rotor); |
|
if (xp->positions) |
|
PyMem_DEL(xp->positions); |
|
if (xp->advances) |
|
PyMem_DEL(xp->advances); |
|
Py_DECREF(xp); |
|
return (Rotorobj*)PyErr_NoMemory(); |
|
} |
|
|
|
|
|
/* These routines implement the rotor itself */ |
|
|
|
/* Here is a fairly sophisticated {en,de}cryption system. It is based on |
|
the idea of a "rotor" machine. A bunch of rotors, each with a |
|
different permutation of the alphabet, rotate around a different amount |
|
after encrypting one character. The current state of the rotors is |
|
used to encrypt one character. |
|
|
|
The code is smart enough to tell if your alphabet has a number of |
|
characters equal to a power of two. If it does, it uses logical |
|
operations, if not it uses div and mod (both require a division). |
|
|
|
You will need to make two changes to the code 1) convert to c, and |
|
customize for an alphabet of 255 chars 2) add a filter at the begining, |
|
and end, which subtracts one on the way in, and adds one on the way |
|
out. |
|
|
|
You might wish to do some timing studies. Another viable alternative |
|
is to "byte stuff" the encrypted data of a normal (perhaps this one) |
|
encryption routine. |
|
|
|
j' |
|
|
|
*/ |
|
|
|
/* Note: the C code here is a fairly straightforward transliteration of a |
|
* rotor implemented in lisp. The original lisp code has been removed from |
|
* this file to for simplification, but I've kept the docstrings as |
|
* comments in front of the functions. |
|
*/ |
|
|
|
|
|
/* Set ROTOR to the identity permutation */ |
|
static void |
|
RTR_make_id_rotor(Rotorobj *r, unsigned char *rtr) |
|
{ |
|
register int j; |
|
register int size = r->size; |
|
for (j = 0; j < size; j++) { |
|
rtr[j] = (unsigned char)j; |
|
} |
|
} |
|
|
|
|
|
/* The current set of encryption rotors */ |
|
static void |
|
RTR_e_rotors(Rotorobj *r) |
|
{ |
|
int i; |
|
for (i = 0; i < r->rotors; i++) { |
|
RTR_make_id_rotor(r, &(r->e_rotor[(i*r->size)])); |
|
} |
|
} |
|
|
|
/* The current set of decryption rotors */ |
|
static void |
|
RTR_d_rotors(Rotorobj *r) |
|
{ |
|
register int i, j; |
|
for (i = 0; i < r->rotors; i++) { |
|
for (j = 0; j < r->size; j++) { |
|
r->d_rotor[((i*r->size)+j)] = (unsigned char)j; |
|
} |
|
} |
|
} |
|
|
|
/* The positions of the rotors at this time */ |
|
static void |
|
RTR_positions(Rotorobj *r) |
|
{ |
|
int i; |
|
for (i = 0; i < r->rotors; i++) { |
|
r->positions[i] = 1; |
|
} |
|
} |
|
|
|
/* The number of positions to advance the rotors at a time */ |
|
static void |
|
RTR_advances(Rotorobj *r) |
|
{ |
|
int i; |
|
for (i = 0; i < r->rotors; i++) { |
|
r->advances[i] = 1; |
|
} |
|
} |
|
|
|
/* Permute the E rotor, and make the D rotor its inverse |
|
* see Knuth for explanation of algorithm. |
|
*/ |
|
static void |
|
RTR_permute_rotor(Rotorobj *r, unsigned char *e, unsigned char *d) |
|
{ |
|
short i = r->size; |
|
short q; |
|
unsigned char j; |
|
RTR_make_id_rotor(r,e); |
|
while (2 <= i) { |
|
q = r_rand(r,i); |
|
i--; |
|
j = e[q]; |
|
e[q] = (unsigned char)e[i]; |
|
e[i] = (unsigned char)j; |
|
d[j] = (unsigned char)i; |
|
} |
|
e[0] = (unsigned char)e[0]; |
|
d[(e[0])] = (unsigned char)0; |
|
} |
|
|
|
/* Given KEY (a list of 5 16 bit numbers), initialize the rotor machine. |
|
* Set the advancement, position, and permutation of the rotors |
|
*/ |
|
static void |
|
RTR_init(Rotorobj *r) |
|
{ |
|
int i; |
|
set_seed(r); |
|
RTR_positions(r); |
|
RTR_advances(r); |
|
RTR_e_rotors(r); |
|
RTR_d_rotors(r); |
|
for (i = 0; i < r->rotors; i++) { |
|
r->positions[i] = (unsigned char) r_rand(r, (short)r->size); |
|
r->advances[i] = (1+(2*(r_rand(r, (short)(r->size/2))))); |
|
RTR_permute_rotor(r, |
|
&(r->e_rotor[(i*r->size)]), |
|
&(r->d_rotor[(i*r->size)])); |
|
} |
|
r->isinited = TRUE; |
|
} |
|
|
|
/* Change the RTR-positions vector, using the RTR-advances vector */ |
|
static void |
|
RTR_advance(Rotorobj *r) |
|
{ |
|
register int i=0, temp=0; |
|
if (r->size_mask) { |
|
while (i < r->rotors) { |
|
temp = r->positions[i] + r->advances[i]; |
|
r->positions[i] = temp & r->size_mask; |
|
if ((temp >= r->size) && (i < (r->rotors - 1))) { |
|
r->positions[(i+1)] = 1 + r->positions[(i+1)]; |
|
} |
|
i++; |
|
} |
|
} else { |
|
while (i < r->rotors) { |
|
temp = r->positions[i] + r->advances[i]; |
|
r->positions[i] = temp%r->size; |
|
if ((temp >= r->size) && (i < (r->rotors - 1))) { |
|
r->positions[(i+1)] = 1 + r->positions[(i+1)]; |
|
} |
|
i++; |
|
} |
|
} |
|
} |
|
|
|
/* Encrypt the character P with the current rotor machine */ |
|
static unsigned char |
|
RTR_e_char(Rotorobj *r, unsigned char p) |
|
{ |
|
register int i=0; |
|
register unsigned char tp=p; |
|
if (r->size_mask) { |
|
while (i < r->rotors) { |
|
tp = r->e_rotor[(i*r->size) + |
|
(((r->positions[i] ^ tp) & |
|
r->size_mask))]; |
|
i++; |
|
} |
|
} else { |
|
while (i < r->rotors) { |
|
tp = r->e_rotor[(i*r->size) + |
|
(((r->positions[i] ^ tp) % |
|
(unsigned int) r->size))]; |
|
i++; |
|
} |
|
} |
|
RTR_advance(r); |
|
return ((unsigned char)tp); |
|
} |
|
|
|
/* Decrypt the character C with the current rotor machine */ |
|
static unsigned char |
|
RTR_d_char(Rotorobj *r, unsigned char c) |
|
{ |
|
register int i = r->rotors - 1; |
|
register unsigned char tc = c; |
|
|
|
if (r->size_mask) { |
|
while (0 <= i) { |
|
tc = (r->positions[i] ^ |
|
r->d_rotor[(i*r->size)+tc]) & r->size_mask; |
|
i--; |
|
} |
|
} else { |
|
while (0 <= i) { |
|
tc = (r->positions[i] ^ |
|
r->d_rotor[(i*r->size)+tc]) % |
|
(unsigned int) r->size; |
|
i--; |
|
} |
|
} |
|
RTR_advance(r); |
|
return(tc); |
|
} |
|
|
|
/* Perform a rotor encryption of the region from BEG to END by KEY */ |
|
static void |
|
RTR_e_region(Rotorobj *r, unsigned char *beg, int len, int doinit) |
|
{ |
|
register int i; |
|
if (doinit || r->isinited == FALSE) |
|
RTR_init(r); |
|
for (i = 0; i < len; i++) { |
|
beg[i] = RTR_e_char(r, beg[i]); |
|
} |
|
} |
|
|
|
/* Perform a rotor decryption of the region from BEG to END by KEY */ |
|
static void |
|
RTR_d_region(Rotorobj *r, unsigned char *beg, int len, int doinit) |
|
{ |
|
register int i; |
|
if (doinit || r->isinited == FALSE) |
|
RTR_init(r); |
|
for (i = 0; i < len; i++) { |
|
beg[i] = RTR_d_char(r, beg[i]); |
|
} |
|
} |
|
|
|
|
|
|
|
/* Rotor methods */ |
|
static void |
|
rotor_dealloc(Rotorobj *xp) |
|
{ |
|
if (xp->e_rotor) |
|
PyMem_DEL(xp->e_rotor); |
|
if (xp->d_rotor) |
|
PyMem_DEL(xp->d_rotor); |
|
if (xp->positions) |
|
PyMem_DEL(xp->positions); |
|
if (xp->advances) |
|
PyMem_DEL(xp->advances); |
|
PyObject_Del(xp); |
|
} |
|
|
|
static PyObject * |
|
rotorobj_encrypt(Rotorobj *self, PyObject *args) |
|
{ |
|
char *string = NULL; |
|
int len = 0; |
|
PyObject *rtn = NULL; |
|
char *tmp; |
|
|
|
if (!PyArg_ParseTuple(args, "s#:encrypt", &string, &len)) |
|
return NULL; |
|
if (!(tmp = PyMem_NEW(char, len+5))) { |
|
PyErr_NoMemory(); |
|
return NULL; |
|
} |
|
memset(tmp, '\0', len+1); |
|
memcpy(tmp, string, len); |
|
RTR_e_region(self, (unsigned char *)tmp, len, TRUE); |
|
rtn = PyString_FromStringAndSize(tmp, len); |
|
PyMem_DEL(tmp); |
|
return(rtn); |
|
} |
|
|
|
static PyObject * |
|
rotorobj_encrypt_more(Rotorobj *self, PyObject *args) |
|
{ |
|
char *string = NULL; |
|
int len = 0; |
|
PyObject *rtn = NULL; |
|
char *tmp; |
|
|
|
if (!PyArg_ParseTuple(args, "s#:encrypt_more", &string, &len)) |
|
return NULL; |
|
if (!(tmp = PyMem_NEW(char, len+5))) { |
|
PyErr_NoMemory(); |
|
return NULL; |
|
} |
|
memset(tmp, '\0', len+1); |
|
memcpy(tmp, string, len); |
|
RTR_e_region(self, (unsigned char *)tmp, len, FALSE); |
|
rtn = PyString_FromStringAndSize(tmp, len); |
|
PyMem_DEL(tmp); |
|
return(rtn); |
|
} |
|
|
|
static PyObject * |
|
rotorobj_decrypt(Rotorobj *self, PyObject *args) |
|
{ |
|
char *string = NULL; |
|
int len = 0; |
|
PyObject *rtn = NULL; |
|
char *tmp; |
|
|
|
if (!PyArg_ParseTuple(args, "s#:decrypt", &string, &len)) |
|
return NULL; |
|
if (!(tmp = PyMem_NEW(char, len+5))) { |
|
PyErr_NoMemory(); |
|
return NULL; |
|
} |
|
memset(tmp, '\0', len+1); |
|
memcpy(tmp, string, len); |
|
RTR_d_region(self, (unsigned char *)tmp, len, TRUE); |
|
rtn = PyString_FromStringAndSize(tmp, len); |
|
PyMem_DEL(tmp); |
|
return(rtn); |
|
} |
|
|
|
static PyObject * |
|
rotorobj_decrypt_more(Rotorobj *self, PyObject *args) |
|
{ |
|
char *string = NULL; |
|
int len = 0; |
|
PyObject *rtn = NULL; |
|
char *tmp; |
|
|
|
if (!PyArg_ParseTuple(args, "s#:decrypt_more", &string, &len)) |
|
return NULL; |
|
if (!(tmp = PyMem_NEW(char, len+5))) { |
|
PyErr_NoMemory(); |
|
return NULL; |
|
} |
|
memset(tmp, '\0', len+1); |
|
memcpy(tmp, string, len); |
|
RTR_d_region(self, (unsigned char *)tmp, len, FALSE); |
|
rtn = PyString_FromStringAndSize(tmp, len); |
|
PyMem_DEL(tmp); |
|
return(rtn); |
|
} |
|
|
|
static PyObject * |
|
rotorobj_setkey(Rotorobj *self, PyObject *args) |
|
{ |
|
char *key; |
|
|
|
if (!PyArg_ParseTuple(args, "s:setkey", &key)) |
|
return NULL; |
|
|
|
set_key(self, key); |
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
|
|
static struct PyMethodDef |
|
rotorobj_methods[] = { |
|
{"encrypt", (PyCFunction)rotorobj_encrypt, METH_VARARGS}, |
|
{"encryptmore", (PyCFunction)rotorobj_encrypt_more, METH_VARARGS}, |
|
{"decrypt", (PyCFunction)rotorobj_decrypt, METH_VARARGS}, |
|
{"decryptmore", (PyCFunction)rotorobj_decrypt_more, METH_VARARGS}, |
|
{"setkey", (PyCFunction)rotorobj_setkey, METH_VARARGS}, |
|
{NULL, NULL} /* sentinel */ |
|
}; |
|
|
|
|
|
/* Return a rotor object's named attribute. */ |
|
static PyObject * |
|
rotorobj_getattr(Rotorobj *s, char *name) |
|
{ |
|
return Py_FindMethod(rotorobj_methods, (PyObject*)s, name); |
|
} |
|
|
|
|
|
static PyTypeObject Rotor_Type = { |
|
PyObject_HEAD_INIT(NULL) |
|
0, /*ob_size*/ |
|
"rotor.rotor", /*tp_name*/ |
|
sizeof(Rotorobj), /*tp_size*/ |
|
0, /*tp_itemsize*/ |
|
/* methods */ |
|
(destructor)rotor_dealloc, /*tp_dealloc*/ |
|
0, /*tp_print*/ |
|
(getattrfunc)rotorobj_getattr, /*tp_getattr*/ |
|
0, /*tp_setattr*/ |
|
0, /*tp_compare*/ |
|
0, /*tp_repr*/ |
|
0, /*tp_hash*/ |
|
}; |
|
|
|
|
|
static PyObject * |
|
rotor_rotor(PyObject *self, PyObject *args) |
|
{ |
|
Rotorobj *r; |
|
char *string; |
|
int num_rotors = 6; |
|
|
|
if (!PyArg_ParseTuple(args, "s|i:newrotor", &string, &num_rotors)) |
|
return NULL; |
|
|
|
r = rotorobj_new(num_rotors, string); |
|
return (PyObject *)r; |
|
} |
|
|
|
|
|
|
|
static struct PyMethodDef |
|
rotor_methods[] = { |
|
{"newrotor", rotor_rotor, METH_VARARGS}, |
|
{NULL, NULL} /* sentinel */ |
|
}; |
|
|
|
|
|
PyMODINIT_FUNC |
|
initrotor(void) |
|
{ |
|
Rotor_Type.ob_type = &PyType_Type; |
|
(void)Py_InitModule("rotor", rotor_methods); |
|
if (PyErr_Warn(PyExc_DeprecationWarning, |
|
"the rotor module uses an insecure algorithm " |
|
"and is deprecated") < 0) |
|
return; |
|
}
|
|
|