Python Cryptography Toolkit

Support for PKCS#1 v1.5 signatures (RFC3447)

Reported by Legrandin on 2010-01-02
14
This bug affects 2 people
Affects Status Importance Assigned to Milestone
Python-Crypto
Wishlist
Unassigned

Bug Description

This patch adds support for PKCS#1 v1.5 signatures.

The sign() and verify() methods for an RSA key object
are extended to accept an optional 'protocol' parameter,
to specify how the signature should be carried out.

The default value is 'raw' (or 'schoolbook') which is
still the original algorithm. Since 'protocol' is optional
there should be no backward compatibility problems.

The 'protocol' associated to PKCS#1 v1.5 is either 'PKCS1',
'PKCS1-1.5' , or 'RSA/PKCS1-1.5'. Since such protocol
embeds the OID of the hash used, I have also modified
each available hash algorithm so that each hash object has got
an appropriate 'oid' string attribute, that will be retrieved
by the sign() method.

I guess that in the future we may add other protocols in
the same way, by picking intuitive strings (e.g.' PKCS1-PSS', 'X9.31', etc).

The verification code is not subject to Bleichenbacher's
(http://www.imc.org/ietf-openpgp/mail-archive/msg14307.html)
and OKW's (http://lists.gnupg.org/pipermail/gnutls-dev/2006-September/001240.html)
attacks.

Typical usage is the following:

import Crypto.Hash.SHA
import Crypto.PublicKey.RSA

message = "Test"
hash = SHA.new()
hash.update(message)

signature = k.sign(hash, None, 'PKCS1')[0]

[... at the other end ...]
messageReceived = "Test"
hash = SHA.new()
hash.update(messageReceived)

auth = k.verify(hash, signatureReceived)

Legrandin (gooksankoo) wrote :

I forgot to add that this patch uses the DER routines from the previous one,
to make up the necessary DigestInfo structure, but in theory they could be
decoupled.

Dwayne Litzenberger (dlitz) wrote :

Marking this as "wishlist", though PKCS#1 v1.5 and v2 support are probably one of the higher-priority wishlist items, because I'd really like people to stop using textbook RSA.

Changed in pycrypto:
importance: Undecided → Wishlist
status: New → Confirmed

Will it be merged to trunk? Its really important. Well and it will be first implementation of PKCS#1 v1.5 in Python.

Emmanuel Blot (eblot-ml) wrote :

Any news about an integration into the official branch? Thanks.

Thorsten Behrens (sbehrens-gmx) wrote :

Since this came up again on the mailing list: How does this play with the moratorium on new ciphers (http://lists.dlitz.net/pipermail/pycrypto/2010q3/000264.html)? It's not, strictly speaking, a new cipher, and Legrandin has a history of working on the RSA/DSA code. He patched in unit tests, too, which is great.

I'd like to see this resurrected and brought in. I'll even volunteer to bring it into pycrypto-next, though for selfish reasons, I'd like to see the py3k work land on trunk first, then create a branch to bring this patch in. That'd make it easier to maintain one code base. The py3k work and this patch both have a large number of changes to the same files, which would be a pain to merge from two branches.

Thorsten Behrens (sbehrens-gmx) wrote :

nm, I re-read your post. "Permanent feature freeze", not just "freeze on from-scratch-new implementations". I guess that leaves us with the backend API. I'd love to hear what you have come up with so far.

Guddu (anurag-chourasia) wrote :

Hi Dwayne, Appreciate your help in getting this patch into the Main Stream.

The goal behind the freeze is to improve security in a practical sense by ensuring that the project remains maintainable, and to avoid adding new security holes (especially in the C code).

Considering how many times I've seen people report the "plaintext too large" error as a PyCrypto bug rather than PEBKAC, I think we can make some huge security gains by adding PKCS#1 v2 and v1.5 support, without adding too much complexity to the code base.

I do want to pay close attention to the resulting API, however. The Crypto.PublicKey API is pretty unfriendly, and I'd like to avoid making the same mistake with PKCS#1.

"Thorsten Behrens" <email address hidden> wrote:

>Since this came up again on the mailing list: How does this play with
>the moratorium on new ciphers
>(http://lists.dlitz.net/pipermail/pycrypto/2010q3/000264.html)? It's
>not, strictly speaking, a new cipher, and Legrandin has a history of
>working on the RSA/DSA code. He patched in unit tests, too, which is
>great.
>
>I'd like to see this resurrected and brought in. I'll even volunteer to
>bring it into pycrypto-next, though for selfish reasons, I'd like to
>see
>the py3k work land on trunk first, then create a branch to bring this
>patch in. That'd make it easier to maintain one code base. The py3k
>work
>and this patch both have a large number of changes to the same files,
>which would be a pain to merge from two branches.
>
>--
>You received this bug notification because you are subscribed to
>Python-
>Crypto.
>https://bugs.launchpad.net/bugs/502291
>
>Title:
> Support for PKCS#1 v1.5 signatures (RFC3447)

--
Sent from my Android phone with K-9 Mail. Please excuse my brevity.

Guddu (anurag-chourasia) wrote :
Download full text (3.8 KiB)

Good Evening Folks :-)

Could you please tell me if we are going to include this in the trunk soon
then?

Thanks for all your help and all the amazing work that you guys have done.

Regards,
Anurag

On Wed, Dec 29, 2010 at 9:12 PM, Dwayne Litzenberger <email address hidden>wrote:

> The goal behind the freeze is to improve security in a practical sense
> by ensuring that the project remains maintainable, and to avoid adding
> new security holes (especially in the C code).
>
> Considering how many times I've seen people report the "plaintext too
> large" error as a PyCrypto bug rather than PEBKAC, I think we can make
> some huge security gains by adding PKCS#1 v2 and v1.5 support, without
> adding too much complexity to the code base.
>
> I do want to pay close attention to the resulting API, however. The
> Crypto.PublicKey API is pretty unfriendly, and I'd like to avoid making
> the same mistake with PKCS#1.
>
> "Thorsten Behrens" <email address hidden> wrote:
>
> >Since this came up again on the mailing list: How does this play with
> >the moratorium on new ciphers
> >(http://lists.dlitz.net/pipermail/pycrypto/2010q3/000264.html)? It's
> >not, strictly speaking, a new cipher, and Legrandin has a history of
> >working on the RSA/DSA code. He patched in unit tests, too, which is
> >great.
> >
> >I'd like to see this resurrected and brought in. I'll even volunteer to
> >bring it into pycrypto-next, though for selfish reasons, I'd like to
> >see
> >the py3k work land on trunk first, then create a branch to bring this
> >patch in. That'd make it easier to maintain one code base. The py3k
> >work
> >and this patch both have a large number of changes to the same files,
> >which would be a pain to merge from two branches.
> >
> >--
> >You received this bug notification because you are subscribed to
> >Python-
> >Crypto.
> >https://bugs.launchpad.net/bugs/502291
> >
> >Title:
> > Support for PKCS#1 v1.5 signatures (RFC3447)
>
> --
> Sent from my Android phone with K-9 Mail. Please excuse my brevity.
>
> --
> You received this bug notification because you are a direct subscriber
> of the bug.
> https://bugs.launchpad.net/bugs/502291
>
> Title:
> Support for PKCS#1 v1.5 signatures (RFC3447)
>
> Status in Python Cryptography Toolkit:
> Confirmed
>
> Bug description:
> This patch adds support for PKCS#1 v1.5 signatures.
>
> The sign() and verify() methods for an RSA key object
> are extended to accept an optional 'protocol' parameter,
> to specify how the signature should be carried out.
>
> The default value is 'raw' (or 'schoolbook') which is
> still the original algorithm. Since 'protocol' is optional
> there should be no backward compatibility problems.
>
> The 'protocol' associated to PKCS#1 v1.5 is either 'PKCS1',
> 'PKCS1-1.5' , or 'RSA/PKCS1-1.5'. Since such protocol
> embeds the OID of the hash used, I have also modified
> each available hash algorithm so that each hash object has got
> an appropriate 'oid' string attribute, that will be retrieved
> by the sign() method.
>
> I guess that in the future we may add other protocols in
> the same way, by picking intuitive strings (e.g.' PKCS1-PSS', 'X9.31',
> etc).
>
> The verification code is n...

Read more...

Legrandin (gooksankoo) wrote :

@Thorsten, I can defintely revive this patch (and add more documentation) as a github fork as soon as your python 3 work get merged into fork.

What is not clear to me is whether the proposed API (see patch description) is OK to you guys or not.

@Dwayne, note that this patch *extends* Crypto.PublicKey (which I agree is pretty horrible): it does not create a new API. However, it is backward compatible and at least it does not break any existing application using it.

Legrandin (gooksankoo) wrote :

I meant ... as soon as your work gets merged in the *trunk*... :-)

Guddu (anurag-chourasia) wrote :

Applied this patch over V2.3 Downloaded from GITHUB

Guddu (anurag-chourasia) wrote :

The Private Key that I am using is in the attached XML (Element Tag name is RSASK). Signing with this key fails with the error "RSA key format is not supported"

Guddu (anurag-chourasia) wrote :

G'day All,

I download the V2.3 ZIP from Github and applied the changes from this patch over it (Resulting Code Set Attached).

Apart from indentation changes I did the following change to make things work.

RSA.py
=====

Change

EMSA_PKCS1_V1_5_ENCODE(m, blockLen)
to
self.EMSA_PKCS1_V1_5_ENCODE(m, blockLen)

Change

def EMSA_PKCS1_V1_5_ENCODE(hash, emLen):
to
def EMSA_PKCS1_V1_5_ENCODE(self, hash, emLen):

Once i got it all working, signing fails with the error "RSA key format is not supported"

The Private Key that I am using is in the XML attached to this bug report (Element Tag name is RSASK)

Appreciate if you could tell me what might be going wrong here.

Regards,
Anurag

Guddu (anurag-chourasia) wrote :

Dear All,

Please ignore my previous comment.

Signing works just perfectly fine :-) Thanks for all the hardwork.

What i did wrong earlier was I was not extracting the Private key from the XML Properly.

From the XML, I was using the string "<KeyElement>KeyValue</KeyElement>" instead of using "KeyValue" as the Key to do the signs.

It will be good to see this Patch in the MainStream :-)

