RSA/DSA in C
Paul Swartz <[email protected]>
| Newsgroups | gmane.comp.python.cryptography |
|---|---|
| Message-ID | <3DD95D18.3053.181FFEB@localhost> |
Over the weekend, I wrote up modules using gmp to
implement RSA and DSA in C. These work with the
current Crypto.PublicKey.pubkey interface, and
pass the tests. I'm submitting them to you all to
look at, and if no one has any complaints, I'll
commit them to the repository.
The benchmarks I wrote (5000 encrypts/decrypts for
RSA, 500 signs/verifys for DSA) show a significant
speedup, especially for DSA. RSA went from 10.7s
to 2.1s, and DSA went from 76.7s to 2.6s.
(attached: Crypto/setup.py.diff,
Crypto/PublicKey/RSA.py.diff,
Crypto/PublicKey/DSA.py.diff, , Crypto/src/_rsa.c,
Crypto/src/_dsa.c)
-p
--
Paul Swartz
(o_ http://twistedmatrix.com/users/z3p.twistd/
//\ [email protected]
V_/_ AIM: Z3Penguin
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- File information -----------
File: _dsa.c
Date: 17 Nov 2002, 23:57
Size: 7026 bytes.
Type: Text
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- File information -----------
File: _rsa.c
Date: 17 Nov 2002, 21:39
Size: 7124 bytes.
Type: Text
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- File information -----------
File: setup.py.diff
Date: 18 Nov 2002, 18:20
Size: 1007 bytes.
Type: Text
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- File information -----------
File: DSA.py.diff
Date: 18 Nov 2002, 21:30
Size: 1900 bytes.
Type: Text
The following section of this message contains a file attachment
prepared for transmission using the Internet MIME message format.
If you are using Pegasus Mail, or any another MIME-compliant system,
you should be able to save it or view it from within your mailer.
If you cannot, please ask your system administrator for assistance.
---- File information -----------
File: RSA.py.diff
Date: 18 Nov 2002, 21:34
Size: 2791 bytes.
Type: Text
_dsa.c
(application/octet-stream, 6.9 KB)
#include <stdio.h>
#include <string.h>
#include <Python.h>
#include <longintrepr.h> // for conversions
#include <gmp.h>
PyObject* _dsa_module;
PyObject* _dsa_dict;
void longObjToMPZ(mpz_t m, PyLongObject *p) {
int size, i;
mpz_t temp, temp2;
mpz_init(temp);
mpz_init(temp2);
if (p->ob_size>0)
size = p->ob_size;
else
size = -p->ob_size;
for (i=0; i<size; i++) {
mpz_set_ui(temp, p->ob_digit[i]);
mpz_mul_2exp(temp2, temp, SHIFT * i);
mpz_add(m, m, temp2);
}
mpz_clear(temp);
mpz_clear(temp2);
}
PyObject* mpzToLongObj(mpz_t m) {
// borrowed from gmpy
int size = (mpz_sizeinbase(m, 2) + SHIFT - 1) / SHIFT;
int i;
PyLongObject *l = _PyLong_New(size);
if (!l) {return NULL;}
mpz_t temp;
mpz_init_set(temp, m);
for (i=0;i<size;i++){
l->ob_digit[i] = (digit) (mpz_get_ui(temp) & MASK);
mpz_fdiv_q_2exp(temp, temp, SHIFT);
}
i=size;
while ((i>0) && (l->ob_digit[i-1] == 0)) i--;
l->ob_size = i;
mpz_clear(temp);
return (PyObject*)l;
}
PyObject* dsaKey_new(PyObject*, PyObject*);
static PyMethodDef _dsa__methods__[] =
{
{ "construct", dsaKey_new, METH_VARARGS },
{ NULL, NULL }
};
typedef struct {
PyObject_HEAD
mpz_t y;
mpz_t g;
mpz_t p;
mpz_t q;
mpz_t x;
} dsaKey;
static int dsaSign(dsaKey *key, mpz_t m, mpz_t k, mpz_t r, mpz_t s) {
if (mpz_cmp_ui(k, 2)<0 || mpz_cmp(k, key->q)>=0) {
return 1;
}
mpz_t temp;
mpz_init(temp);
mpz_powm(r, key->g, k, key->p);
mpz_mod(r, r, key->q);
mpz_invert(s, k, key->q);
mpz_mul(temp, key->x, r);
mpz_add(temp, m, temp);
mpz_mul(s, s, temp);
mpz_mod(s, s, key->q);
mpz_clear(temp);
return 0;
}
static int dsaVerify(dsaKey *key, mpz_t m, mpz_t r, mpz_t s) {
if (mpz_cmp_ui(r, 0)<=0 || mpz_cmp(r, key->q)>=0 ||
mpz_cmp_ui(s, 0)<=0 || mpz_cmp(s, key->q)>=0)
return 0;
int result;
mpz_t u1, u2, v1, v2, w;
mpz_init(u1);
mpz_init(u2);
mpz_init(v1);
mpz_init(v2);
mpz_init(w);
mpz_invert(w, s, key->q);
mpz_mul(u1, m, w);
mpz_mod(u1, u1, key->q);
mpz_mul(u2, r, w);
mpz_mod(u2, u2, key->q);
mpz_powm(v1, key->g, u1, key->p);
mpz_powm(v2, key->y, u2, key->p);
mpz_mul(w, v1, v2);
mpz_mod(w, w, key->p);
mpz_mod(w, w, key->q);
if (mpz_cmp(r, w) == 0)
result=1;
else
result=0;
mpz_clear(u1);
mpz_clear(u2);
mpz_clear(v1);
mpz_clear(v2);
mpz_clear(w);
return result;
}
static void dsaKey_dealloc(dsaKey*);
static PyObject * dsaKey_getattr(dsaKey*, char*);
static PyObject * dsaKey__sign(dsaKey*, PyObject*);
static PyObject * dsaKey__verify(dsaKey*, PyObject*);
static PyObject * dsaKey_size(dsaKey*);
static PyObject * dsaKey_hasprivate(dsaKey*);
PyObject *dsaError; // raised on erros
static PyTypeObject dsaKeyType = {
PyObject_HEAD_INIT(NULL)
0,
"dsaKey",
sizeof(dsaKey),
0,
(destructor)dsaKey_dealloc, /* dealloc */
0, /* print */
(getattrfunc)dsaKey_getattr, /* getattr */
0, /* setattr */
0, /* compare */
0, /* repr */
0, /* as_number */
0, /* as_sequence */
0, /* as_mapping */
0, /* hash */
0, /* call */
};
static PyMethodDef dsaKey__methods__[] = {
{"_sign", (PyCFunction)dsaKey__sign, METH_VARARGS, "Sign the given long."},
{"_verify", (PyCFunction)dsaKey__verify, METH_VARARGS, "Verify that the signature is valid."},
{"size", (PyCFunction)dsaKey_size, METH_NOARGS, "Return the number of bits that this key can handle."},
{"hasprivate", (PyCFunction)dsaKey_hasprivate, METH_NOARGS, "Return 1 or 0 if this key does/doesn't have a private key."},
{NULL, NULL, 0, NULL}
};
PyObject * dsaKey_new(PyObject *self, PyObject *args) {
PyLongObject *y = NULL, *g = NULL, *p = NULL, *q = NULL, *x = NULL;
dsaKey* key;
key = PyObject_New(dsaKey, &dsaKeyType);
mpz_init(key->y);
mpz_init(key->g);
mpz_init(key->p);
mpz_init(key->q);
mpz_init(key->x);
PyArg_ParseTuple(args, "O!O!O!O!|O!", &PyLong_Type, &y,
&PyLong_Type, &g,
&PyLong_Type, &p,
&PyLong_Type, &q,
&PyLong_Type, &x);
longObjToMPZ(key->y, y);
longObjToMPZ(key->g, g);
longObjToMPZ(key->p, p);
longObjToMPZ(key->q, q);
if (x) {
longObjToMPZ(key->x, x);
}
/*Py_XDECREF(n);
Py_XDECREF(e);
Py_XDECREF(d);
Py_XDECREF(p);
Py_XDECREF(q);*/
return (PyObject*) key;
}
static void dsaKey_dealloc(dsaKey* key) {
mpz_clear(key->y);
mpz_clear(key->g);
mpz_clear(key->p);
mpz_clear(key->q);
mpz_clear(key->x);
PyObject_Del(key);
}
static PyObject* dsaKey_getattr(dsaKey* key, char* attr) {
if (strcmp(attr, "y") == 0)
return mpzToLongObj(key->y);
else if (strcmp(attr, "g") == 0)
return mpzToLongObj(key->g);
else if (strcmp(attr, "p") == 0)
return mpzToLongObj(key->p);
else if (strcmp(attr, "q") == 0)
return mpzToLongObj(key->q);
else if (strcmp(attr, "x") == 0) {
if (mpz_size(key->x) == 0) {
PyErr_SetString(PyExc_AttributeError, "rsaKey instance has no attribute 'x'");
return NULL;
}
return mpzToLongObj(key->x);
}
else {
return Py_FindMethod(dsaKey__methods__, (PyObject*) key, attr);
}
}
PyObject* dsaKey__sign(dsaKey *key, PyObject *args) {
PyObject *lm, *lk, *lr, *ls;
if (!(PyArg_ParseTuple(args, "O!O!", &PyLong_Type, &lm,
&PyLong_Type, &lk))) {
return NULL;
}
mpz_t m;
mpz_t k;
mpz_t r;
mpz_t s;
mpz_init(m);
mpz_init(k);
mpz_init(r);
mpz_init(s);
longObjToMPZ(m, (PyLongObject*)lm);
longObjToMPZ(k, (PyLongObject*)lk);
int result = dsaSign(key, m, k, r, s);
if (result == 1) {
PyErr_SetString(dsaError, "K not between 2 and q");
return NULL;
}
lr = mpzToLongObj(r);
ls = mpzToLongObj(s);
mpz_clear(m);
mpz_clear(k);
mpz_clear(r);
mpz_clear(s);
return Py_BuildValue("(NN)", lr, ls);
}
PyObject* dsaKey__verify(dsaKey *key, PyObject *args) {
PyObject *lm, *lr, *ls;
if (!(PyArg_ParseTuple(args, "O!O!O!", &PyLong_Type, &lm,
&PyLong_Type, &lr,
&PyLong_Type, &ls))) {
return NULL;
}
mpz_t m, r, s;
mpz_init(m);
mpz_init(r);
mpz_init(s);
longObjToMPZ(m, (PyLongObject*)lm);
longObjToMPZ(r, (PyLongObject*)lr);
longObjToMPZ(s, (PyLongObject*)ls);
int result = dsaVerify(key, m, r, s);
mpz_clear(m);
mpz_clear(r);
mpz_clear(s);
return Py_BuildValue("i", result);
}
PyObject* dsaKey_size(dsaKey *key) {
return Py_BuildValue("i", mpz_sizeinbase(key->p,2)-1);
}
PyObject* dsaKey_hasprivate(dsaKey *key) {
if (mpz_size(key->x) == 0)
return Py_BuildValue("i", 0);
else
return Py_BuildValue("i", 1);
}
void init_dsa(void) {
dsaKeyType.ob_type = &PyType_Type;
_dsa_module = Py_InitModule("_dsa", _dsa__methods__);
_dsa_dict = PyModule_GetDict(_dsa_module);
dsaError = PyErr_NewException("_dsa.error", NULL, NULL);
PyDict_SetItemString(_dsa_dict, "error", dsaError);
}
_rsa.c
(application/octet-stream, 7 KB)
#include <stdio.h>
#include <string.h>
#include <Python.h>
#include <longintrepr.h> // for conversions
#include <gmp.h>
PyObject* _rsa_module;
PyObject* _rsa_dict;
void longObjToMPZ(mpz_t m, PyLongObject *p) {
int size, i;
mpz_t temp, temp2;
mpz_init(temp);
mpz_init(temp2);
if (p->ob_size>0)
size = p->ob_size;
else
size = -p->ob_size;
for (i=0; i<size; i++) {
mpz_set_ui(temp, p->ob_digit[i]);
mpz_mul_2exp(temp2, temp, SHIFT * i);
mpz_add(m, m, temp2);
}
mpz_clear(temp);
mpz_clear(temp2);
}
PyObject* mpzToLongObj(mpz_t m) {
// borrowed from gmpy
int size = (mpz_sizeinbase(m, 2) + SHIFT - 1) / SHIFT;
int i;
PyLongObject *l = _PyLong_New(size);
if (!l) {return NULL;}
mpz_t temp;
mpz_init_set(temp, m);
for (i=0;i<size;i++){
l->ob_digit[i] = (digit) (mpz_get_ui(temp) & MASK);
mpz_fdiv_q_2exp(temp, temp, SHIFT);
}
i=size;
while ((i>0) && (l->ob_digit[i-1] == 0)) i--;
l->ob_size = i;
mpz_clear(temp);
return (PyObject*)l;
}
PyObject* rsaKey_new(PyObject*, PyObject*);
static PyMethodDef _rsa__methods__[] =
{
{ "construct", rsaKey_new, METH_VARARGS },
{ NULL, NULL }
};
typedef struct {
PyObject_HEAD
mpz_t n;
mpz_t e;
mpz_t d;
mpz_t p;
mpz_t q;
} rsaKey;
static int rsaEncrypt(rsaKey *key, mpz_t v) {
if (mpz_cmp(v, key->n)>=0) {
return 1;
}
mpz_powm(v, v, key->e, key->n);
return 0;
}
static int rsaDecrypt(rsaKey *key, mpz_t v) {
if (mpz_cmp(v, key->n)>=0) {
return 1;
}
if (mpz_size(key->d)==0) {
return 2;
}
mpz_powm(v, v, key->d, key->n);
return 0;
}
static void rsaKey_dealloc(rsaKey*);
static PyObject * rsaKey_getattr(rsaKey*, char*);
static PyObject * rsaKey__encrypt(rsaKey*, PyObject*);
static PyObject * rsaKey__decrypt(rsaKey*, PyObject*);
static PyObject * rsaKey__verify(rsaKey*, PyObject*);
static PyObject * rsaKey_size(rsaKey*);
static PyObject * rsaKey_hasprivate(rsaKey*);
PyObject *rsaError; // raised on erros
static PyTypeObject rsaKeyType = {
PyObject_HEAD_INIT(NULL)
0,
"rsaKey",
sizeof(rsaKey),
0,
(destructor)rsaKey_dealloc, /* dealloc */
0, /* print */
(getattrfunc)rsaKey_getattr, /* getattr */
0, /* setattr */
0, /* compare */
0, /* repr */
0, /* as_number */
0, /* as_sequence */
0, /* as_mapping */
0, /* hash */
0, /* call */
};
static PyMethodDef rsaKey__methods__[] = {
{"_encrypt", (PyCFunction)rsaKey__encrypt, METH_VARARGS, "Encrypt the given long."},
{"_decrypt", (PyCFunction)rsaKey__decrypt, METH_VARARGS, "Decrypt the given long."},
{"_sign", (PyCFunction)rsaKey__decrypt, METH_VARARGS, "Sign the given long."},
{"_verify", (PyCFunction)rsaKey__verify, METH_VARARGS, "Verify that the signature is valid."},
{"size", (PyCFunction)rsaKey_size, METH_NOARGS, "Return the number of bits that this key can handle."},
{"hasprivate", (PyCFunction)rsaKey_hasprivate, METH_NOARGS, "Return 1 or 0 if this key does/doesn't have a private key."},
{NULL, NULL, 0, NULL}
};
PyObject * rsaKey_new(PyObject *self, PyObject *args) {
PyLongObject *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL;
rsaKey* key;
key = PyObject_New(rsaKey, &rsaKeyType);
mpz_init(key->n);
mpz_init(key->e);
mpz_init(key->d);
mpz_init(key->p);
mpz_init(key->q);
PyArg_ParseTuple(args, "O!O!|O!O!O!", &PyLong_Type, &n,
&PyLong_Type, &e,
&PyLong_Type, &d,
&PyLong_Type, &p,
&PyLong_Type, &q);
longObjToMPZ(key->n, n);
longObjToMPZ(key->e, e);
if (!d) {
return (PyObject*) key;
}
longObjToMPZ(key->d, d);
if (p) {
if (q) {
longObjToMPZ(key->p, p);
longObjToMPZ(key->q, q);
}
}
/*Py_XDECREF(n);
Py_XDECREF(e);
Py_XDECREF(d);
Py_XDECREF(p);
Py_XDECREF(q);*/
return (PyObject*) key; // ingore p and q for now
}
static void rsaKey_dealloc(rsaKey* key) {
mpz_clear(key->n);
mpz_clear(key->e);
mpz_clear(key->d);
mpz_clear(key->p);
mpz_clear(key->q);
PyObject_Del(key);
}
static PyObject* rsaKey_getattr(rsaKey* key, char* attr) {
if (strcmp(attr, "n") == 0)
return mpzToLongObj(key->n);
else if (strcmp(attr, "e") == 0)
return mpzToLongObj(key->e);
else if (strcmp(attr, "d") == 0) {
if (mpz_size(key->d)==0) {
PyErr_SetString(PyExc_AttributeError, "rsaKey instance has no attribute 'd'");
return NULL;
}
return mpzToLongObj(key->d);
}
else if (strcmp(attr, "p") == 0) {
if (mpz_size(key->p)==0) {
PyErr_SetString(PyExc_AttributeError, "rsaKey instance has no attribute 'p'");
return NULL;
}
return mpzToLongObj(key->p);
}
else if (strcmp(attr, "q") == 0) {
if (mpz_size(key->q)==0) {
PyErr_SetString(PyExc_AttributeError, "rsaKey instance has no attribute 'q'");
return NULL;
}
return mpzToLongObj(key->q);
}
else {
return Py_FindMethod(rsaKey__methods__, (PyObject*) key, attr);
}
}
PyObject* rsaKey__encrypt(rsaKey *key, PyObject *args) {
PyObject *l, *r;
if (!(PyArg_ParseTuple(args, "O!", &PyLong_Type, &l))) {
return NULL;
}
mpz_t v;
mpz_init(v);
longObjToMPZ(v, (PyLongObject*)l);
int result = rsaEncrypt(key, v);
if (result == 1) { // plaintext too big
PyErr_SetString(rsaError, "Plaintext too large");
return NULL;
}
r = (PyObject*)mpzToLongObj(v);
mpz_clear(v);
return Py_BuildValue("N", r);
}
PyObject* rsaKey__decrypt(rsaKey *key, PyObject *args) {
PyObject *l, *r;
if (!(PyArg_ParseTuple(args, "O!", &PyLong_Type, &l))) {
return NULL;
}
mpz_t v;
mpz_init(v);
longObjToMPZ(v, (PyLongObject*)l);
int result = rsaDecrypt(key, v);
if (result == 1) { // ciphertext too big
PyErr_SetString(rsaError, "Ciphertext too large");
return NULL;
}
else if (result == 2) { // no private key
PyErr_SetString(rsaError, "Private key not available in this object");
return NULL;
}
r = mpzToLongObj(v);
mpz_clear(v);
return Py_BuildValue("N", r);
}
// PyObject* rsaKey__sign(rsaKey *key, PyObject *args) {} // same as __decrypt
PyObject* rsaKey__verify(rsaKey *key, PyObject *args) {
PyObject *l, *lsig;
if (!(PyArg_ParseTuple(args, "O!O!", &PyLong_Type, &l, &PyLong_Type, &lsig))) {
return NULL;
}
mpz_t v, vsig;
mpz_init(v);
mpz_init(vsig);
longObjToMPZ(v, (PyLongObject*)l);
longObjToMPZ(vsig, (PyLongObject*)lsig);
rsaEncrypt(key, vsig);
if (mpz_cmp(v, vsig) == 0)
return Py_BuildValue("i", 1);
else
return Py_BuildValue("i", 0);
}
PyObject* rsaKey_size(rsaKey *key) {
return Py_BuildValue("i", mpz_sizeinbase(key->n,2)-1);
}
PyObject* rsaKey_hasprivate(rsaKey *key) {
if (mpz_size(key->d) == 0)
return Py_BuildValue("i", 0);
else
return Py_BuildValue("i", 1);
}
void init_rsa(void) {
rsaKeyType.ob_type = &PyType_Type;
_rsa_module = Py_InitModule("_rsa", _rsa__methods__);
_rsa_dict = PyModule_GetDict(_rsa_module);
rsaError = PyErr_NewException("_rsa.error", NULL, NULL);
PyDict_SetItemString(_rsa_dict, "error", rsaError);
}
setup.py.diff
(application/octet-stream, 975 B)
Index: setup.py
===================================================================
RCS file: /cvsroot/pycrypto/crypto/setup.py,v
retrieving revision 1.16
diff -u -r1.16 setup.py
--- setup.py 18 Jul 2002 13:05:37 -0000 1.16
+++ setup.py 18 Nov 2002 23:20:27 -0000
@@ -71,7 +71,16 @@
Extension("Crypto.Cipher.XOR",
include_dirs=['src/'],
sources=["src/XOR.c"]),
-
+
+ # Public Key crypto
+ Extension("Crypto.PublicKey._rsa",
+ include_dirs=['src/'],
+ libraries=['gmp'],
+ sources=["src/_rsa.c"]),
+ Extension("Crypto.PublicKey._dsa",
+ include_dirs=['src/'],
+ libraries=['gmp'],
+ sources=["src/_dsa.c"]),
]
)
DSA.py.diff
(application/octet-stream, 1.9 KB)
Index: DSA.py
===================================================================
RCS file: /cvsroot/pycrypto/crypto/PublicKey/DSA.py,v
retrieving revision 1.4
diff -u -r1.4 DSA.py
--- DSA.py 11 Jul 2002 14:31:19 -0000 1.4
+++ DSA.py 19 Nov 2002 02:30:24 -0000
@@ -17,6 +17,11 @@
from Crypto.Util.number import bytes_to_long, long_to_bytes
from Crypto.Hash import SHA
+try:
+ from Crypto.PublicKey import _dsa
+except:
+ _dsa = None
+
class error (Exception):
pass
@@ -145,4 +150,54 @@
object=DSAobj
+generate_py = generate
+construct_py = construct
+
+class DSAobj_c(DSAobj):
+ def __init__(self, key):
+ self.key = key
+
+ def __getstate__(self):
+ d = {}
+ for k in self.keydata:
+ if hasattr(self.key, k):
+ d[k]=getattr(self.key, k)
+ return d
+
+ def __setstate__(self, state):
+ y,g,p,q = state['y'], state['g'], state['p'], state['q']
+ if 'x' not in state:
+ self.key = _dsa.construct(y,g,p,q)
+ else:
+ x = state['x']
+ self.key = _dsa.construct(y,g,p,q,x)
+
+ def _sign(self, M, K):
+ return self.key._sign(M, K)
+
+ def _verify(self, M, (r, s)):
+ return self.key._verify(M, r, s)
+
+ def size(self):
+ return self.key.size()
+
+ def hasprivate(self):
+ return self.key.hasprivate()
+
+ def publickey(self):
+ return construct_c((self.key.y, self.key.g, self.key.p, self.key.q))
+def generate_c(bits, randfunc, progress_func=None):
+ obj = generate_py(bits, randfunc, progress_func)
+ y,g,p,q,x = obj.y, obj.g, obj.p, obj.q, obj.x
+ return construct_c((y,g,p,q,x))
+
+def construct_c(tuple):
+ key = apply(_dsa.construct, tuple)
+ return DSAobj_c(key)
+
+if _dsa:
+ #print "using C version of DSA"
+ generate = generate_c
+ construct = construct_c
+ error = _dsa.error
RSA.py.diff
(application/octet-stream, 2.7 KB)
Index: RSA.py
===================================================================
RCS file: /cvsroot/pycrypto/crypto/PublicKey/RSA.py,v
retrieving revision 1.5
diff -u -r1.5 RSA.py
--- RSA.py 11 Jul 2002 14:33:05 -0000 1.5
+++ RSA.py 19 Nov 2002 02:29:33 -0000
@@ -14,6 +14,11 @@
from Crypto.PublicKey import pubkey
+try:
+ from Crypto.PublicKey import _rsa
+except:
+ _rsa = None
+
class error (Exception):
pass
@@ -101,7 +105,80 @@
"""
return construct((self.n, self.e))
+class RSAobj_c(pubkey.pubkey):
+ keydata = ['n', 'e', 'd', 'p', 'q']
+ n = property(lambda s:s.key.n)
+ e = property(lambda s:s.key.e)
+ d = property(lambda s:s.key.d)
+ p = property(lambda s:s.key.p)
+ q = property(lambda s:s.key.q)
+
+ def __init__(self, key):
+ self.key = key
+
+ def __getstate__(self):
+ d = {}
+ for k in self.keydata:
+ if hasattr(self.key, k):
+ d[k]=getattr(self.key, k)
+ return d
+
+ def __setstate__(self, state):
+ n,e = state['n'], state['e']
+ if 'd' not in state:
+ self.key = _rsa.construct(n,e)
+ else:
+ d = state['d']
+ if 'q' not in state:
+ self.key = _rsa.construct(n,e,d)
+ else:
+ p, q = state['p'], state['q']
+ self.key = _rsa.construct(n,e,d,p,q)
+
+ def _encrypt(self, plain, K):
+ return (self.key._encrypt(plain),)
+ def _decrypt(self, cipher):
+ return self.key._decrypt(cipher[0])
+ def _sign(self, M, K):
+ return (self.key._sign(M),)
+ def _verify(self, M, sig):
+ return self.key._verify(M, sig[0])
+ def size(self):
+ return self.key.size()
+ def hasprivate(self):
+ return self.key.hasprivate()
+ def publickey(self):
+ return construct_c((self.key.n, self.key.e))
+
+def generate_c(bits, randfunc, progress_func = None):
+ difference=ord(randfunc(1)) & 7
+
+ # Generate the prime factors of n
+ if progress_func: progress_func('p\n')
+ p=pubkey.getPrime(bits/2, randfunc)
+ if progress_func: progress_func('q\n')
+ q=pubkey.getPrime((bits/2)+difference, randfunc)
+ n=p*q
+
+ # Generate encryption exponent
+ if progress_func: progress_func('e\n')
+ e=pubkey.getPrime(17, randfunc)
+ if progress_func: progress_func('d\n')
+ d=pubkey.inverse(e, (p-1)*(q-1))
+ key = _rsa.construct(n,e,d,p,q)
+ return RSAobj_c(key)
+
+def construct_c(tuple):
+ key = apply(_rsa.construct, tuple)
+ return RSAobj_c(key)
object = RSAobj
+generate_py = generate
+construct_py = construct
+if _rsa:
+ #print "using C version of RSA"
+ generate = generate_c
+ construct = construct_c
+ error = _rsa.error