Adding functionality into DSA.

Igor Belyi <[email protected]>
Newsgroups gmane.comp.python.cryptography
Message-ID <1081817615.1495.11.camel@leonid>
I've added some functionality into DSA so that it can now sign, verify,
and save/retrieve public and private keys in/from files.

To be honest, it was just copy/paste from the RSA with slight
variations. But at least now you can use DSA for some simple security
purposes.

Patch is on top of m2crypto-0.13.1

Cheers,
Igor
m2crypto-0.13.1-DSA.patch (text/x-patch, 5.9 KB)
diff -ur m2crypto-0.13.orig/M2Crypto/DSA.py m2crypto-0.13/M2Crypto/DSA.py
--- m2crypto-0.13.orig/M2Crypto/DSA.py  2004-04-12 20:19:46.000000000 -0400
+++ m2crypto-0.13/M2Crypto/DSA.py       2004-04-12 20:34:41.000000000 -0400
@@ -58,11 +58,62 @@
         assert m2.dsa_type_check(self.dsa), "'dsa' type error"
         m2.dsa_gen_key(self.dsa)

-    def save_key(self, file, callback=util.passphrase_callback):
-        pass
+    def save_key_bio(self, bio, cipher='des_ede3_cbc', callback=util.passphrase_callback):
+        """
+        Save the key pair to an M2Crypto.BIO object in PEM format.
+
+        _bio_ is the target M2Crypto.BIO object.
+
+        _cipher_ is a symmetric cipher to protect the key. The
+        default cipher is 'des_ede3_cbc', i.e., three-key triple-DES
+        in cipher block chaining mode. If _cipher_ is None, then the key
+        is saved in the clear.
+
+        _callback_ is a Python callable object that is invoked
+        to acquire a passphrase with which to protect the key.
+        """
+        if cipher is None:
+            return m2.dsa_write_key_no_cipher(self.dsa, bio._ptr(), callback)
+        else:
+            ciph = getattr(m2, cipher, None)
+            if ciph is None:
+                raise DSAError, 'not such cipher %s' % cipher
+            else:
+                ciph = ciph()
+            return m2.dsa_write_key(self.dsa, bio._ptr(), ciph, callback)
+
+    def save_key(self, file, cipher='des_ede3_cbc', callback=util.passphrase_callback):
+        """
+        Save the key pair to filename _file_ in PEM format.
+        """
+        bio = BIO.openfile(file, 'wb')
+        return self.save_key_bio(bio, cipher, callback)
+
+    def save_pub_key_bio(self, bio):
+        """
+        Save the public key to the M2Crypto.BIO object _bio_ in PEM format.
+        """
+        return m2.dsa_write_pub_key(self.dsa, bio._ptr())
+
+    def save_pub_key(self, file):
+        """
+        Save the public key to filename _file_ in PEM format.
+        """
+        bio = BIO.openfile(file, 'wb')
+        return self.save_pub_key_bio(bio)
+
+    def save_params_bio(self, bio):
+        """
+        Save DSA parameters to the M2Crypto.BIO object _bio_ in PEM format.
+        """
+        return m2.dsa_write_params(self.dsa, bio._ptr())

     def save_params(self, file):
-        pass
+        """
+        Save DSA parameters to filename _file_ in PEM format.
+        """
+        bio = BIO.openfile(file, 'wb')
+        return self.save_params_bio(bio)

     def sign(self, digest):
         assert self.check_key(), 'key is not initialised'
@@ -76,9 +127,9 @@
         assert self.check_key(), 'key is not initialised'
         return m2.dsa_sign_asn1(self.dsa, digest)

-    def verify_asn1(self, digest, blob):
+    def verify_asn1(self, digest, sign):
         assert self.check_key(), 'key is not initialised'
-        return m2.dsa_verify_asn1(self.dsa, digest, blob)
+        return m2.dsa_verify_asn1(self.dsa, digest, sign)

     def check_key(self):
         assert m2.dsa_type_check(self.dsa), "'dsa' type error"
