Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added PKCSv1 2.2 PSS and SHA3-224 support #204

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion doc/compatibility.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ Compatibility with standards
.. index:: compatibility

Python-RSA implements encryption and signatures according to PKCS#1
version 1.5. This makes it compatible with the OpenSSL RSA module.
version 1.5. Additionally, Python-RSA implements signatures according to PKCS#1
version 2.1 and supports the hashes of PKCS#1 version 2.2 (excluding SHA-512/224
or SHA-512/256, as these are not provided by the ``hashlib`` module).
This makes it largely compatible with the OpenSSL RSA module.

Keys are stored in PEM or DER format according to PKCS#1 v1.5. Private
keys are compatible with OpenSSL. However, OpenSSL uses X.509 for its
Expand All @@ -17,6 +20,8 @@ Encryption:
Signatures:
PKCS#1 v1.5 using the following hash methods:
MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512
PKCS#1 v2.1 using the following hash methods:
SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA3-224, SHA3-256, SHA3-384, SHA3-512

Private keys:
PKCS#1 v1.5 in PEM and DER format, ASN.1 type RSAPrivateKey
Expand Down
5 changes: 4 additions & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ Welcome to Python-RSA's documentation!

Python-RSA is a pure-Python RSA implementation. It supports
encryption and decryption, signing and verifying signatures, and key
generation according to PKCS#1 version 1.5.
generation according to PKCS#1 version 1.5. Additionally, Python-RSA
implements signatures according to PKCS#1 version 2.1 and supports the
hashes of PKCS#1 version 2.2 (excluding SHA-512/224 or SHA-512/256, as
these are not provided by the ``hashlib`` module)

If you have the time and skill to improve the implementation, by all
means be my guest. The best way is to clone the `Git
Expand Down
9 changes: 9 additions & 0 deletions doc/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ Functions

.. autodata:: rsa.pkcs1.HASH_METHODS

.. autofunction:: rsa.pkcs1_v2.sign

.. autofunction:: rsa.pkcs1_v2.verify

.. autofunction:: rsa.pkcs1_v2.sign_hash

.. autodata:: rsa.pkcs1_v2.HASH_METHODS

Classes
-------
Expand Down Expand Up @@ -56,6 +63,8 @@ Exceptions

.. autoclass:: rsa.pkcs1.VerificationError(CryptoError)

.. autoclass:: rsa.pkcs1_v2.VerificationError(CryptoError)


.. index:: VARBLOCK (file format)

Expand Down
68 changes: 66 additions & 2 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,72 @@ are considered low-level and are supported by the
:py:func:`rsa.core.encrypt_int` and :py:func:`rsa.core.decrypt_int`
functions.

Signing and verification
------------------------
Signing and verification (PKCS#1 v2.2)
--------------------------------------

You can create a detached PSS signature for a message using the
:py:func:`rsa.sign` function:

>>> (pubkey, privkey) = rsa.newkeys(512)
>>> message = 'Go left at the blue tree'.encode()
>>> signature = rsa.pkcs1_v2.sign(message, privkey, 'SHA-1')

This hashes the message using SHA-1. Other hash methods are also
possible, check the :py:func:`rsa.pkcs1_v2.sign` function documentation for
details. The hash is then signed with the private key. A fourth argument
may be provided to override the default signature salt length of 20.

It is possible to calculate the hash and signature in separate operations
(i.e for generating the hash on a client machine and then sign with a
private key on remote server). To hash a message use the :py:func:`rsa.compute_hash`
function and then use the :py:func:`rsa.pkcs1_v2.sign_hash` function to sign the hash:

>>> message = 'Go left at the blue tree'.encode()
>>> hash = rsa.compute_hash(message, 'SHA-1')
>>> signature = rsa.pkcs1_v2.sign_hash(hash, privkey, 'SHA-1', 20)

In order to verify the signature, use the :py:func:`rsa.pkcs1_v2.verify`
function. A fourth argument may be provided to override the default signature
salt length of 20; this value must match the one used when signing or verification
will fail. If the verification is successful, this function returns
the hash algorithm used as a string:

>>> message = 'Go left at the blue tree'.encode()
>>> rsa.verify(message, signature, pubkey)
'SHA-1'

Modify the message, and the signature is no longer valid and a
:py:class:`rsa.pkcs1_v2.VerificationError` is thrown:

>>> message = 'Go right at the blue tree'.encode()
>>> rsa.pkcs1_v2.verify(message, signature, pubkey)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/sybren/workspace/python-rsa/rsa/pkcs1_v2.py", line 289, in verify
raise VerificationError('Verification failed')
rsa.pkcs1_v2.VerificationError: Verification failed

.. warning::

Never display the stack trace of a
:py:class:`rsa.pkcs1_v2.VerificationError` exception. It shows where
in the code the exception occurred, and thus leaks information
about the key. It's only a tiny bit of information, but every bit
makes cracking the keys easier.

Instead of a message you can also call :py:func:`rsa.pkcs1_v2.sign` and
:py:func:`rsa.pkcs1_v2.verify` with a `file`-like object. If the
message object has a ``read(int)`` method it is assumed to be a file.
In that case the file is hashed in 1024-byte blocks at the time.

>>> with open('somefile', 'rb') as msgfile:
... signature = rsa.pkcs1_v2.sign(msgfile, privkey, 'SHA-1')

>>> with open('somefile', 'rb') as msgfile:
... rsa.pkcs1_v2.verify(msgfile, signature, pubkey)

Signing and verification (PKCS#1 v1.5)
--------------------------------------

You can create a detached signature for a message using the
:py:func:`rsa.sign` function:
Expand Down