[Cryptography-dev] Asymmetric signing primitives

Ron Frederick ronf at timeheart.net
Sat Jul 26 21:52:32 CEST 2014


Hello,

I recently began looking at adding support for PyCA to my AsyncSSH package (http://asyncssh.timeheart.net). It currently uses PyCrypto, but I see a lot of potential in being able to directly use OpenSSL and other more carefully scrutinized crypto libraries from a security perspective.

In the process of adding this support, I ran into an issue with DSA signing and verification. The current implementation in PyCA seems to ASN.1 encode the signature it produces before returning it, while the SSH protocol requires a different encoding to be used of the raw ‘r’ and ’s’ values. I’ve worked around this for now by doing my own ASN.1 code of the return result before re-encoding it in the form SSH needs, but this is somewhat wasteful. I was wondering if it might be possible to provide an option or alternate API which would return the raw r & s values as integers, for protocols that want to use an encoding other than ASN.1.

As I worked with these asymmetric key classes, I also noticed a bit of an inconsistency in the API used to access the various raw numbers that go into making up the keys. The current API uses a mixture of method calls and properties, and provides different ways to access some of the values depending on whether you are working with public or private keys. I think it would be good to make this a bit more consistent, at least about method calls vs. properties, but also ideally to provide a common way to access all the values common to public & private keys using the same API, with additional API calls for private keys to access values only applicable there.

As an example of what I’m talking about, here are the calls needed to access the parameters of a DSA public key today:

p: key.parameters().parameter_numbers().p
q: key.parameters().parameter_numbers().q
g: key.parameters().parameter_numbers().g
y: key.public_numbers().y

Note how in one case you can get to the public numbers directly, whereas in the other you have to go through an intermediate object first. It would be nice there to have parameter_numbers() available directly from the key similar to public_numbers(), at least as a convenience function. I would keep the existing parameters() function as well, as it has value to extract the parameters as a group to use in creating other keys. However, allowing access either that way or directly to the numbers object would be nice.

For a DSA private key, the first three calls are the same, but the call to get the “y” value is different:

y: key.private_numbers().public_numbers.y

Also, note here how public_numbers is a property of the object returned by private_numbers(), rather than being a function call the way it is above. Again, it would be nice if private keys had parameter_numbers(), public_numbers(), and private_numbers() calls to expose these values directly, in a way consistent with public keys.

The final call to get the private numbers is already consistent with this:

x: key.private_numbers().x

What I’m suggesting is something that looks more like:

p: key.parameter_numbers().p
q: key.parameter_numbers().q
g: key.parameter_numbers().g
y: key.public_numbers().y
x: key.private_numbers().x

RSA keys have similar issues. The current calls for public keys are:

n: key.public_numbers().n
e: key.public_numbers().e

However, the calls for private keys are:

n: key.private_numbers().public_numbers.n
e: key.private_numbers().public_numbers.e
d: key.private_numbers().d
p: key.private_numbers().p
q: key.private_numbers().q

Having a directly callable public_numbers() function on both the public & private key classes here would be convenient.

Finally, if I may, I have one final suggestion. It would be convenient to have the update() function return self (the signer object). That way, it would be possible to write something like:

        signature = key.signer(PKCS1v15(), SHA1()).update(data).finalize()

instead of:

        signer = self._key.signer(PKCS1v15(), SHA1())
        signer.update(data)
        signature = signer.finalize()

in cases where you had only a single block of data to pass in.

Thank you for listening, and for all the work that has gone into this package so far!
-- 
Ron Frederick
ronf at timeheart.net

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cryptography-dev/attachments/20140726/2b446c02/attachment.html>


More information about the Cryptography-dev mailing list