RSA/DSA in C, part deux

Paul Swartz <[email protected]>
Newsgroups gmane.comp.python.cryptography
Message-ID <3DDA8C92.6933.FA394F@localhost>
New versions of the C modules attached, the old
ones didn't build on all C compilers (thank you -
pedantic).

-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:  _rsa.c
     Date:  19 Nov 2002, 19:08
     Size:  7137 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.c
     Date:  19 Nov 2002, 19:08
     Size:  7184 bytes.
     Type:  Text
_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;
  mpz_t temp;
  PyLongObject *l = _PyLong_New(size);
  if (!l) return NULL;
  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*, PyObject*);
static PyObject * rsaKey_hasprivate(rsaKey*, PyObject*);

PyObject *rsaError; /* raised on errors */

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_VARARGS, "Return the number of bits that this key can handle."},
  {"hasprivate", (PyCFunction)rsaKey_hasprivate, METH_VARARGS, "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;
}

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;
  mpz_t v;
  int result;
  if (!(PyArg_ParseTuple(args, "O!", &PyLong_Type, &l))) {
    return NULL;
  }
  mpz_init(v);
  longObjToMPZ(v, (PyLongObject*)l);
  result = rsaEncrypt(key, v);
  if (result == 1) {
    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;
  mpz_t v;
  int result;
  if (!(PyArg_ParseTuple(args, "O!", &PyLong_Type, &l))) {
    return NULL;
  }
  mpz_init(v);
  longObjToMPZ(v, (PyLongObject*)l);
  result = rsaDecrypt(key, v);
  if (result == 1) {
    PyErr_SetString(rsaError, "Ciphertext too large");
    return NULL;
  }
  else if (result == 2) {
    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__verify(rsaKey *key, PyObject *args) {
  PyObject *l, *lsig;
  mpz_t v, vsig;
  if (!(PyArg_ParseTuple(args, "O!O!", &PyLong_Type, &l, &PyLong_Type, &lsig))) {
    return NULL;
  }
  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, PyObject* args) {
  if (!PyArg_ParseTuple(args, "")) return NULL;
  return Py_BuildValue("i", mpz_sizeinbase(key->n,2)-1);
}

PyObject* rsaKey_hasprivate(rsaKey *key, PyObject* args) {
  if (!PyArg_ParseTuple(args, "")) return NULL;
  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);
}
_dsa.c (application/octet-stream, 7 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;
  mpz_t temp;
  PyLongObject *l = _PyLong_New(size);
  if (!l) {return NULL;}
  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) {
  mpz_t temp;
  if (mpz_cmp_ui(k, 2)<0 || mpz_cmp(k, key->q)>=0) {
    return 1;
  }
  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) {
  int result;
  mpz_t u1, u2, v1, v2, w;
  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;
  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*, PyObject*);
static PyObject * dsaKey_hasprivate(dsaKey*, PyObject*);

PyObject *dsaError; /* raised on errors */

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_VARARGS, "Return the number of bits that this key can handle."},
  {"hasprivate", (PyCFunction)dsaKey_hasprivate, METH_VARARGS, "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;
  mpz_t m, k, r, s;
  int result;
  if (!(PyArg_ParseTuple(args, "O!O!", &PyLong_Type, &lm,
                                       &PyLong_Type, &lk))) {
    return NULL;
  }
  mpz_init(m);
  mpz_init(k);
  mpz_init(r);
  mpz_init(s);
  longObjToMPZ(m, (PyLongObject*)lm);
  longObjToMPZ(k, (PyLongObject*)lk);
  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;
  mpz_t m, r, s;
  int result;
  if (!(PyArg_ParseTuple(args, "O!O!O!", &PyLong_Type, &lm,
                                         &PyLong_Type, &lr,
                                         &PyLong_Type, &ls))) {
    return NULL;
  }
  mpz_init(m);
  mpz_init(r);
  mpz_init(s);
  longObjToMPZ(m, (PyLongObject*)lm);
  longObjToMPZ(r, (PyLongObject*)lr);
  longObjToMPZ(s, (PyLongObject*)ls);
  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, PyObject* args) {
  if (!PyArg_ParseTuple(args, "")) return NULL;
  return Py_BuildValue("i", mpz_sizeinbase(key->p,2)-1);
}

PyObject* dsaKey_hasprivate(dsaKey *key, PyObject* args) {
  if (!PyArg_ParseTuple(args, "")) return NULL;
  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);
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.