@@ -92,8 +143,25 @@
     Object interface to a DSA public key.
     """

-    def __init__(self, *args):
-        raise NotImplementedError
+    def __setattr__(self, name, value):
+        if name in ['p', 'q', 'g', 'priv', 'pub']:
+            raise DSAError, \
+                'DSA_pub object can not change its parameters'
+        else:
+            self.__dict__[name] = value
+
+    def sign(self, digest):
+        raise DSAError, 'DSA_pub object can not be used for signing'
+
+    def sign_asn1(self, digest):
+        raise DSAError, 'DSA_pub object can not be used for signing'
+
+    save_key = DSA.save_pub_key
+
+    save_key_bio = DSA.save_pub_key_bio
+
+    def check_key(self):
+        return m2.dsa_check_pub_key(self.dsa)


 def paramgen_callback(p, n, out=sys.stdout):
@@ -175,3 +243,27 @@
     """
     return DSA(m2.dsa_read_key(bio._ptr(), callback), 1)

+
+def load_pub_key(file):
+    """
+    Factory function that instantiates an DSA_pub object.
+
+    The argument 'file' contains the PEM representation of the DSA public key.
+    """
+    bio = BIO.openfile(file)
+    return load_pub_key_bio(bio)
+
+
+def load_pub_key_bio(bio):
+    """
+    Factory function that instantiates an DSA_pub object.
+
+    The argument 'bio' is an M2Crypto.BIO object that contains the PEM
+    representation of the DSA public key.
+    """
+    dsa = m2.dsa_read_pub_key(bio._ptr())
+    if dsa is None:
+        dsa_error()
+    return DSA_pub(dsa, 1)
+
+
diff -ur m2crypto-0.13.orig/SWIG/_dsa.i m2crypto-0.13/SWIG/_dsa.i
--- m2crypto-0.13.orig/SWIG/_dsa.i      2003-06-22 13:30:52.000000000 -0400
+++ m2crypto-0.13/SWIG/_dsa.i   2004-04-12 20:31:36.000000000 -0400
@@ -183,6 +183,10 @@
     return ret;
 }

+int dsa_write_params(DSA *dsa, BIO *f) {
+    return PEM_write_bio_DSAparams(f, dsa);
+}
+
 DSA *dsa_read_key(BIO *f, PyObject *pyfunc) {
     DSA *ret;

@@ -192,6 +196,34 @@
     return ret;
 }

+int dsa_write_key(DSA *dsa, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) {
+    int ret;
+
+    Py_INCREF(pyfunc);
+    ret = PEM_write_bio_DSAPrivateKey(f, dsa, cipher, NULL, 0,
+        passphrase_callback, (void *)pyfunc);
+    Py_DECREF(pyfunc);
+    return ret;
+}
+
+int dsa_write_key_no_cipher(DSA *dsa, BIO *f, PyObject *pyfunc) {
+    int ret;
+
+    Py_INCREF(pyfunc);
+    ret = PEM_write_bio_DSAPrivateKey(f, dsa, NULL, NULL, 0,
+                                     passphrase_callback, (void *)pyfunc);
+    Py_DECREF(pyfunc);
+    return ret;
+}
+
+DSA *dsa_read_pub_key(BIO *f) {
+    return PEM_read_bio_DSA_PUBKEY(f, NULL, NULL, NULL);
+}
+
+int dsa_write_pub_key(DSA *dsa, BIO *f) {
+    return PEM_write_bio_DSA_PUBKEY(f, dsa);
+}
+
 /* Deprecated.
 PyObject *dsa_sign(DSA *dsa, Blob *digest) {
     PyObject *pytuple;
@@ -377,6 +409,10 @@
     return (dsa->pub_key) && (dsa->priv_key);
 }

+int dsa_check_pub_key(DSA *dsa) {
+    return dsa->pub_key;
+}
+
 int dsa_keylen(DSA *dsa) {
     return BN_num_bits(dsa->p);
 }
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.