Regards,
Anurag

Legrandin (gooksankoo) wrote :

I have put a variation of this in a branch on github, which is available via this command:

git clone -b pkcs1 git://github.com/Legrandin/pycrypto.git

I have realized in the meanwhile that the Crypto.PublicKey.RSA interface contains already too much stuff and is quite shaky.

I therefore tried to create a separate module for signatures (much in the style of JCA).

import Crypto.Signature.PKCS1_v1_5 as PKCS
import Crypto.Hash.SHA as SHA1
import Crypto.PublicKey.RSA as RSA

key = RSA.importKey('pubkey.der')
h = SHA1.new()
h.update(message)
if PKCS.verify(h, key, signature):
    print "The signature is authentic."
else:
    print "The signature is not authentic."

Seem to be much cleaner than the other attempt.

Guddu (anurag-chourasia) wrote :

Thanks :-)

On Fri, Feb 4, 2011 at 12:17 AM, Legrandin <email address hidden>wrote:

> I have put a variation of this in a branch on github, which is available
> via this command:
>
> git clone -b pkcs1 git://github.com/Legrandin/pycrypto.git
>
> I have realized in the meanwhile that the Crypto.PublicKey.RSA interface
> contains already too much stuff and is quite shaky.
>
> I therefore tried to create a separate module for signatures (much in
> the style of JCA).
>
> import Crypto.Signature.PKCS1_v1_5 as PKCS
> import Crypto.Hash.SHA as SHA1
> import Crypto.PublicKey.RSA as RSA
>
> key = RSA.importKey('pubkey.der')
> h = SHA1.new()
> h.update(message)
> if PKCS.verify(h, key, signature):
> print "The signature is authentic."
> else:
> print "The signature is not authentic."
>
> Seem to be much cleaner than the other attempt.
>
> --
> You received this bug notification because you are a direct subscriber
> of the bug.
> https://bugs.launchpad.net/bugs/502291
>
> Title:
> Support for PKCS#1 v1.5 signatures (RFC3447)
>
> Status in Python Cryptography Toolkit:
> Confirmed
>
> Bug description:
> This patch adds support for PKCS#1 v1.5 signatures.
>
> The sign() and verify() methods for an RSA key object
> are extended to accept an optional 'protocol' parameter,
> to specify how the signature should be carried out.
>
> The default value is 'raw' (or 'schoolbook') which is
> still the original algorithm. Since 'protocol' is optional
> there should be no backward compatibility problems.
>
> The 'protocol' associated to PKCS#1 v1.5 is either 'PKCS1',
> 'PKCS1-1.5' , or 'RSA/PKCS1-1.5'. Since such protocol
> embeds the OID of the hash used, I have also modified
> each available hash algorithm so that each hash object has got
> an appropriate 'oid' string attribute, that will be retrieved
> by the sign() method.
>
> I guess that in the future we may add other protocols in
> the same way, by picking intuitive strings (e.g.' PKCS1-PSS', 'X9.31',
> etc).
>
> The verification code is not subject to Bleichenbacher's
> (http://www.imc.org/ietf-openpgp/mail-archive/msg14307.html)
> and OKW's (
> http://lists.gnupg.org/pipermail/gnutls-dev/2006-September/001240.html)
> attacks.
>
> Typical usage is the following:
>
> import Crypto.Hash.SHA
> import Crypto.PublicKey.RSA
>
> message = "Test"
> hash = SHA.new()
> hash.update(message)
>
> signature = k.sign(hash, None, 'PKCS1')[0]
>
> [... at the other end ...]
> messageReceived = "Test"
> hash = SHA.new()
> hash.update(messageReceived)
>
> auth = k.verify(hash, signatureReceived)
>
> To unsubscribe from this bug, go to:
> https://bugs.launchpad.net/pycrypto/+bug/502291/+subscribe
>

Dwayne Litzenberger (dlitz) wrote :

Thanks, everyone! Legrandin's implementation was merged in v2.5. From the docs:

    This scheme is more properly called ``RSASSA-PKCS1-v1_5``.

    For example, a sender may authenticate a message using SHA-1 like
    this:

            >>> from Crypto.Signature import PKCS1_v1_5
            >>> from Crypto.Hash import SHA
            >>> from Crypto.PublicKey import RSA
            >>>
            >>> message = 'To be signed'
            >>> key = RSA.importKey(open('privkey.der').read())
            >>> h = SHA.new(message)
            >>> signer = PKCS1_v1_5.new(key)
            >>> signature = signer.sign(h)

    At the receiver side, verification can be done using the public part of
    the RSA key:

            >>> key = RSA.importKey(open('pubkey.der').read())
            >>> h = SHA.new(message)
            >>> verifier = PKCS1_v1_5.new(key)
            >>> if verifier.verify(h, signature):
            >>> print "The signature is authentic."
            >>> else:
            >>> print "The signature is not authentic."

Changed in pycrypto:
status: Confirmed → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers