diff -Nru python-rsa-4.7.2/CHANGELOG.md python-rsa-4.8/CHANGELOG.md --- python-rsa-4.7.2/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 +++ python-rsa-4.8/CHANGELOG.md 2021-11-24 10:02:19.036184300 +0000 @@ -0,0 +1,235 @@ +# Python-RSA changelog + +## Version 4.8 - in development + +- Switch to [Poetry](https://python-poetry.org/) for dependency and release management. +- Compatibility with Python 3.10. +- Chain exceptions using `raise new_exception from old_exception` + ([#157](https://github.com/sybrenstuvel/python-rsa/pull/157)) +- Added marker file for PEP 561. This will allow type checking tools in dependent projects + to use type annotations from Python-RSA + ([#136](https://github.com/sybrenstuvel/python-rsa/pull/136)). +- Use the Chinese Remainder Theorem when decrypting with a private key. This + makes decryption 2-4x faster + ([#163](https://github.com/sybrenstuvel/python-rsa/pull/163)). + +## Version 4.7.2 - released 2021-02-24 + +- Fix picking/unpickling issue introduced in 4.7 + ([#173](https://github.com/sybrenstuvel/python-rsa/issues/173)) + +## Version 4.7.1 - released 2021-02-15 + +- Fix threading issue introduced in 4.7 + ([#173](https://github.com/sybrenstuvel/python-rsa/issues/173)) + +## Version 4.7 - released 2021-01-10 + +- Fix [#165](https://github.com/sybrenstuvel/python-rsa/issues/165): + CVE-2020-25658 - Bleichenbacher-style timing oracle in PKCS#1 v1.5 decryption + code +- Add padding length check as described by PKCS#1 v1.5 (Fixes + [#164](https://github.com/sybrenstuvel/python-rsa/issues/164)) +- Reuse of blinding factors to speed up blinding operations. + Fixes [#162](https://github.com/sybrenstuvel/python-rsa/issues/162). +- Declare & test support for Python 3.9 + + +## Version 4.4 & 4.6 - released 2020-06-12 + +Version 4.4 and 4.6 are almost a re-tagged release of version 4.2. It requires +Python 3.5+. To avoid older Python installations from trying to upgrade to RSA +4.4, this is now made explicit in the `python_requires` argument in `setup.py`. +There was a mistake releasing 4.4 as "3.5+ only", which made it necessary to +retag 4.4 as 4.6 as well. + +No functional changes compared to version 4.2. + + +## Version 4.3 & 4.5 - released 2020-06-12 + +Version 4.3 and 4.5 are almost a re-tagged release of version 4.0. It is the +last to support Python 2.7. This is now made explicit in the `python_requires` +argument in `setup.py`. Python 3.4 is not supported by this release. There was a +mistake releasing 4.4 as "3.5+ only", which made it necessary to retag 4.3 as +4.5 as well. + +Two security fixes have also been backported, so 4.3 = 4.0 + these two fixes. + +- Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. +- Reject cyphertexts (when decrypting) and signatures (when verifying) that have + been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks + Carnil for pointing this out. + + +## Version 4.2 - released 2020-06-10 + +- Rolled back the switch to Poetry, and reverted back to using Pipenv + setup.py + for dependency management. There apparently is an issue no-binary installs of + packages build with Poetry. This fixes + [#148](https://github.com/sybrenstuvel/python-rsa/issues/148) +- Limited SHA3 support to those Python versions (3.6+) that support it natively. + The third-party library that adds support for this to Python 3.5 is a binary + package, and thus breaks the pure-Python nature of Python-RSA. + This should fix [#147](https://github.com/sybrenstuvel/python-rsa/issues/147). + + +## Version 4.1 - released 2020-06-10 + +- Added support for Python 3.8. +- Dropped support for Python 2 and 3.4. +- Added type annotations to the source code. This will make Python-RSA easier to use in + your IDE, and allows better type checking. +- Added static type checking via [MyPy](http://mypy-lang.org/). +- Fix [#129](https://github.com/sybrenstuvel/python-rsa/issues/129) Installing from source + gives UnicodeDecodeError. +- Switched to using [Poetry](https://poetry.eustace.io/) for package + management. +- Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This + is natively supported by Python 3.6+ and supported via a third-party + library on Python 3.5. +- Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. +- Reject cyphertexts (when decrypting) and signatures (when verifying) that have + been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks + Adelapie for pointing this out. + + +## Version 4.0 - released 2018-09-16 + +- Removed deprecated modules: + - rsa.varblock + - rsa.bigfile + - rsa._version133 + - rsa._version200 +- Removed CLI commands that use the VARBLOCK/bigfile format. +- Ensured that PublicKey.save_pkcs1() and PrivateKey.save_pkcs1() always return bytes. +- Dropped support for Python 2.6 and 3.3. +- Dropped support for Psyco. +- Miller-Rabin iterations determined by bitsize of key. + [#58](https://github.com/sybrenstuvel/python-rsa/pull/58) +- Added function `rsa.find_signature_hash()` to return the name of the hashing + algorithm used to sign a message. `rsa.verify()` now also returns that name, + instead of always returning `True`. + [#78](https://github.com/sybrenstuvel/python-rsa/issues/13) +- Add support for SHA-224 for PKCS1 signatures. + [#104](https://github.com/sybrenstuvel/python-rsa/pull/104) +- Transitioned from `requirements.txt` to Pipenv for package management. + + +## Version 3.4.2 - released 2016-03-29 + +- Fixed dates in CHANGELOG.txt + + +## Version 3.4.1 - released 2016-03-26 + +- Included tests/private.pem in MANIFEST.in +- Included README.md and CHANGELOG.txt in MANIFEST.in + + +## Version 3.4 - released 2016-03-17 + +- Moved development to GitHub: https://github.com/sybrenstuvel/python-rsa +- Solved side-channel vulnerability by implementing blinding, fixes #19 +- Deprecated the VARBLOCK format and rsa.bigfile module due to security issues, see + https://github.com/sybrenstuvel/python-rsa/issues/13 +- Integration with Travis-CI [1], Coveralls [2] and Code Climate [3] +- Deprecated the old rsa._version133 and rsa._version200 submodules, they will be + completely removed in version 4.0. +- Add an 'exponent' argument to key.newkeys() +- Switched from Solovay-Strassen to Miller-Rabin primality testing, to + comply with NIST FIPS 186-4 [4] as probabilistic primality test + (Appendix C, subsection C.3): +- Fixed bugs #12, #14, #27, #30, #49 + +[1] https://travis-ci.org/sybrenstuvel/python-rsa +[2] https://coveralls.io/github/sybrenstuvel/python-rsa +[3] https://codeclimate.com/github/sybrenstuvel/python-rsa +[4] http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + + +## Version 3.3 - released 2016-01-13 + +- Thanks to Filippo Valsorda: Fix BB'06 attack in verify() by + switching from parsing to comparison. See [1] for more information. +- Simplified Tox configuration and dropped Python 3.2 support. The + coverage package uses a u'' prefix, which was reintroduced in 3.3 + for ease of porting. + +[1] https://blog.filippo.io/bleichenbacher-06-signature-forgery-in-python-rsa/ + + +## Version 3.2.3 - released 2015-11-05 + +- Added character encoding markers for Python 2.x + + +## Version 3.2.1 - released 2015-11-05 + +- Added per-file licenses +- Added support for wheel packages +- Made example code more consistent and up to date with Python 3.4 + + +## Version 3.2 - released 2015-07-29 + +- Mentioned support for Python 3 in setup.py + + +## Version 3.1.4 - released 2014-02-22 + +- Fixed some bugs + + +## Version 3.1.3 - released 2014-02-02 + +- Dropped support for Python 2.5 + + +## Version 3.1.2 - released 2013-09-15 + +- Added Python 3.3 to the test environment. +- Removed dependency on Distribute +- Added support for loading public keys from OpenSSL + + +## Version 3.1.1 - released 2012-06-18 + +- Fixed doctests for Python 2.7 +- Removed obsolete unittest so all tests run fine on Python 3.2 + +## Version 3.1 - released 2012-06-17 + +- Big, big credits to Yesudeep Mangalapilly for all the changes listed + below! +- Added ability to generate keys on multiple cores simultaneously. +- Massive speedup +- Partial Python 3.2 compatibility (core functionality works, but + saving or loading keys doesn't, for that the pyasn1 package needs to + be ported to Python 3 first) +- Lots of bug fixes + + + +## Version 3.0.1 - released 2011-08-07 + +- Removed unused import of abc module + + +## Version 3.0 - released 2011-08-05 + +- Changed the meaning of the keysize to mean the size of ``n`` rather than + the size of both ``p`` and ``q``. This is the common interpretation of + RSA keysize. To get the old behaviour, double the keysize when generating a + new key. +- Added a lot of doctests +- Added random-padded encryption and decryption using PKCS#1 version 1.5 +- Added hash-based signatures and verification using PKCS#1v1.5 +- Modeling private and public key as real objects rather than dicts. +- Support for saving and loading keys as PEM and DER files. +- Ability to extract a public key from a private key (PEM+DER) + + +## Version 2.0 + +- Security improvements by Barry Mead. diff -Nru python-rsa-4.7.2/create_timing_table.py python-rsa-4.8/create_timing_table.py --- python-rsa-4.7.2/create_timing_table.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/create_timing_table.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import time -import rsa - -poolsize = 8 -accurate = True - - -def run_speed_test(bitsize): - iterations = 0 - start = end = time.time() - - # At least a number of iterations, and at least 2 seconds - while iterations < 10 or end - start < 2: - iterations += 1 - rsa.newkeys(bitsize, accurate=accurate, poolsize=poolsize) - end = time.time() - - duration = end - start - dur_per_call = duration / iterations - - print('%5i bit: %9.3f sec. (%i iterations over %.1f seconds)' % - (bitsize, dur_per_call, iterations, duration)) - - -if __name__ == '__main__': - for bitsize in (128, 256, 384, 512, 1024, 2048, 3072, 4096): - run_speed_test(bitsize) diff -Nru python-rsa-4.7.2/debian/changelog python-rsa-4.8/debian/changelog --- python-rsa-4.7.2/debian/changelog 2021-09-26 06:18:08.000000000 +0000 +++ python-rsa-4.8/debian/changelog 2021-11-28 14:16:31.000000000 +0000 @@ -1,3 +1,11 @@ +python-rsa (4.8-1) unstable; urgency=medium + + * New upstream version 4.8 + * Bump Standards-Version to 4.6.0 + * d/patches: Remove unused patch + + -- TANIGUCHI Takaki Sun, 28 Nov 2021 23:16:31 +0900 + python-rsa (4.7.2-1) unstable; urgency=medium [ TANIGUCHI Takaki ] diff -Nru python-rsa-4.7.2/debian/control python-rsa-4.8/debian/control --- python-rsa-4.7.2/debian/control 2021-09-26 06:18:08.000000000 +0000 +++ python-rsa-4.8/debian/control 2021-11-28 14:16:31.000000000 +0000 @@ -11,7 +11,7 @@ , python3-pyasn1 , python3-mock , mypy -Standards-Version: 4.5.0 +Standards-Version: 4.6.0 Homepage: http://stuvel.eu/rsa X-Python-Versioni: >= 2.7 X-Python3-Versioni: >= 3.2 diff -Nru python-rsa-4.7.2/debian/patches/0001-Fix-test-failure.patch python-rsa-4.8/debian/patches/0001-Fix-test-failure.patch --- python-rsa-4.7.2/debian/patches/0001-Fix-test-failure.patch 2021-09-26 06:18:08.000000000 +0000 +++ python-rsa-4.8/debian/patches/0001-Fix-test-failure.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -From: TANIGUCHI Takaki -Date: Sun, 26 Sep 2021 15:10:27 +0900 -Subject: Fix test failure - -import from https://github.com/sybrenstuvel/python-rsa/pull/176 . ---- - rsa/pkcs1.py | 7 ++++++- - tests/test_mypy.py | 8 ++++++-- - 2 files changed, 12 insertions(+), 3 deletions(-) - -diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py -index 07cf85b..9adad90 100644 ---- a/rsa/pkcs1.py -+++ b/rsa/pkcs1.py -@@ -34,6 +34,11 @@ from hmac import compare_digest - - from . import common, transform, core, key - -+if typing.TYPE_CHECKING: -+ HashType = hashlib._Hash -+else: -+ HashType = typing.Any -+ - # ASN.1 codes that describe the hash algorithm used. - HASH_ASN1 = { - 'MD5': b'\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10', -@@ -44,7 +49,7 @@ HASH_ASN1 = { - 'SHA-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40', - } - --HASH_METHODS = { -+HASH_METHODS: typing.Dict[str, typing.Callable[[], HashType]] = { - 'MD5': hashlib.md5, - 'SHA-1': hashlib.sha1, - 'SHA-224': hashlib.sha224, -diff --git a/tests/test_mypy.py b/tests/test_mypy.py -index 8258e7e..b13cdcc 100644 ---- a/tests/test_mypy.py -+++ b/tests/test_mypy.py -@@ -1,4 +1,5 @@ - import pathlib -+import sys - import unittest - - import mypy.api -@@ -9,8 +10,11 @@ test_modules = ['rsa', 'tests'] - class MypyRunnerTest(unittest.TestCase): - def test_run_mypy(self): - proj_root = pathlib.Path(__file__).parent.parent -- args = ['--incremental', '--ignore-missing-imports'] + [str(proj_root / dirname) for dirname -- in test_modules] -+ args = [ -+ '--incremental', -+ '--ignore-missing-imports', -+ f'--python-version={sys.version_info.major}.{sys.version_info.minor}' -+ ] + [str(proj_root / dirname) for dirname in test_modules] - - result = mypy.api.run(args) - diff -Nru python-rsa-4.7.2/debian/patches/series python-rsa-4.8/debian/patches/series --- python-rsa-4.7.2/debian/patches/series 2021-09-26 06:18:08.000000000 +0000 +++ python-rsa-4.8/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -0001-Fix-test-failure.patch diff -Nru python-rsa-4.7.2/fileexample.py python-rsa-4.8/fileexample.py --- python-rsa-4.7.2/fileexample.py 2021-01-10 11:08:39.000000000 +0000 +++ python-rsa-4.8/fileexample.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -import rsa - -pubkey, privkey = rsa.newkeys(512) - -with open('bothkeys.pem', 'wb') as pemfile: - pemfile.write(pubkey.save_pkcs1()) - pemfile.write(privkey.save_pkcs1()) diff -Nru python-rsa-4.7.2/MANIFEST.in python-rsa-4.8/MANIFEST.in --- python-rsa-4.7.2/MANIFEST.in 2018-09-16 11:47:18.000000000 +0000 +++ python-rsa-4.8/MANIFEST.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -include README.md -include CHANGELOG.txt -include LICENSE -include *.py -recursive-include rsa *.py -recursive-include tests *.py *.pem diff -Nru python-rsa-4.7.2/PKG-INFO python-rsa-4.8/PKG-INFO --- python-rsa-4.7.2/PKG-INFO 2021-02-24 10:54:39.757972000 +0000 +++ python-rsa-4.8/PKG-INFO 2021-11-24 10:08:59.662871800 +0000 @@ -1,69 +1,12 @@ Metadata-Version: 2.1 Name: rsa -Version: 4.7.2 +Version: 4.8 Summary: Pure-Python RSA implementation Home-page: https://stuvel.eu/rsa -Author: Sybren A. Stuvel +License: Apache-2.0 +Author: Sybren A. Stüvel Author-email: sybren@stuvel.eu -Maintainer: Sybren A. Stuvel -Maintainer-email: sybren@stuvel.eu -License: ASL 2 -Description: Pure Python RSA implementation - ============================== - - [![PyPI](https://img.shields.io/pypi/v/rsa.svg)](https://pypi.org/project/rsa/) - [![Build Status](https://travis-ci.org/sybrenstuvel/python-rsa.svg?branch=master)](https://travis-ci.org/sybrenstuvel/python-rsa) - [![Coverage Status](https://coveralls.io/repos/github/sybrenstuvel/python-rsa/badge.svg?branch=master)](https://coveralls.io/github/sybrenstuvel/python-rsa?branch=master) - [![Code Climate](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/codeclimate/codeclimate/maintainability) - - [Python-RSA](https://stuvel.eu/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. It can be used as a Python - library as well as on the commandline. The code was mostly written by - Sybren A. Stüvel. - - Documentation can be found at the [Python-RSA homepage](https://stuvel.eu/rsa). For all changes, check [the changelog](https://github.com/sybrenstuvel/python-rsa/blob/master/CHANGELOG.md). - - Download and install using: - - pip install rsa - - or download it from the [Python Package Index](https://pypi.org/project/rsa/). - - The source code is maintained at [GitHub](https://github.com/sybrenstuvel/python-rsa/) and is - licensed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0) - - Security - -------- - - Because of how Python internally stores numbers, it is very hard (if not impossible) to make a pure-Python program secure against timing attacks. This library is no exception, so use it with care. See https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/ for more info. - - - Major changes in 4.1 - -------------------- - - Version 4.0 was the last version to support Python 2 and 3.4. Version 4.1 is compatible with Python 3.5+ only. - - - Major changes in 4.0 - -------------------- - - Version 3.4 was the last version in the 3.x range. Version 4.0 drops the following modules, - as they are insecure: - - - `rsa._version133` - - `rsa._version200` - - `rsa.bigfile` - - `rsa.varblock` - - Those modules were marked as deprecated in version 3.4. - - Furthermore, in 4.0 the I/O functions is streamlined to always work with bytes on all - supported versions of Python. - - Version 4.0 drops support for Python 2.6 and 3.3. - -Platform: UNKNOWN +Requires-Python: >=3.6,<4 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education @@ -72,7 +15,7 @@ Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 @@ -80,5 +23,50 @@ Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Security :: Cryptography -Requires-Python: >=3.5, <4 +Requires-Dist: pyasn1 (>=0.1.3) Description-Content-Type: text/markdown + +# Pure Python RSA implementation + +[![PyPI](https://img.shields.io/pypi/v/rsa.svg)](https://pypi.org/project/rsa/) +[![Build Status](https://travis-ci.org/sybrenstuvel/python-rsa.svg?branch=master)](https://travis-ci.org/sybrenstuvel/python-rsa) +[![Coverage Status](https://coveralls.io/repos/github/sybrenstuvel/python-rsa/badge.svg?branch=master)](https://coveralls.io/github/sybrenstuvel/python-rsa?branch=master) +[![Code Climate](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/codeclimate/codeclimate/maintainability) + +[Python-RSA](https://stuvel.eu/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. It can be used as a Python +library as well as on the commandline. The code was mostly written by +Sybren A. Stüvel. + +Documentation can be found at the [Python-RSA homepage](https://stuvel.eu/rsa). For all changes, check [the changelog](https://github.com/sybrenstuvel/python-rsa/blob/master/CHANGELOG.md). + +Download and install using: + + pip install rsa + +or download it from the [Python Package Index](https://pypi.org/project/rsa/). + +The source code is maintained at [GitHub](https://github.com/sybrenstuvel/python-rsa/) and is +licensed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0) + +## Security + +Because of how Python internally stores numbers, it is very hard (if not impossible) to make a pure-Python program secure against timing attacks. This library is no exception, so use it with care. See https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/ for more info. + +## Setup of Development Environment + +``` +python3 -m venv .venv +. ./.venv/bin/activate +pip install poetry +poetry install +``` + +## Publishing a New Release + +``` +. ./.venv/bin/activate +poetry publish --build +``` + diff -Nru python-rsa-4.7.2/pyproject.toml python-rsa-4.8/pyproject.toml --- python-rsa-4.7.2/pyproject.toml 1970-01-01 00:00:00.000000000 +0000 +++ python-rsa-4.8/pyproject.toml 2021-11-24 10:06:58.596184300 +0000 @@ -0,0 +1,57 @@ +[tool.poetry] +name = "rsa" +version = "4.8" +license = "Apache-2.0" +description = "Pure-Python RSA implementation" +readme = "README.md" +authors = ["Sybren A. Stüvel "] +homepage = "https://stuvel.eu/rsa" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Education", + "Intended Audience :: Information Technology", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Security :: Cryptography", +] +include = [ + "LICENSE", "README.md", "CHANGELOG.md", +] + +[tool.poetry.dependencies] +python = ">=3.6, <4" +pyasn1 = ">=0.1.3" + +[tool.poetry.dev-dependencies] +coveralls = "^3.0.0" +Sphinx = "^3.5.1" +pytest = "^6.2.2" +pytest-cov = "^2.11.1" +tox = "^3.22.0" +mypy = "^0.910" +flake8 = "^3.8.4" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +"pyrsa-priv2pub" = "rsa.util:private_to_public" +"pyrsa-keygen" = "rsa.cli:keygen" +"pyrsa-encrypt" = "rsa.cli:encrypt" +"pyrsa-decrypt" = "rsa.cli:decrypt" +"pyrsa-sign" = "rsa.cli:sign" +"pyrsa-verify" = "rsa.cli:verify" + +[tool.black] +line-length = 100 diff -Nru python-rsa-4.7.2/README.md python-rsa-4.8/README.md --- python-rsa-4.7.2/README.md 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/README.md 2021-06-10 06:38:34.170000000 +0000 @@ -1,5 +1,4 @@ -Pure Python RSA implementation -============================== +# Pure Python RSA implementation [![PyPI](https://img.shields.io/pypi/v/rsa.svg)](https://pypi.org/project/rsa/) [![Build Status](https://travis-ci.org/sybrenstuvel/python-rsa.svg?branch=master)](https://travis-ci.org/sybrenstuvel/python-rsa) @@ -23,32 +22,22 @@ The source code is maintained at [GitHub](https://github.com/sybrenstuvel/python-rsa/) and is licensed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -Security --------- +## Security Because of how Python internally stores numbers, it is very hard (if not impossible) to make a pure-Python program secure against timing attacks. This library is no exception, so use it with care. See https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/ for more info. +## Setup of Development Environment -Major changes in 4.1 --------------------- - -Version 4.0 was the last version to support Python 2 and 3.4. Version 4.1 is compatible with Python 3.5+ only. - - -Major changes in 4.0 --------------------- - -Version 3.4 was the last version in the 3.x range. Version 4.0 drops the following modules, -as they are insecure: - -- `rsa._version133` -- `rsa._version200` -- `rsa.bigfile` -- `rsa.varblock` - -Those modules were marked as deprecated in version 3.4. - -Furthermore, in 4.0 the I/O functions is streamlined to always work with bytes on all -supported versions of Python. - -Version 4.0 drops support for Python 2.6 and 3.3. +``` +python3 -m venv .venv +. ./.venv/bin/activate +pip install poetry +poetry install +``` + +## Publishing a New Release + +``` +. ./.venv/bin/activate +poetry publish --build +``` diff -Nru python-rsa-4.7.2/rsa/asn1.py python-rsa-4.8/rsa/asn1.py --- python-rsa-4.7.2/rsa/asn1.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/asn1.py 2021-06-10 06:38:34.170000000 +0000 @@ -22,18 +22,19 @@ class PubKeyHeader(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('oid', univ.ObjectIdentifier()), - namedtype.NamedType('parameters', univ.Null()), + namedtype.NamedType("oid", univ.ObjectIdentifier()), + namedtype.NamedType("parameters", univ.Null()), ) class OpenSSLPubKey(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('header', PubKeyHeader()), - - # This little hack (the implicit tag) allows us to get a Bit String as Octet String - namedtype.NamedType('key', univ.OctetString().subtype( - implicitTag=tag.Tag(tagClass=0, tagFormat=0, tagId=3))), + namedtype.NamedType("header", PubKeyHeader()), + # This little hack (the implicit tag) allows us to get a Bit String as Octet String + namedtype.NamedType( + "key", + univ.OctetString().subtype(implicitTag=tag.Tag(tagClass=0, tagFormat=0, tagId=3)), + ), ) @@ -46,6 +47,6 @@ """ componentType = namedtype.NamedTypes( - namedtype.NamedType('modulus', univ.Integer()), - namedtype.NamedType('publicExponent', univ.Integer()), + namedtype.NamedType("modulus", univ.Integer()), + namedtype.NamedType("publicExponent", univ.Integer()), ) diff -Nru python-rsa-4.7.2/rsa/cli.py python-rsa-4.8/rsa/cli.py --- python-rsa-4.7.2/rsa/cli.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/cli.py 2021-11-24 09:29:15.857291700 +0000 @@ -34,21 +34,33 @@ """Key generator.""" # Parse the CLI options - parser = optparse.OptionParser(usage='usage: %prog [options] keysize', - description='Generates a new RSA keypair of "keysize" bits.') - - parser.add_option('--pubout', type='string', - help='Output filename for the public key. The public key is ' - 'not saved if this option is not present. You can use ' - 'pyrsa-priv2pub to create the public key file later.') - - parser.add_option('-o', '--out', type='string', - help='Output filename for the private key. The key is ' - 'written to stdout if this option is not present.') - - parser.add_option('--form', - help='key format of the private and public keys - default PEM', - choices=('PEM', 'DER'), default='PEM') + parser = optparse.OptionParser( + usage="usage: %prog [options] keysize", + description='Generates a new RSA key pair of "keysize" bits.', + ) + + parser.add_option( + "--pubout", + type="string", + help="Output filename for the public key. The public key is " + "not saved if this option is not present. You can use " + "pyrsa-priv2pub to create the public key file later.", + ) + + parser.add_option( + "-o", + "--out", + type="string", + help="Output filename for the private key. The key is " + "written to stdout if this option is not present.", + ) + + parser.add_option( + "--form", + help="key format of the private and public keys - default PEM", + choices=("PEM", "DER"), + default="PEM", + ) (cli, cli_args) = parser.parse_args(sys.argv[1:]) @@ -58,46 +70,47 @@ try: keysize = int(cli_args[0]) - except ValueError: + except ValueError as ex: parser.print_help() - print('Not a valid number: %s' % cli_args[0], file=sys.stderr) - raise SystemExit(1) + print("Not a valid number: %s" % cli_args[0], file=sys.stderr) + raise SystemExit(1) from ex - print('Generating %i-bit key' % keysize, file=sys.stderr) + print("Generating %i-bit key" % keysize, file=sys.stderr) (pub_key, priv_key) = rsa.newkeys(keysize) # Save public key if cli.pubout: - print('Writing public key to %s' % cli.pubout, file=sys.stderr) + print("Writing public key to %s" % cli.pubout, file=sys.stderr) data = pub_key.save_pkcs1(format=cli.form) - with open(cli.pubout, 'wb') as outfile: + with open(cli.pubout, "wb") as outfile: outfile.write(data) # Save private key data = priv_key.save_pkcs1(format=cli.form) if cli.out: - print('Writing private key to %s' % cli.out, file=sys.stderr) - with open(cli.out, 'wb') as outfile: + print("Writing private key to %s" % cli.out, file=sys.stderr) + with open(cli.out, "wb") as outfile: outfile.write(data) else: - print('Writing private key to stdout', file=sys.stderr) + print("Writing private key to stdout", file=sys.stderr) sys.stdout.buffer.write(data) class CryptoOperation(metaclass=abc.ABCMeta): """CLI callable that operates with input, output, and a key.""" - keyname = 'public' # or 'private' - usage = 'usage: %%prog [options] %(keyname)s_key' - description = '' - operation = 'decrypt' - operation_past = 'decrypted' - operation_progressive = 'decrypting' - input_help = 'Name of the file to %(operation)s. Reads from stdin if ' \ - 'not specified.' - output_help = 'Name of the file to write the %(operation_past)s file ' \ - 'to. Written to stdout if this option is not present.' + keyname = "public" # or 'private' + usage = "usage: %%prog [options] %(keyname)s_key" + description = "" + operation = "decrypt" + operation_past = "decrypted" + operation_progressive = "decrypting" + input_help = "Name of the file to %(operation)s. Reads from stdin if " "not specified." + output_help = ( + "Name of the file to write the %(operation_past)s file " + "to. Written to stdout if this option is not present." + ) expected_cli_args = 1 has_output = True @@ -109,8 +122,9 @@ self.output_help = self.output_help % self.__class__.__dict__ @abc.abstractmethod - def perform_operation(self, indata: bytes, key: rsa.key.AbstractKey, - cli_args: Indexable) -> typing.Any: + def perform_operation( + self, indata: bytes, key: rsa.key.AbstractKey, cli_args: Indexable + ) -> typing.Any: """Performs the program's operation. Implement in a subclass. @@ -141,14 +155,17 @@ parser = optparse.OptionParser(usage=self.usage, description=self.description) - parser.add_option('-i', '--input', type='string', help=self.input_help) + parser.add_option("-i", "--input", type="string", help=self.input_help) if self.has_output: - parser.add_option('-o', '--output', type='string', help=self.output_help) + parser.add_option("-o", "--output", type="string", help=self.output_help) - parser.add_option('--keyform', - help='Key format of the %s key - default PEM' % self.keyname, - choices=('PEM', 'DER'), default='PEM') + parser.add_option( + "--keyform", + help="Key format of the %s key - default PEM" % self.keyname, + choices=("PEM", "DER"), + default="PEM", + ) (cli, cli_args) = parser.parse_args(sys.argv[1:]) @@ -161,8 +178,8 @@ def read_key(self, filename: str, keyform: str) -> rsa.key.AbstractKey: """Reads a public or private key.""" - print('Reading %s key from %s' % (self.keyname, filename), file=sys.stderr) - with open(filename, 'rb') as keyfile: + print("Reading %s key from %s" % (self.keyname, filename), file=sys.stderr) + with open(filename, "rb") as keyfile: keydata = keyfile.read() return self.key_class.load_pkcs1(keydata, keyform) @@ -171,37 +188,39 @@ """Read the input file""" if inname: - print('Reading input from %s' % inname, file=sys.stderr) - with open(inname, 'rb') as infile: + print("Reading input from %s" % inname, file=sys.stderr) + with open(inname, "rb") as infile: return infile.read() - print('Reading input from stdin', file=sys.stderr) + print("Reading input from stdin", file=sys.stderr) return sys.stdin.buffer.read() def write_outfile(self, outdata: bytes, outname: str) -> None: """Write the output file""" if outname: - print('Writing output to %s' % outname, file=sys.stderr) - with open(outname, 'wb') as outfile: + print("Writing output to %s" % outname, file=sys.stderr) + with open(outname, "wb") as outfile: outfile.write(outdata) else: - print('Writing output to stdout', file=sys.stderr) + print("Writing output to stdout", file=sys.stderr) sys.stdout.buffer.write(outdata) class EncryptOperation(CryptoOperation): """Encrypts a file.""" - keyname = 'public' - description = ('Encrypts a file. The file must be shorter than the key ' - 'length in order to be encrypted.') - operation = 'encrypt' - operation_past = 'encrypted' - operation_progressive = 'encrypting' - - def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, - cli_args: Indexable = ()) -> bytes: + keyname = "public" + description = ( + "Encrypts a file. The file must be shorter than the key " "length in order to be encrypted." + ) + operation = "encrypt" + operation_past = "encrypted" + operation_progressive = "encrypting" + + def perform_operation( + self, indata: bytes, pub_key: rsa.key.AbstractKey, cli_args: Indexable = () + ) -> bytes: """Encrypts files.""" assert isinstance(pub_key, rsa.key.PublicKey) return rsa.encrypt(indata, pub_key) @@ -210,16 +229,19 @@ class DecryptOperation(CryptoOperation): """Decrypts a file.""" - keyname = 'private' - description = ('Decrypts a file. The original file must be shorter than ' - 'the key length in order to have been encrypted.') - operation = 'decrypt' - operation_past = 'decrypted' - operation_progressive = 'decrypting' + keyname = "private" + description = ( + "Decrypts a file. The original file must be shorter than " + "the key length in order to have been encrypted." + ) + operation = "decrypt" + operation_past = "decrypted" + operation_progressive = "decrypting" key_class = rsa.PrivateKey - def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, - cli_args: Indexable = ()) -> bytes: + def perform_operation( + self, indata: bytes, priv_key: rsa.key.AbstractKey, cli_args: Indexable = () + ) -> bytes: """Decrypts files.""" assert isinstance(priv_key, rsa.key.PrivateKey) return rsa.decrypt(indata, priv_key) @@ -228,28 +250,32 @@ class SignOperation(CryptoOperation): """Signs a file.""" - keyname = 'private' - usage = 'usage: %%prog [options] private_key hash_method' - description = ('Signs a file, outputs the signature. Choose the hash ' - 'method from %s' % ', '.join(HASH_METHODS)) - operation = 'sign' - operation_past = 'signature' - operation_progressive = 'Signing' + keyname = "private" + usage = "usage: %%prog [options] private_key hash_method" + description = ( + "Signs a file, outputs the signature. Choose the hash " + "method from %s" % ", ".join(HASH_METHODS) + ) + operation = "sign" + operation_past = "signature" + operation_progressive = "Signing" key_class = rsa.PrivateKey expected_cli_args = 2 - output_help = ('Name of the file to write the signature to. Written ' - 'to stdout if this option is not present.') - - def perform_operation(self, indata: bytes, priv_key: rsa.key.AbstractKey, - cli_args: Indexable) -> bytes: + output_help = ( + "Name of the file to write the signature to. Written " + "to stdout if this option is not present." + ) + + def perform_operation( + self, indata: bytes, priv_key: rsa.key.AbstractKey, cli_args: Indexable + ) -> bytes: """Signs files.""" assert isinstance(priv_key, rsa.key.PrivateKey) hash_method = cli_args[1] if hash_method not in HASH_METHODS: - raise SystemExit('Invalid hash method, choose one of %s' % - ', '.join(HASH_METHODS)) + raise SystemExit("Invalid hash method, choose one of %s" % ", ".join(HASH_METHODS)) return rsa.sign(indata, priv_key, hash_method) @@ -257,33 +283,36 @@ class VerifyOperation(CryptoOperation): """Verify a signature.""" - keyname = 'public' - usage = 'usage: %%prog [options] public_key signature_file' - description = ('Verifies a signature, exits with status 0 upon success, ' - 'prints an error message and exits with status 1 upon error.') - operation = 'verify' - operation_past = 'verified' - operation_progressive = 'Verifying' + keyname = "public" + usage = "usage: %%prog [options] public_key signature_file" + description = ( + "Verifies a signature, exits with status 0 upon success, " + "prints an error message and exits with status 1 upon error." + ) + operation = "verify" + operation_past = "verified" + operation_progressive = "Verifying" key_class = rsa.PublicKey expected_cli_args = 2 has_output = False - def perform_operation(self, indata: bytes, pub_key: rsa.key.AbstractKey, - cli_args: Indexable) -> None: + def perform_operation( + self, indata: bytes, pub_key: rsa.key.AbstractKey, cli_args: Indexable + ) -> None: """Verifies files.""" assert isinstance(pub_key, rsa.key.PublicKey) signature_file = cli_args[1] - with open(signature_file, 'rb') as sigfile: + with open(signature_file, "rb") as sigfile: signature = sigfile.read() try: rsa.verify(indata, signature, pub_key) - except rsa.VerificationError: - raise SystemExit('Verification failed.') + except rsa.VerificationError as ex: + raise SystemExit("Verification failed.") from ex - print('Verification OK', file=sys.stderr) + print("Verification OK", file=sys.stderr) encrypt = EncryptOperation() diff -Nru python-rsa-4.7.2/rsa/common.py python-rsa-4.8/rsa/common.py --- python-rsa-4.7.2/rsa/common.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/common.py 2021-11-24 09:29:15.857291700 +0000 @@ -18,7 +18,7 @@ class NotRelativePrimeError(ValueError): - def __init__(self, a: int, b: int, d: int, msg: str = '') -> None: + def __init__(self, a: int, b: int, d: int, msg: str = "") -> None: super().__init__(msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d)) self.a = a self.b = b @@ -50,7 +50,7 @@ try: return num.bit_length() except AttributeError as ex: - raise TypeError('bit_size(num) only supports integers, not %r' % type(num)) from ex + raise TypeError("bit_size(num) only supports integers, not %r" % type(num)) from ex def byte_size(number: int) -> int: @@ -103,8 +103,7 @@ def extended_gcd(a: int, b: int) -> typing.Tuple[int, int, int]: - """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb - """ + """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb""" # r = gcd(a,b) i = multiplicitive inverse of a mod b # or j = multiplicitive inverse of b mod a # Neg return values for i or j are made positive mod b or a respectively @@ -121,9 +120,9 @@ (x, lx) = ((lx - (q * x)), x) (y, ly) = ((ly - (q * y)), y) if lx < 0: - lx += ob # If neg wrap modulo orignal b + lx += ob # If neg wrap modulo original b if ly < 0: - ly += oa # If neg wrap modulo orignal a + ly += oa # If neg wrap modulo original a return a, lx, ly # Return only positive values @@ -179,7 +178,7 @@ return x -if __name__ == '__main__': +if __name__ == "__main__": import doctest doctest.testmod() diff -Nru python-rsa-4.7.2/rsa/core.py python-rsa-4.8/rsa/core.py --- python-rsa-4.7.2/rsa/core.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/core.py 2021-06-10 06:38:34.170000000 +0000 @@ -23,18 +23,18 @@ if isinstance(var, int): return - raise TypeError('%s should be an integer, not %s' % (name, var.__class__)) + raise TypeError("%s should be an integer, not %s" % (name, var.__class__)) def encrypt_int(message: int, ekey: int, n: int) -> int: """Encrypts a message using encryption key 'ekey', working modulo n""" - assert_int(message, 'message') - assert_int(ekey, 'ekey') - assert_int(n, 'n') + assert_int(message, "message") + assert_int(ekey, "ekey") + assert_int(n, "n") if message < 0: - raise ValueError('Only non-negative numbers are supported') + raise ValueError("Only non-negative numbers are supported") if message > n: raise OverflowError("The message %i is too long for n=%i" % (message, n)) @@ -45,9 +45,9 @@ def decrypt_int(cyphertext: int, dkey: int, n: int) -> int: """Decrypts a cypher text using the decryption key 'dkey', working modulo n""" - assert_int(cyphertext, 'cyphertext') - assert_int(dkey, 'dkey') - assert_int(n, 'n') + assert_int(cyphertext, "cyphertext") + assert_int(dkey, "dkey") + assert_int(n, "n") message = pow(cyphertext, dkey, n) return message diff -Nru python-rsa-4.7.2/rsa/__init__.py python-rsa-4.8/rsa/__init__.py --- python-rsa-4.7.2/rsa/__init__.py 2021-02-24 10:43:02.000000000 +0000 +++ python-rsa-4.8/rsa/__init__.py 2021-11-24 10:06:58.596184300 +0000 @@ -22,12 +22,21 @@ """ from rsa.key import newkeys, PrivateKey, PublicKey -from rsa.pkcs1 import encrypt, decrypt, sign, verify, DecryptionError, \ - VerificationError, find_signature_hash, sign_hash, compute_hash +from rsa.pkcs1 import ( + encrypt, + decrypt, + sign, + verify, + DecryptionError, + VerificationError, + find_signature_hash, + sign_hash, + compute_hash, +) __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" -__date__ = '2021-02-24' -__version__ = '4.7.2' +__date__ = "2021-11-24" +__version__ = "4.8" # Do doctest if we're run directly if __name__ == "__main__": @@ -35,6 +44,17 @@ doctest.testmod() -__all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify", 'PublicKey', - 'PrivateKey', 'DecryptionError', 'VerificationError', - 'find_signature_hash', 'compute_hash', 'sign_hash'] +__all__ = [ + "newkeys", + "encrypt", + "decrypt", + "sign", + "verify", + "PublicKey", + "PrivateKey", + "DecryptionError", + "VerificationError", + "find_signature_hash", + "compute_hash", + "sign_hash", +] diff -Nru python-rsa-4.7.2/rsa/key.py python-rsa-4.8/rsa/key.py --- python-rsa-4.7.2/rsa/key.py 2021-02-24 10:40:11.000000000 +0000 +++ python-rsa-4.8/rsa/key.py 2021-11-24 09:29:15.857291700 +0000 @@ -50,7 +50,7 @@ class AbstractKey: """Abstract superclass for private and public keys.""" - __slots__ = ('n', 'e', 'blindfac', 'blindfac_inverse', 'mutex') + __slots__ = ("n", "e", "blindfac", "blindfac_inverse", "mutex") def __init__(self, n: int, e: int) -> None: self.n = n @@ -64,7 +64,7 @@ self.mutex = threading.Lock() @classmethod - def _load_pkcs1_pem(cls, keyfile: bytes) -> 'AbstractKey': + def _load_pkcs1_pem(cls, keyfile: bytes) -> "AbstractKey": """Loads a key in PKCS#1 PEM format, implement in a subclass. :param keyfile: contents of a PEM-encoded file that contains @@ -76,7 +76,7 @@ """ @classmethod - def _load_pkcs1_der(cls, keyfile: bytes) -> 'AbstractKey': + def _load_pkcs1_der(cls, keyfile: bytes) -> "AbstractKey": """Loads a key in PKCS#1 PEM format, implement in a subclass. :param keyfile: contents of a DER-encoded file that contains @@ -102,7 +102,7 @@ """ @classmethod - def load_pkcs1(cls, keyfile: bytes, format: str = 'PEM') -> 'AbstractKey': + def load_pkcs1(cls, keyfile: bytes, format: str = "PEM") -> "AbstractKey": """Loads a key in PKCS#1 DER or PEM format. :param keyfile: contents of a DER- or PEM-encoded file that contains @@ -116,27 +116,28 @@ """ methods = { - 'PEM': cls._load_pkcs1_pem, - 'DER': cls._load_pkcs1_der, + "PEM": cls._load_pkcs1_pem, + "DER": cls._load_pkcs1_der, } method = cls._assert_format_exists(format, methods) return method(keyfile) @staticmethod - def _assert_format_exists(file_format: str, methods: typing.Mapping[str, typing.Callable]) \ - -> typing.Callable: - """Checks whether the given file format exists in 'methods'. - """ + def _assert_format_exists( + file_format: str, methods: typing.Mapping[str, typing.Callable] + ) -> typing.Callable: + """Checks whether the given file format exists in 'methods'.""" try: return methods[file_format] - except KeyError: - formats = ', '.join(sorted(methods.keys())) - raise ValueError('Unsupported format: %r, try one of %s' % (file_format, - formats)) + except KeyError as ex: + formats = ", ".join(sorted(methods.keys())) + raise ValueError( + "Unsupported format: %r, try one of %s" % (file_format, formats) + ) from ex - def save_pkcs1(self, format: str = 'PEM') -> bytes: + def save_pkcs1(self, format: str = "PEM") -> bytes: """Saves the key in PKCS#1 DER or PEM format. :param format: the format to save; 'PEM' or 'DER' @@ -146,8 +147,8 @@ """ methods = { - 'PEM': self._save_pkcs1_pem, - 'DER': self._save_pkcs1_der, + "PEM": self._save_pkcs1_pem, + "DER": self._save_pkcs1_der, } method = self._assert_format_exists(format, methods) @@ -186,7 +187,7 @@ blind_r = rsa.randnum.randint(self.n - 1) if rsa.prime.are_relatively_prime(self.n, blind_r): return blind_r - raise RuntimeError('unable to find blinding factor') + raise RuntimeError("unable to find blinding factor") def _update_blinding_factor(self) -> typing.Tuple[int, int]: """Update blinding factors. @@ -212,6 +213,7 @@ return self.blindfac, self.blindfac_inverse + class PublicKey(AbstractKey): """Represents a public RSA key. @@ -236,13 +238,13 @@ """ - __slots__ = ('n', 'e') + __slots__ = ("n", "e") def __getitem__(self, key: str) -> int: return getattr(self, key) def __repr__(self) -> str: - return 'PublicKey(%i, %i)' % (self.n, self.e) + return "PublicKey(%i, %i)" % (self.n, self.e) def __getstate__(self) -> typing.Tuple[int, int]: """Returns the key as tuple for pickling.""" @@ -269,7 +271,7 @@ return hash((self.n, self.e)) @classmethod - def _load_pkcs1_der(cls, keyfile: bytes) -> 'PublicKey': + def _load_pkcs1_der(cls, keyfile: bytes) -> "PublicKey": """Loads a key in PKCS#1 DER format. :param keyfile: contents of a DER-encoded file that contains the public @@ -293,7 +295,7 @@ from rsa.asn1 import AsnPubKey (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey()) - return cls(n=int(priv['modulus']), e=int(priv['publicExponent'])) + return cls(n=int(priv["modulus"]), e=int(priv["publicExponent"])) def _save_pkcs1_der(self) -> bytes: """Saves the public key in PKCS#1 DER format. @@ -307,13 +309,13 @@ # Create the ASN object asn_key = AsnPubKey() - asn_key.setComponentByName('modulus', self.n) - asn_key.setComponentByName('publicExponent', self.e) + asn_key.setComponentByName("modulus", self.n) + asn_key.setComponentByName("publicExponent", self.e) return encoder.encode(asn_key) @classmethod - def _load_pkcs1_pem(cls, keyfile: bytes) -> 'PublicKey': + def _load_pkcs1_pem(cls, keyfile: bytes) -> "PublicKey": """Loads a PKCS#1 PEM-encoded public key file. The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and @@ -324,7 +326,7 @@ :return: a PublicKey object """ - der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY') + der = rsa.pem.load_pem(keyfile, "RSA PUBLIC KEY") return cls._load_pkcs1_der(der) def _save_pkcs1_pem(self) -> bytes: @@ -335,10 +337,10 @@ """ der = self._save_pkcs1_der() - return rsa.pem.save_pem(der, 'RSA PUBLIC KEY') + return rsa.pem.save_pem(der, "RSA PUBLIC KEY") @classmethod - def load_pkcs1_openssl_pem(cls, keyfile: bytes) -> 'PublicKey': + def load_pkcs1_openssl_pem(cls, keyfile: bytes) -> "PublicKey": """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL. These files can be recognised in that they start with BEGIN PUBLIC KEY @@ -353,11 +355,11 @@ :return: a PublicKey object """ - der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY') + der = rsa.pem.load_pem(keyfile, "PUBLIC KEY") return cls.load_pkcs1_openssl_der(der) @classmethod - def load_pkcs1_openssl_der(cls, keyfile: bytes) -> 'PublicKey': + def load_pkcs1_openssl_der(cls, keyfile: bytes) -> "PublicKey": """Loads a PKCS#1 DER-encoded public key file from OpenSSL. :param keyfile: contents of a DER-encoded file that contains the public @@ -371,10 +373,10 @@ (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey()) - if keyinfo['header']['oid'] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'): + if keyinfo["header"]["oid"] != univ.ObjectIdentifier("1.2.840.113549.1.1.1"): raise TypeError("This is not a DER-encoded OpenSSL-compatible public key") - return cls._load_pkcs1_der(keyinfo['key'][1:]) + return cls._load_pkcs1_der(keyinfo["key"][1:]) class PrivateKey(AbstractKey): @@ -401,7 +403,7 @@ """ - __slots__ = ('n', 'e', 'd', 'p', 'q', 'exp1', 'exp2', 'coef') + __slots__ = ("n", "e", "d", "p", "q", "exp1", "exp2", "coef") def __init__(self, n: int, e: int, d: int, p: int, q: int) -> None: AbstractKey.__init__(self, n, e) @@ -418,7 +420,13 @@ return getattr(self, key) def __repr__(self) -> str: - return 'PrivateKey(%i, %i, %i, %i, %i)' % (self.n, self.e, self.d, self.p, self.q) + return "PrivateKey(%i, %i, %i, %i, %i)" % ( + self.n, + self.e, + self.d, + self.p, + self.q, + ) def __getstate__(self) -> typing.Tuple[int, int, int, int, int, int, int, int]: """Returns the key as tuple for pickling.""" @@ -436,14 +444,16 @@ if not isinstance(other, PrivateKey): return False - return (self.n == other.n and - self.e == other.e and - self.d == other.d and - self.p == other.p and - self.q == other.q and - self.exp1 == other.exp1 and - self.exp2 == other.exp2 and - self.coef == other.coef) + return ( + self.n == other.n + and self.e == other.e + and self.d == other.d + and self.p == other.p + and self.q == other.q + and self.exp1 == other.exp1 + and self.exp2 == other.exp2 + and self.coef == other.coef + ) def __ne__(self, other: typing.Any) -> bool: return not (self == other) @@ -463,7 +473,16 @@ # Blinding and un-blinding should be using the same factor blinded, blindfac_inverse = self.blind(encrypted) - decrypted = rsa.core.decrypt_int(blinded, self.d, self.n) + + # Instead of using the core functionality, use the Chinese Remainder + # Theorem and be 2-4x faster. This the same as: + # + # decrypted = rsa.core.decrypt_int(blinded, self.d, self.n) + s1 = pow(blinded, self.exp1, self.p) + s2 = pow(blinded, self.exp2, self.q) + h = ((s1 - s2) * self.coef) % self.p + decrypted = s2 + self.q * h + return self.unblind(decrypted, blindfac_inverse) def blinded_encrypt(self, message: int) -> int: @@ -481,7 +500,7 @@ return self.unblind(encrypted, blindfac_inverse) @classmethod - def _load_pkcs1_der(cls, keyfile: bytes) -> 'PrivateKey': + def _load_pkcs1_der(cls, keyfile: bytes) -> "PrivateKey": """Loads a key in PKCS#1 DER format. :param keyfile: contents of a DER-encoded file that contains the private @@ -503,6 +522,7 @@ """ from pyasn1.codec.der import decoder + (priv, _) = decoder.decode(keyfile) # ASN.1 contents of DER encoded private key: @@ -521,7 +541,7 @@ # } if priv[0] != 0: - raise ValueError('Unable to read this file, version %s != 0' % priv[0]) + raise ValueError("Unable to read this file, version %s != 0" % priv[0]) as_ints = map(int, priv[1:6]) key = cls(*as_ints) @@ -530,9 +550,9 @@ if (key.exp1, key.exp2, key.coef) != (exp1, exp2, coef): warnings.warn( - 'You have provided a malformed keyfile. Either the exponents ' - 'or the coefficient are incorrect. Using the correct values ' - 'instead.', + "You have provided a malformed keyfile. Either the exponents " + "or the coefficient are incorrect. Using the correct values " + "instead.", UserWarning, ) @@ -550,33 +570,33 @@ class AsnPrivKey(univ.Sequence): componentType = namedtype.NamedTypes( - namedtype.NamedType('version', univ.Integer()), - namedtype.NamedType('modulus', univ.Integer()), - namedtype.NamedType('publicExponent', univ.Integer()), - namedtype.NamedType('privateExponent', univ.Integer()), - namedtype.NamedType('prime1', univ.Integer()), - namedtype.NamedType('prime2', univ.Integer()), - namedtype.NamedType('exponent1', univ.Integer()), - namedtype.NamedType('exponent2', univ.Integer()), - namedtype.NamedType('coefficient', univ.Integer()), + namedtype.NamedType("version", univ.Integer()), + namedtype.NamedType("modulus", univ.Integer()), + namedtype.NamedType("publicExponent", univ.Integer()), + namedtype.NamedType("privateExponent", univ.Integer()), + namedtype.NamedType("prime1", univ.Integer()), + namedtype.NamedType("prime2", univ.Integer()), + namedtype.NamedType("exponent1", univ.Integer()), + namedtype.NamedType("exponent2", univ.Integer()), + namedtype.NamedType("coefficient", univ.Integer()), ) # Create the ASN object asn_key = AsnPrivKey() - asn_key.setComponentByName('version', 0) - asn_key.setComponentByName('modulus', self.n) - asn_key.setComponentByName('publicExponent', self.e) - asn_key.setComponentByName('privateExponent', self.d) - asn_key.setComponentByName('prime1', self.p) - asn_key.setComponentByName('prime2', self.q) - asn_key.setComponentByName('exponent1', self.exp1) - asn_key.setComponentByName('exponent2', self.exp2) - asn_key.setComponentByName('coefficient', self.coef) + asn_key.setComponentByName("version", 0) + asn_key.setComponentByName("modulus", self.n) + asn_key.setComponentByName("publicExponent", self.e) + asn_key.setComponentByName("privateExponent", self.d) + asn_key.setComponentByName("prime1", self.p) + asn_key.setComponentByName("prime2", self.q) + asn_key.setComponentByName("exponent1", self.exp1) + asn_key.setComponentByName("exponent2", self.exp2) + asn_key.setComponentByName("coefficient", self.coef) return encoder.encode(asn_key) @classmethod - def _load_pkcs1_pem(cls, keyfile: bytes) -> 'PrivateKey': + def _load_pkcs1_pem(cls, keyfile: bytes) -> "PrivateKey": """Loads a PKCS#1 PEM-encoded private key file. The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and @@ -588,7 +608,7 @@ :return: a PrivateKey object """ - der = rsa.pem.load_pem(keyfile, b'RSA PRIVATE KEY') + der = rsa.pem.load_pem(keyfile, b"RSA PRIVATE KEY") return cls._load_pkcs1_der(der) def _save_pkcs1_pem(self) -> bytes: @@ -599,15 +619,17 @@ """ der = self._save_pkcs1_der() - return rsa.pem.save_pem(der, b'RSA PRIVATE KEY') + return rsa.pem.save_pem(der, b"RSA PRIVATE KEY") -def find_p_q(nbits: int, - getprime_func: typing.Callable[[int], int] = rsa.prime.getprime, - accurate: bool = True) -> typing.Tuple[int, int]: +def find_p_q( + nbits: int, + getprime_func: typing.Callable[[int], int] = rsa.prime.getprime, + accurate: bool = True, +) -> typing.Tuple[int, int]: """Returns a tuple of two different primes of nbits bits each. - The resulting p * q has exacty 2 * nbits bits, and the returned p and q + The resulting p * q has exactly 2 * nbits bits, and the returned p and q will not be equal. :param nbits: the number of bits in each of p and q. @@ -644,16 +666,16 @@ qbits = nbits - shift # Choose the two initial primes - log.debug('find_p_q(%i): Finding p', nbits) + log.debug("find_p_q(%i): Finding p", nbits) p = getprime_func(pbits) - log.debug('find_p_q(%i): Finding q', nbits) + log.debug("find_p_q(%i): Finding q", nbits) q = getprime_func(qbits) def is_acceptable(p: int, q: int) -> bool: """Returns True iff p and q are acceptable: - - p and q differ - - (p * q) has the right nr of bits (when accurate=True) + - p and q differ + - (p * q) has the right nr of bits (when accurate=True) """ if p == q: @@ -701,13 +723,17 @@ d = rsa.common.inverse(exponent, phi_n) except rsa.common.NotRelativePrimeError as ex: raise rsa.common.NotRelativePrimeError( - exponent, phi_n, ex.d, - msg="e (%d) and phi_n (%d) are not relatively prime (divider=%i)" % - (exponent, phi_n, ex.d)) + exponent, + phi_n, + ex.d, + msg="e (%d) and phi_n (%d) are not relatively prime (divider=%i)" + % (exponent, phi_n, ex.d), + ) from ex if (exponent * d) % phi_n != 1: - raise ValueError("e (%d) and d (%d) are not mult. inv. modulo " - "phi_n (%d)" % (exponent, d, phi_n)) + raise ValueError( + "e (%d) and d (%d) are not mult. inv. modulo " "phi_n (%d)" % (exponent, d, phi_n) + ) return exponent, d @@ -725,10 +751,12 @@ return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT) -def gen_keys(nbits: int, - getprime_func: typing.Callable[[int], int], - accurate: bool = True, - exponent: int = DEFAULT_EXPONENT) -> typing.Tuple[int, int, int, int]: +def gen_keys( + nbits: int, + getprime_func: typing.Callable[[int], int], + accurate: bool = True, + exponent: int = DEFAULT_EXPONENT, +) -> typing.Tuple[int, int, int, int]: """Generate RSA keys of nbits bits. Returns (p, q, e, d). Note: this can take a long time, depending on the key size. @@ -756,10 +784,12 @@ return p, q, e, d -def newkeys(nbits: int, - accurate: bool = True, - poolsize: int = 1, - exponent: int = DEFAULT_EXPONENT) -> typing.Tuple[PublicKey, PrivateKey]: +def newkeys( + nbits: int, + accurate: bool = True, + poolsize: int = 1, + exponent: int = DEFAULT_EXPONENT, +) -> typing.Tuple[PublicKey, PrivateKey]: """Generates public and private keys, and returns them as (pub, priv). The public key is also known as the 'encryption key', and is a @@ -786,10 +816,10 @@ """ if nbits < 16: - raise ValueError('Key too small') + raise ValueError("Key too small") if poolsize < 1: - raise ValueError('Pool size (%i) should be >= 1' % poolsize) + raise ValueError("Pool size (%i) should be >= 1" % poolsize) # Determine which getprime function to use if poolsize > 1: @@ -797,6 +827,7 @@ def getprime_func(nbits: int) -> int: return parallel.getprime(nbits, poolsize=poolsize) + else: getprime_func = rsa.prime.getprime @@ -806,15 +837,12 @@ # Create the key objects n = p * q - return ( - PublicKey(n, e), - PrivateKey(n, e, d, p, q) - ) + return (PublicKey(n, e), PrivateKey(n, e, d, p, q)) -__all__ = ['PublicKey', 'PrivateKey', 'newkeys'] +__all__ = ["PublicKey", "PrivateKey", "newkeys"] -if __name__ == '__main__': +if __name__ == "__main__": import doctest try: @@ -824,8 +852,8 @@ break if (count % 10 == 0 and count) or count == 1: - print('%i times' % count) + print("%i times" % count) except KeyboardInterrupt: - print('Aborted') + print("Aborted") else: - print('Doctests done') + print("Doctests done") diff -Nru python-rsa-4.7.2/rsa/parallel.py python-rsa-4.8/rsa/parallel.py --- python-rsa-4.7.2/rsa/parallel.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/parallel.py 2021-06-10 06:38:34.170000000 +0000 @@ -62,8 +62,7 @@ # Create processes try: - procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send)) - for _ in range(poolsize)] + procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send)) for _ in range(poolsize)] # Start processes for p in procs: p.start() @@ -80,10 +79,10 @@ return result -__all__ = ['getprime'] +__all__ = ["getprime"] -if __name__ == '__main__': - print('Running doctests 1000x or until failure') +if __name__ == "__main__": + print("Running doctests 1000x or until failure") import doctest for count in range(100): @@ -92,6 +91,6 @@ break if count % 10 == 0 and count: - print('%i times' % count) + print("%i times" % count) - print('Doctests done') + print("Doctests done") diff -Nru python-rsa-4.7.2/rsa/pem.py python-rsa-4.8/rsa/pem.py --- python-rsa-4.7.2/rsa/pem.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/pem.py 2021-06-10 06:38:34.170000000 +0000 @@ -27,10 +27,12 @@ """ if not isinstance(pem_marker, bytes): - pem_marker = pem_marker.encode('ascii') + pem_marker = pem_marker.encode("ascii") - return (b'-----BEGIN ' + pem_marker + b'-----', - b'-----END ' + pem_marker + b'-----') + return ( + b"-----BEGIN " + pem_marker + b"-----", + b"-----END " + pem_marker + b"-----", + ) def _pem_lines(contents: bytes, pem_start: bytes, pem_end: bytes) -> typing.Iterator[bytes]: @@ -65,7 +67,7 @@ break # Load fields - if b':' in line: + if b":" in line: continue yield line @@ -95,13 +97,13 @@ # We want bytes, not text. If it's text, it can be converted to ASCII bytes. if not isinstance(contents, bytes): - contents = contents.encode('ascii') + contents = contents.encode("ascii") (pem_start, pem_end) = _markers(pem_marker) pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)] # Base64-decode the contents - pem = b''.join(pem_lines) + pem = b"".join(pem_lines) return base64.standard_b64decode(pem) @@ -119,14 +121,14 @@ (pem_start, pem_end) = _markers(pem_marker) - b64 = base64.standard_b64encode(contents).replace(b'\n', b'') + b64 = base64.standard_b64encode(contents).replace(b"\n", b"") pem_lines = [pem_start] for block_start in range(0, len(b64), 64): - block = b64[block_start:block_start + 64] + block = b64[block_start : block_start + 64] pem_lines.append(block) pem_lines.append(pem_end) - pem_lines.append(b'') + pem_lines.append(b"") - return b'\n'.join(pem_lines) + return b"\n".join(pem_lines) diff -Nru python-rsa-4.7.2/rsa/pkcs1.py python-rsa-4.8/rsa/pkcs1.py --- python-rsa-4.7.2/rsa/pkcs1.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/pkcs1.py 2021-11-24 09:29:15.857291700 +0000 @@ -34,39 +34,48 @@ from . import common, transform, core, key +if typing.TYPE_CHECKING: + HashType = hashlib._Hash +else: + HashType = typing.Any + # ASN.1 codes that describe the hash algorithm used. HASH_ASN1 = { - 'MD5': b'\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10', - 'SHA-1': b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14', - 'SHA-224': b'\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c', - 'SHA-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20', - 'SHA-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30', - 'SHA-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40', + "MD5": b"\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10", + "SHA-1": b"\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14", + "SHA-224": b"\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c", + "SHA-256": b"\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20", + "SHA-384": b"\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30", + "SHA-512": b"\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40", } -HASH_METHODS = { - 'MD5': hashlib.md5, - 'SHA-1': hashlib.sha1, - 'SHA-224': hashlib.sha224, - 'SHA-256': hashlib.sha256, - 'SHA-384': hashlib.sha384, - 'SHA-512': hashlib.sha512, +HASH_METHODS: typing.Dict[str, typing.Callable[[], HashType]] = { + "MD5": hashlib.md5, + "SHA-1": hashlib.sha1, + "SHA-224": hashlib.sha224, + "SHA-256": hashlib.sha256, + "SHA-384": hashlib.sha384, + "SHA-512": hashlib.sha512, } if sys.version_info >= (3, 6): # Python 3.6 introduced SHA3 support. - HASH_ASN1.update({ - 'SHA3-256': b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20', - 'SHA3-384': b'\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30', - 'SHA3-512': b'\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0a\x05\x00\x04\x40', - }) - - HASH_METHODS.update({ - 'SHA3-256': hashlib.sha3_256, - 'SHA3-384': hashlib.sha3_384, - 'SHA3-512': hashlib.sha3_512, - }) + HASH_ASN1.update( + { + "SHA3-256": b"\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20", + "SHA3-384": b"\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30", + "SHA3-512": b"\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0a\x05\x00\x04\x40", + } + ) + + HASH_METHODS.update( + { + "SHA3-256": hashlib.sha3_256, + "SHA3-384": hashlib.sha3_384, + "SHA3-512": hashlib.sha3_512, + } + ) class CryptoError(Exception): @@ -100,11 +109,13 @@ msglength = len(message) if msglength > max_msglength: - raise OverflowError('%i bytes needed for message, but there is only' - ' space for %i' % (msglength, max_msglength)) + raise OverflowError( + "%i bytes needed for message, but there is only" + " space for %i" % (msglength, max_msglength) + ) # Get random padding - padding = b'' + padding = b"" padding_length = target_length - msglength - 3 # We remove 0-bytes, so we'll end up with less padding than we've asked for, @@ -116,15 +127,12 @@ # after removing the 0-bytes. This increases the chance of getting # enough bytes, especially when needed_bytes is small new_padding = os.urandom(needed_bytes + 5) - new_padding = new_padding.replace(b'\x00', b'') + new_padding = new_padding.replace(b"\x00", b"") padding = padding + new_padding[:needed_bytes] assert len(padding) == padding_length - return b''.join([b'\x00\x02', - padding, - b'\x00', - message]) + return b"".join([b"\x00\x02", padding, b"\x00", message]) def _pad_for_signing(message: bytes, target_length: int) -> bytes: @@ -150,15 +158,14 @@ msglength = len(message) if msglength > max_msglength: - raise OverflowError('%i bytes needed for message, but there is only' - ' space for %i' % (msglength, max_msglength)) + raise OverflowError( + "%i bytes needed for message, but there is only" + " space for %i" % (msglength, max_msglength) + ) padding_length = target_length - msglength - 3 - return b''.join([b'\x00\x01', - padding_length * b'\xff', - b'\x00', - message]) + return b"".join([b"\x00\x01", padding_length * b"\xff", b"\x00", message]) def encrypt(message: bytes, pub_key: key.PublicKey) -> bytes: @@ -254,26 +261,26 @@ # integer). This fixes CVE-2020-13757. if len(crypto) > blocksize: # This is operating on public information, so doesn't need to be constant-time. - raise DecryptionError('Decryption failed') + raise DecryptionError("Decryption failed") # If we can't find the cleartext marker, decryption failed. - cleartext_marker_bad = not compare_digest(cleartext[:2], b'\x00\x02') + cleartext_marker_bad = not compare_digest(cleartext[:2], b"\x00\x02") # Find the 00 separator between the padding and the message - sep_idx = cleartext.find(b'\x00', 2) + sep_idx = cleartext.find(b"\x00", 2) # sep_idx indicates the position of the `\x00` separator that separates the # padding from the actual message. The padding should be at least 8 bytes # long (see https://tools.ietf.org/html/rfc8017#section-7.2.2 step 3), which # means the separator should be at least at index 10 (because of the - # `\x00\x02` marker that preceeds it). + # `\x00\x02` marker that precedes it). sep_idx_bad = sep_idx < 10 anything_bad = cleartext_marker_bad | sep_idx_bad if anything_bad: - raise DecryptionError('Decryption failed') + raise DecryptionError("Decryption failed") - return cleartext[sep_idx + 1:] + return cleartext[sep_idx + 1 :] def sign_hash(hash_value: bytes, priv_key: key.PrivateKey, hash_method: str) -> bytes: @@ -294,7 +301,7 @@ # Get the ASN1 code for this hash method if hash_method not in HASH_ASN1: - raise ValueError('Invalid hash method: %s' % hash_method) + raise ValueError("Invalid hash method: %s" % hash_method) asn1code = HASH_ASN1[hash_method] # Encrypt the hash with the private key @@ -360,11 +367,11 @@ expected = _pad_for_signing(cleartext, keylength) if len(signature) != keylength: - raise VerificationError('Verification failed') + raise VerificationError("Verification failed") # Compare with the signed one if expected != clearsig: - raise VerificationError('Verification failed') + raise VerificationError("Verification failed") return method_name @@ -421,7 +428,7 @@ """ if method_name not in HASH_METHODS: - raise ValueError('Invalid hash method: %s' % method_name) + raise ValueError("Invalid hash method: %s" % method_name) method = HASH_METHODS[method_name] hasher = method() @@ -429,7 +436,7 @@ if isinstance(message, bytes): hasher.update(message) else: - assert hasattr(message, 'read') and hasattr(message.read, '__call__') + assert hasattr(message, "read") and hasattr(message.read, "__call__") # read as 1K blocks for block in yield_fixedblocks(message, 1024): hasher.update(block) @@ -449,14 +456,21 @@ if asn1code in clearsig: return hashname - raise VerificationError('Verification failed') + raise VerificationError("Verification failed") -__all__ = ['encrypt', 'decrypt', 'sign', 'verify', - 'DecryptionError', 'VerificationError', 'CryptoError'] +__all__ = [ + "encrypt", + "decrypt", + "sign", + "verify", + "DecryptionError", + "VerificationError", + "CryptoError", +] -if __name__ == '__main__': - print('Running doctests 1000x or until failure') +if __name__ == "__main__": + print("Running doctests 1000x or until failure") import doctest for count in range(1000): @@ -465,6 +479,6 @@ break if count % 100 == 0 and count: - print('%i times' % count) + print("%i times" % count) - print('Doctests done') + print("Doctests done") diff -Nru python-rsa-4.7.2/rsa/pkcs1_v2.py python-rsa-4.8/rsa/pkcs1_v2.py --- python-rsa-4.7.2/rsa/pkcs1_v2.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/pkcs1_v2.py 2021-06-10 06:38:34.170000000 +0000 @@ -25,7 +25,7 @@ ) -def mgf1(seed: bytes, length: int, hasher: str = 'SHA-1') -> bytes: +def mgf1(seed: bytes, length: int, hasher: str = "SHA-1") -> bytes: """ MGF1 is a Mask Generation Function based on a hash function. @@ -49,15 +49,15 @@ try: hash_length = pkcs1.HASH_METHODS[hasher]().digest_size - except KeyError: + except KeyError as ex: raise ValueError( - 'Invalid `hasher` specified. Please select one of: {hash_list}'.format( - hash_list=', '.join(sorted(pkcs1.HASH_METHODS.keys())) + "Invalid `hasher` specified. Please select one of: {hash_list}".format( + hash_list=", ".join(sorted(pkcs1.HASH_METHODS.keys())) ) - ) + ) from ex # If l > 2^32(hLen), output "mask too long" and stop. - if length > (2**32 * hash_length): + if length > (2 ** 32 * hash_length): raise OverflowError( "Desired length should be at most 2**32 times the hasher's output " "length ({hash_length} for {hasher} function)".format( @@ -69,7 +69,7 @@ # Looping `counter` from 0 to ceil(l / hLen)-1, build `output` based on the # hashes formed by (`seed` + C), being `C` an octet string of length 4 # generated by converting `counter` with the primitive I2OSP - output = b''.join( + output = b"".join( pkcs1.compute_hash( seed + transform.int2bytes(counter, fill_size=4), method_name=hasher, @@ -82,11 +82,11 @@ __all__ = [ - 'mgf1', + "mgf1", ] -if __name__ == '__main__': - print('Running doctests 1000x or until failure') +if __name__ == "__main__": + print("Running doctests 1000x or until failure") import doctest for count in range(1000): @@ -95,6 +95,6 @@ break if count % 100 == 0 and count: - print('%i times' % count) + print("%i times" % count) - print('Doctests done') + print("Doctests done") diff -Nru python-rsa-4.7.2/rsa/prime.py python-rsa-4.8/rsa/prime.py --- python-rsa-4.7.2/rsa/prime.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/prime.py 2021-11-24 09:29:15.857291700 +0000 @@ -21,7 +21,7 @@ import rsa.common import rsa.randnum -__all__ = ['getprime', 'are_relatively_prime'] +__all__ = ["getprime", "are_relatively_prime"] def gcd(p: int, q: int) -> int: @@ -157,7 +157,7 @@ True """ - assert nbits > 3 # the loop wil hang on too small numbers + assert nbits > 3 # the loop will hang on too small numbers while True: integer = rsa.randnum.read_random_odd_int(nbits) @@ -183,8 +183,8 @@ return d == 1 -if __name__ == '__main__': - print('Running doctests 1000x or until failure') +if __name__ == "__main__": + print("Running doctests 1000x or until failure") import doctest for count in range(1000): @@ -193,6 +193,6 @@ break if count % 100 == 0 and count: - print('%i times' % count) + print("%i times" % count) - print('Doctests done') + print("Doctests done") diff -Nru python-rsa-4.7.2/rsa/py.typed python-rsa-4.8/rsa/py.typed --- python-rsa-4.7.2/rsa/py.typed 1970-01-01 00:00:00.000000000 +0000 +++ python-rsa-4.8/rsa/py.typed 2021-06-10 06:38:34.170000000 +0000 @@ -0,0 +1 @@ +# Marker file for PEP 561. The rsa package uses inline types. diff -Nru python-rsa-4.7.2/rsa/randnum.py python-rsa-4.8/rsa/randnum.py --- python-rsa-4.7.2/rsa/randnum.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/randnum.py 2021-06-10 06:38:34.170000000 +0000 @@ -37,15 +37,14 @@ # Add the remaining random bits if rbits > 0: randomvalue = ord(os.urandom(1)) - randomvalue >>= (8 - rbits) + randomvalue >>= 8 - rbits randomdata = struct.pack("B", randomvalue) + randomdata return randomdata def read_random_int(nbits: int) -> int: - """Reads a random integer of approximately nbits bits. - """ + """Reads a random integer of approximately nbits bits.""" randomdata = read_random_bits(nbits) value = transform.bytes2int(randomdata) diff -Nru python-rsa-4.7.2/rsa/transform.py python-rsa-4.8/rsa/transform.py --- python-rsa-4.7.2/rsa/transform.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/transform.py 2021-06-10 06:38:34.170000000 +0000 @@ -31,7 +31,7 @@ 8405007 """ - return int.from_bytes(raw_bytes, 'big', signed=False) + return int.from_bytes(raw_bytes, "big", signed=False) def int2bytes(number: int, fill_size: int = 0) -> bytes: @@ -61,12 +61,12 @@ bytes_required = max(1, math.ceil(number.bit_length() / 8)) if fill_size > 0: - return number.to_bytes(fill_size, 'big') + return number.to_bytes(fill_size, "big") - return number.to_bytes(bytes_required, 'big') + return number.to_bytes(bytes_required, "big") -if __name__ == '__main__': +if __name__ == "__main__": import doctest doctest.testmod() diff -Nru python-rsa-4.7.2/rsa/util.py python-rsa-4.8/rsa/util.py --- python-rsa-4.7.2/rsa/util.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/rsa/util.py 2021-06-10 06:38:34.170000000 +0000 @@ -24,36 +24,57 @@ """Reads a private key and outputs the corresponding public key.""" # Parse the CLI options - parser = OptionParser(usage='usage: %prog [options]', - description='Reads a private key and outputs the ' - 'corresponding public key. Both private and public keys use ' - 'the format described in PKCS#1 v1.5') - - parser.add_option('-i', '--input', dest='infilename', type='string', - help='Input filename. Reads from stdin if not specified') - parser.add_option('-o', '--output', dest='outfilename', type='string', - help='Output filename. Writes to stdout of not specified') - - parser.add_option('--inform', dest='inform', - help='key format of input - default PEM', - choices=('PEM', 'DER'), default='PEM') - - parser.add_option('--outform', dest='outform', - help='key format of output - default PEM', - choices=('PEM', 'DER'), default='PEM') + parser = OptionParser( + usage="usage: %prog [options]", + description="Reads a private key and outputs the " + "corresponding public key. Both private and public keys use " + "the format described in PKCS#1 v1.5", + ) + + parser.add_option( + "-i", + "--input", + dest="infilename", + type="string", + help="Input filename. Reads from stdin if not specified", + ) + parser.add_option( + "-o", + "--output", + dest="outfilename", + type="string", + help="Output filename. Writes to stdout of not specified", + ) + + parser.add_option( + "--inform", + dest="inform", + help="key format of input - default PEM", + choices=("PEM", "DER"), + default="PEM", + ) + + parser.add_option( + "--outform", + dest="outform", + help="key format of output - default PEM", + choices=("PEM", "DER"), + default="PEM", + ) (cli, cli_args) = parser.parse_args(sys.argv) # Read the input data if cli.infilename: - print('Reading private key from %s in %s format' % - (cli.infilename, cli.inform), file=sys.stderr) - with open(cli.infilename, 'rb') as infile: + print( + "Reading private key from %s in %s format" % (cli.infilename, cli.inform), + file=sys.stderr, + ) + with open(cli.infilename, "rb") as infile: in_data = infile.read() else: - print('Reading private key from stdin in %s format' % cli.inform, - file=sys.stderr) - in_data = sys.stdin.read().encode('ascii') + print("Reading private key from stdin in %s format" % cli.inform, file=sys.stderr) + in_data = sys.stdin.read().encode("ascii") assert type(in_data) == bytes, type(in_data) @@ -65,11 +86,12 @@ out_data = pub_key.save_pkcs1(cli.outform) if cli.outfilename: - print('Writing public key to %s in %s format' % - (cli.outfilename, cli.outform), file=sys.stderr) - with open(cli.outfilename, 'wb') as outfile: + print( + "Writing public key to %s in %s format" % (cli.outfilename, cli.outform), + file=sys.stderr, + ) + with open(cli.outfilename, "wb") as outfile: outfile.write(out_data) else: - print('Writing public key to stdout in %s format' % cli.outform, - file=sys.stderr) - sys.stdout.write(out_data.decode('ascii')) + print("Writing public key to stdout in %s format" % cli.outform, file=sys.stderr) + sys.stdout.write(out_data.decode("ascii")) diff -Nru python-rsa-4.7.2/rsa.egg-info/dependency_links.txt python-rsa-4.8/rsa.egg-info/dependency_links.txt --- python-rsa-4.7.2/rsa.egg-info/dependency_links.txt 2021-02-24 10:54:39.000000000 +0000 +++ python-rsa-4.8/rsa.egg-info/dependency_links.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ - diff -Nru python-rsa-4.7.2/rsa.egg-info/entry_points.txt python-rsa-4.8/rsa.egg-info/entry_points.txt --- python-rsa-4.7.2/rsa.egg-info/entry_points.txt 2021-02-24 10:54:39.000000000 +0000 +++ python-rsa-4.8/rsa.egg-info/entry_points.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -[console_scripts] -pyrsa-decrypt = rsa.cli:decrypt -pyrsa-encrypt = rsa.cli:encrypt -pyrsa-keygen = rsa.cli:keygen -pyrsa-priv2pub = rsa.util:private_to_public -pyrsa-sign = rsa.cli:sign -pyrsa-verify = rsa.cli:verify - diff -Nru python-rsa-4.7.2/rsa.egg-info/PKG-INFO python-rsa-4.8/rsa.egg-info/PKG-INFO --- python-rsa-4.7.2/rsa.egg-info/PKG-INFO 2021-02-24 10:54:39.000000000 +0000 +++ python-rsa-4.8/rsa.egg-info/PKG-INFO 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -Metadata-Version: 2.1 -Name: rsa -Version: 4.7.2 -Summary: Pure-Python RSA implementation -Home-page: https://stuvel.eu/rsa -Author: Sybren A. Stuvel -Author-email: sybren@stuvel.eu -Maintainer: Sybren A. Stuvel -Maintainer-email: sybren@stuvel.eu -License: ASL 2 -Description: Pure Python RSA implementation - ============================== - - [![PyPI](https://img.shields.io/pypi/v/rsa.svg)](https://pypi.org/project/rsa/) - [![Build Status](https://travis-ci.org/sybrenstuvel/python-rsa.svg?branch=master)](https://travis-ci.org/sybrenstuvel/python-rsa) - [![Coverage Status](https://coveralls.io/repos/github/sybrenstuvel/python-rsa/badge.svg?branch=master)](https://coveralls.io/github/sybrenstuvel/python-rsa?branch=master) - [![Code Climate](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/codeclimate/codeclimate/maintainability) - - [Python-RSA](https://stuvel.eu/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. It can be used as a Python - library as well as on the commandline. The code was mostly written by - Sybren A. Stüvel. - - Documentation can be found at the [Python-RSA homepage](https://stuvel.eu/rsa). For all changes, check [the changelog](https://github.com/sybrenstuvel/python-rsa/blob/master/CHANGELOG.md). - - Download and install using: - - pip install rsa - - or download it from the [Python Package Index](https://pypi.org/project/rsa/). - - The source code is maintained at [GitHub](https://github.com/sybrenstuvel/python-rsa/) and is - licensed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0) - - Security - -------- - - Because of how Python internally stores numbers, it is very hard (if not impossible) to make a pure-Python program secure against timing attacks. This library is no exception, so use it with care. See https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/ for more info. - - - Major changes in 4.1 - -------------------- - - Version 4.0 was the last version to support Python 2 and 3.4. Version 4.1 is compatible with Python 3.5+ only. - - - Major changes in 4.0 - -------------------- - - Version 3.4 was the last version in the 3.x range. Version 4.0 drops the following modules, - as they are insecure: - - - `rsa._version133` - - `rsa._version200` - - `rsa.bigfile` - - `rsa.varblock` - - Those modules were marked as deprecated in version 3.4. - - Furthermore, in 4.0 the I/O functions is streamlined to always work with bytes on all - supported versions of Python. - - Version 4.0 drops support for Python 2.6 and 3.3. - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Education -Classifier: Intended Audience :: Information Technology -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Security :: Cryptography -Requires-Python: >=3.5, <4 -Description-Content-Type: text/markdown diff -Nru python-rsa-4.7.2/rsa.egg-info/requires.txt python-rsa-4.8/rsa.egg-info/requires.txt --- python-rsa-4.7.2/rsa.egg-info/requires.txt 2021-02-24 10:54:39.000000000 +0000 +++ python-rsa-4.8/rsa.egg-info/requires.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -pyasn1>=0.1.3 diff -Nru python-rsa-4.7.2/rsa.egg-info/SOURCES.txt python-rsa-4.8/rsa.egg-info/SOURCES.txt --- python-rsa-4.7.2/rsa.egg-info/SOURCES.txt 2021-02-24 10:54:39.000000000 +0000 +++ python-rsa-4.8/rsa.egg-info/SOURCES.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -LICENSE -MANIFEST.in -README.md -create_timing_table.py -fileexample.py -setup.cfg -setup.py -rsa/__init__.py -rsa/_compat.py -rsa/asn1.py -rsa/cli.py -rsa/common.py -rsa/core.py -rsa/key.py -rsa/parallel.py -rsa/pem.py -rsa/pkcs1.py -rsa/pkcs1_v2.py -rsa/prime.py -rsa/randnum.py -rsa/transform.py -rsa/util.py -rsa.egg-info/PKG-INFO -rsa.egg-info/SOURCES.txt -rsa.egg-info/dependency_links.txt -rsa.egg-info/entry_points.txt -rsa.egg-info/requires.txt -rsa.egg-info/top_level.txt -tests/__init__.py -tests/private.pem -tests/test_cli.py -tests/test_common.py -tests/test_compat.py -tests/test_integers.py -tests/test_key.py -tests/test_load_save_keys.py -tests/test_mypy.py -tests/test_parallel.py -tests/test_pem.py -tests/test_pkcs1.py -tests/test_pkcs1_v2.py -tests/test_prime.py -tests/test_strings.py -tests/test_transform.py \ No newline at end of file diff -Nru python-rsa-4.7.2/rsa.egg-info/top_level.txt python-rsa-4.8/rsa.egg-info/top_level.txt --- python-rsa-4.7.2/rsa.egg-info/top_level.txt 2021-02-24 10:54:39.000000000 +0000 +++ python-rsa-4.8/rsa.egg-info/top_level.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -rsa diff -Nru python-rsa-4.7.2/setup.cfg python-rsa-4.8/setup.cfg --- python-rsa-4.7.2/setup.cfg 2021-02-24 10:54:39.764981500 +0000 +++ python-rsa-4.8/setup.cfg 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -[metadata] -license_file = LICENSE - -[flake8] -max-line-length = 100 -max-complexity = 10 - -[pep8] -max-line-length = 100 - -[mypy] -python_version = 3.7 -warn_unused_ignores = True -ignore_missing_imports = True -follow_imports = skip -incremental = True - -[egg_info] -tag_build = -tag_date = 0 - diff -Nru python-rsa-4.7.2/setup.py python-rsa-4.8/setup.py --- python-rsa-4.7.2/setup.py 2021-02-24 10:43:02.000000000 +0000 +++ python-rsa-4.8/setup.py 2021-11-24 10:08:59.662432700 +0000 @@ -1,70 +1,39 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# io.open is needed for projects that support Python 2.7. It ensures open() -# defaults to text mode with universal newlines, and accepts an argument to -# specify the text encoding Python 3 only projects can skip this import. -from io import open from setuptools import setup -with open('README.md', encoding='utf-8') as f: - long_description = f.read() +packages = \ +['rsa'] -if __name__ == '__main__': - setup(name='rsa', - version='4.7.2', - description='Pure-Python RSA implementation', - long_description=long_description, - long_description_content_type='text/markdown', - author='Sybren A. Stuvel', - author_email='sybren@stuvel.eu', - maintainer='Sybren A. Stuvel', - maintainer_email='sybren@stuvel.eu', - url='https://stuvel.eu/rsa', - packages=['rsa'], - license='ASL 2', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Education', - 'Intended Audience :: Information Technology', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Security :: Cryptography', - ], - python_requires='>=3.5, <4', - install_requires=[ - 'pyasn1 >= 0.1.3', - ], - entry_points={'console_scripts': [ - 'pyrsa-priv2pub = rsa.util:private_to_public', - 'pyrsa-keygen = rsa.cli:keygen', - 'pyrsa-encrypt = rsa.cli:encrypt', - 'pyrsa-decrypt = rsa.cli:decrypt', - 'pyrsa-sign = rsa.cli:sign', - 'pyrsa-verify = rsa.cli:verify', - ]}, +package_data = \ +{'': ['*']} - ) +install_requires = \ +['pyasn1>=0.1.3'] + +entry_points = \ +{'console_scripts': ['pyrsa-decrypt = rsa.cli:decrypt', + 'pyrsa-encrypt = rsa.cli:encrypt', + 'pyrsa-keygen = rsa.cli:keygen', + 'pyrsa-priv2pub = rsa.util:private_to_public', + 'pyrsa-sign = rsa.cli:sign', + 'pyrsa-verify = rsa.cli:verify']} + +setup_kwargs = { + 'name': 'rsa', + 'version': '4.8', + 'description': 'Pure-Python RSA implementation', + 'long_description': '# Pure Python RSA implementation\n\n[![PyPI](https://img.shields.io/pypi/v/rsa.svg)](https://pypi.org/project/rsa/)\n[![Build Status](https://travis-ci.org/sybrenstuvel/python-rsa.svg?branch=master)](https://travis-ci.org/sybrenstuvel/python-rsa)\n[![Coverage Status](https://coveralls.io/repos/github/sybrenstuvel/python-rsa/badge.svg?branch=master)](https://coveralls.io/github/sybrenstuvel/python-rsa?branch=master)\n[![Code Climate](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/codeclimate/codeclimate/maintainability)\n\n[Python-RSA](https://stuvel.eu/rsa) is a pure-Python RSA implementation. It supports\nencryption and decryption, signing and verifying signatures, and key\ngeneration according to PKCS#1 version 1.5. It can be used as a Python\nlibrary as well as on the commandline. The code was mostly written by\nSybren A. Stüvel.\n\nDocumentation can be found at the [Python-RSA homepage](https://stuvel.eu/rsa). For all changes, check [the changelog](https://github.com/sybrenstuvel/python-rsa/blob/master/CHANGELOG.md).\n\nDownload and install using:\n\n pip install rsa\n\nor download it from the [Python Package Index](https://pypi.org/project/rsa/).\n\nThe source code is maintained at [GitHub](https://github.com/sybrenstuvel/python-rsa/) and is\nlicensed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0)\n\n## Security\n\nBecause of how Python internally stores numbers, it is very hard (if not impossible) to make a pure-Python program secure against timing attacks. This library is no exception, so use it with care. See https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/ for more info.\n\n## Setup of Development Environment\n\n```\npython3 -m venv .venv\n. ./.venv/bin/activate\npip install poetry\npoetry install\n```\n\n## Publishing a New Release\n\n```\n. ./.venv/bin/activate\npoetry publish --build\n```\n', + 'author': 'Sybren A. Stüvel', + 'author_email': 'sybren@stuvel.eu', + 'maintainer': None, + 'maintainer_email': None, + 'url': 'https://stuvel.eu/rsa', + 'packages': packages, + 'package_data': package_data, + 'install_requires': install_requires, + 'entry_points': entry_points, + 'python_requires': '>=3.6,<4', +} + + +setup(**setup_kwargs) diff -Nru python-rsa-4.7.2/tests/private.pem python-rsa-4.8/tests/private.pem --- python-rsa-4.7.2/tests/private.pem 2018-09-16 11:47:18.000000000 +0000 +++ python-rsa-4.8/tests/private.pem 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MGECAQACEQCvWovlXBvfEeOMZPEleO9NAgMBAAECEA20Y+6fDkaWvC24horBzQEC -CQDdS2PAL/tK4QIJAMratZuNnT3tAghs7iNYA0ZrgQIIQQ5nU93U4fkCCHR55el6 -/K+2 ------END RSA PRIVATE KEY----- diff -Nru python-rsa-4.7.2/tests/test_cli.py python-rsa-4.8/tests/test_cli.py --- python-rsa-4.7.2/tests/test_cli.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_cli.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,286 +0,0 @@ -""" -Unit tests for CLI entry points. -""" - -from __future__ import print_function - -import functools -import io -import os -import sys -import typing -import unittest -from contextlib import contextmanager, redirect_stdout, redirect_stderr - -import rsa -import rsa.cli -import rsa.util - - -@contextmanager -def captured_output() -> typing.Generator: - """Captures output to stdout and stderr""" - - # According to mypy, we're not supposed to change buf_out.buffer. - # However, this is just a test, and it works, hence the 'type: ignore'. - buf_out = io.StringIO() - buf_out.buffer = io.BytesIO() # type: ignore - - buf_err = io.StringIO() - buf_err.buffer = io.BytesIO() # type: ignore - - with redirect_stdout(buf_out), redirect_stderr(buf_err): - yield buf_out, buf_err - - -def get_bytes_out(buf) -> bytes: - return buf.buffer.getvalue() - - -@contextmanager -def cli_args(*new_argv): - """Updates sys.argv[1:] for a single test.""" - - old_args = sys.argv[:] - sys.argv[1:] = [str(arg) for arg in new_argv] - - try: - yield - finally: - sys.argv[1:] = old_args - - -def remove_if_exists(fname): - """Removes a file if it exists.""" - - if os.path.exists(fname): - os.unlink(fname) - - -def cleanup_files(*filenames): - """Makes sure the files don't exist when the test runs, and deletes them afterward.""" - - def remove(): - for fname in filenames: - remove_if_exists(fname) - - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - remove() - try: - return func(*args, **kwargs) - finally: - remove() - - return wrapper - - return decorator - - -class AbstractCliTest(unittest.TestCase): - @classmethod - def setUpClass(cls): - # Ensure there is a key to use - cls.pub_key, cls.priv_key = rsa.newkeys(512) - cls.pub_fname = '%s.pub' % cls.__name__ - cls.priv_fname = '%s.key' % cls.__name__ - - with open(cls.pub_fname, 'wb') as outfile: - outfile.write(cls.pub_key.save_pkcs1()) - - with open(cls.priv_fname, 'wb') as outfile: - outfile.write(cls.priv_key.save_pkcs1()) - - @classmethod - def tearDownClass(cls): - if hasattr(cls, 'pub_fname'): - remove_if_exists(cls.pub_fname) - if hasattr(cls, 'priv_fname'): - remove_if_exists(cls.priv_fname) - - def assertExits(self, status_code, func, *args, **kwargs): - try: - func(*args, **kwargs) - except SystemExit as ex: - if status_code == ex.code: - return - self.fail('SystemExit() raised by %r, but exited with code %r, expected %r' % ( - func, ex.code, status_code)) - else: - self.fail('SystemExit() not raised by %r' % func) - - -class KeygenTest(AbstractCliTest): - def test_keygen_no_args(self): - with cli_args(): - self.assertExits(1, rsa.cli.keygen) - - def test_keygen_priv_stdout(self): - with captured_output() as (out, err): - with cli_args(128): - rsa.cli.keygen() - - lines = get_bytes_out(out).splitlines() - self.assertEqual(b'-----BEGIN RSA PRIVATE KEY-----', lines[0]) - self.assertEqual(b'-----END RSA PRIVATE KEY-----', lines[-1]) - - # The key size should be shown on stderr - self.assertTrue('128-bit key' in err.getvalue()) - - @cleanup_files('test_cli_privkey_out.pem') - def test_keygen_priv_out_pem(self): - with captured_output() as (out, err): - with cli_args('--out=test_cli_privkey_out.pem', '--form=PEM', 128): - rsa.cli.keygen() - - # The key size should be shown on stderr - self.assertTrue('128-bit key' in err.getvalue()) - - # The output file should be shown on stderr - self.assertTrue('test_cli_privkey_out.pem' in err.getvalue()) - - # If we can load the file as PEM, it's good enough. - with open('test_cli_privkey_out.pem', 'rb') as pemfile: - rsa.PrivateKey.load_pkcs1(pemfile.read()) - - @cleanup_files('test_cli_privkey_out.der') - def test_keygen_priv_out_der(self): - with captured_output() as (out, err): - with cli_args('--out=test_cli_privkey_out.der', '--form=DER', 128): - rsa.cli.keygen() - - # The key size should be shown on stderr - self.assertTrue('128-bit key' in err.getvalue()) - - # The output file should be shown on stderr - self.assertTrue('test_cli_privkey_out.der' in err.getvalue()) - - # If we can load the file as der, it's good enough. - with open('test_cli_privkey_out.der', 'rb') as derfile: - rsa.PrivateKey.load_pkcs1(derfile.read(), format='DER') - - @cleanup_files('test_cli_privkey_out.pem', 'test_cli_pubkey_out.pem') - def test_keygen_pub_out_pem(self): - with captured_output() as (out, err): - with cli_args('--out=test_cli_privkey_out.pem', - '--pubout=test_cli_pubkey_out.pem', - '--form=PEM', 256): - rsa.cli.keygen() - - # The key size should be shown on stderr - self.assertTrue('256-bit key' in err.getvalue()) - - # The output files should be shown on stderr - self.assertTrue('test_cli_privkey_out.pem' in err.getvalue()) - self.assertTrue('test_cli_pubkey_out.pem' in err.getvalue()) - - # If we can load the file as PEM, it's good enough. - with open('test_cli_pubkey_out.pem', 'rb') as pemfile: - rsa.PublicKey.load_pkcs1(pemfile.read()) - - -class EncryptDecryptTest(AbstractCliTest): - def test_empty_decrypt(self): - with cli_args(): - self.assertExits(1, rsa.cli.decrypt) - - def test_empty_encrypt(self): - with cli_args(): - self.assertExits(1, rsa.cli.encrypt) - - @cleanup_files('encrypted.txt', 'cleartext.txt') - def test_encrypt_decrypt(self): - with open('cleartext.txt', 'wb') as outfile: - outfile.write(b'Hello cleartext RSA users!') - - with cli_args('-i', 'cleartext.txt', '--out=encrypted.txt', self.pub_fname): - with captured_output(): - rsa.cli.encrypt() - - with cli_args('-i', 'encrypted.txt', self.priv_fname): - with captured_output() as (out, err): - rsa.cli.decrypt() - - # We should have the original cleartext on stdout now. - output = get_bytes_out(out) - self.assertEqual(b'Hello cleartext RSA users!', output) - - @cleanup_files('encrypted.txt', 'cleartext.txt') - def test_encrypt_decrypt_unhappy(self): - with open('cleartext.txt', 'wb') as outfile: - outfile.write(b'Hello cleartext RSA users!') - - with cli_args('-i', 'cleartext.txt', '--out=encrypted.txt', self.pub_fname): - with captured_output(): - rsa.cli.encrypt() - - # Change a few bytes in the encrypted stream. - with open('encrypted.txt', 'r+b') as encfile: - encfile.seek(40) - encfile.write(b'hahaha') - - with cli_args('-i', 'encrypted.txt', self.priv_fname): - with captured_output() as (out, err): - self.assertRaises(rsa.DecryptionError, rsa.cli.decrypt) - - -class SignVerifyTest(AbstractCliTest): - def test_empty_verify(self): - with cli_args(): - self.assertExits(1, rsa.cli.verify) - - def test_empty_sign(self): - with cli_args(): - self.assertExits(1, rsa.cli.sign) - - @cleanup_files('signature.txt', 'cleartext.txt') - def test_sign_verify(self): - with open('cleartext.txt', 'wb') as outfile: - outfile.write(b'Hello RSA users!') - - with cli_args('-i', 'cleartext.txt', '--out=signature.txt', self.priv_fname, 'SHA-256'): - with captured_output(): - rsa.cli.sign() - - with cli_args('-i', 'cleartext.txt', self.pub_fname, 'signature.txt'): - with captured_output() as (out, err): - rsa.cli.verify() - - self.assertFalse(b'Verification OK' in get_bytes_out(out)) - - @cleanup_files('signature.txt', 'cleartext.txt') - def test_sign_verify_unhappy(self): - with open('cleartext.txt', 'wb') as outfile: - outfile.write(b'Hello RSA users!') - - with cli_args('-i', 'cleartext.txt', '--out=signature.txt', self.priv_fname, 'SHA-256'): - with captured_output(): - rsa.cli.sign() - - # Change a few bytes in the cleartext file. - with open('cleartext.txt', 'r+b') as encfile: - encfile.seek(6) - encfile.write(b'DSA') - - with cli_args('-i', 'cleartext.txt', self.pub_fname, 'signature.txt'): - with captured_output() as (out, err): - self.assertExits('Verification failed.', rsa.cli.verify) - - -class PrivatePublicTest(AbstractCliTest): - """Test CLI command to convert a private to a public key.""" - - @cleanup_files('test_private_to_public.pem') - def test_private_to_public(self): - - with cli_args('-i', self.priv_fname, '-o', 'test_private_to_public.pem'): - with captured_output(): - rsa.util.private_to_public() - - # Check that the key is indeed valid. - with open('test_private_to_public.pem', 'rb') as pemfile: - key = rsa.PublicKey.load_pkcs1(pemfile.read()) - - self.assertEqual(self.priv_key.n, key.n) - self.assertEqual(self.priv_key.e, key.e) diff -Nru python-rsa-4.7.2/tests/test_common.py python-rsa-4.8/tests/test_common.py --- python-rsa-4.7.2/tests/test_common.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_common.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -#!/usr/bin/env python -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -import struct -from rsa._compat import byte -from rsa.common import byte_size, bit_size, inverse - - -class TestByte(unittest.TestCase): - def test_values(self): - self.assertEqual(byte(0), b'\x00') - self.assertEqual(byte(255), b'\xff') - - def test_struct_error_when_out_of_bounds(self): - self.assertRaises(struct.error, byte, 256) - self.assertRaises(struct.error, byte, -1) - - -class TestByteSize(unittest.TestCase): - def test_values(self): - self.assertEqual(byte_size(1 << 1023), 128) - self.assertEqual(byte_size((1 << 1024) - 1), 128) - self.assertEqual(byte_size(1 << 1024), 129) - self.assertEqual(byte_size(255), 1) - self.assertEqual(byte_size(256), 2) - self.assertEqual(byte_size(0xffff), 2) - self.assertEqual(byte_size(0xffffff), 3) - self.assertEqual(byte_size(0xffffffff), 4) - self.assertEqual(byte_size(0xffffffffff), 5) - self.assertEqual(byte_size(0xffffffffffff), 6) - self.assertEqual(byte_size(0xffffffffffffff), 7) - self.assertEqual(byte_size(0xffffffffffffffff), 8) - - def test_zero(self): - self.assertEqual(byte_size(0), 1) - - def test_bad_type(self): - self.assertRaises(TypeError, byte_size, []) - self.assertRaises(TypeError, byte_size, ()) - self.assertRaises(TypeError, byte_size, dict()) - self.assertRaises(TypeError, byte_size, "") - self.assertRaises(TypeError, byte_size, None) - - -class TestBitSize(unittest.TestCase): - def test_zero(self): - self.assertEqual(bit_size(0), 0) - - def test_values(self): - self.assertEqual(bit_size(1023), 10) - self.assertEqual(bit_size(1024), 11) - self.assertEqual(bit_size(1025), 11) - self.assertEqual(bit_size(1 << 1024), 1025) - self.assertEqual(bit_size((1 << 1024) + 1), 1025) - self.assertEqual(bit_size((1 << 1024) - 1), 1024) - - def test_negative_values(self): - self.assertEqual(bit_size(-1023), 10) - self.assertEqual(bit_size(-1024), 11) - self.assertEqual(bit_size(-1025), 11) - self.assertEqual(bit_size(-1 << 1024), 1025) - self.assertEqual(bit_size(-((1 << 1024) + 1)), 1025) - self.assertEqual(bit_size(-((1 << 1024) - 1)), 1024) - - def test_bad_type(self): - self.assertRaises(TypeError, bit_size, []) - self.assertRaises(TypeError, bit_size, ()) - self.assertRaises(TypeError, bit_size, dict()) - self.assertRaises(TypeError, bit_size, "") - self.assertRaises(TypeError, bit_size, None) - self.assertRaises(TypeError, bit_size, 0.0) - - -class TestInverse(unittest.TestCase): - def test_normal(self): - self.assertEqual(3, inverse(7, 4)) - self.assertEqual(9, inverse(5, 11)) - - def test_not_relprime(self): - self.assertRaises(ValueError, inverse, 4, 8) - self.assertRaises(ValueError, inverse, 25, 5) diff -Nru python-rsa-4.7.2/tests/test_compat.py python-rsa-4.8/tests/test_compat.py --- python-rsa-4.7.2/tests/test_compat.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_compat.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -import struct - -from rsa._compat import byte, xor_bytes - - -class TestByte(unittest.TestCase): - """Tests for single bytes.""" - - def test_byte(self): - for i in range(256): - byt = byte(i) - self.assertIsInstance(byt, bytes) - self.assertEqual(ord(byt), i) - - def test_raises_StructError_on_overflow(self): - self.assertRaises(struct.error, byte, 256) - self.assertRaises(struct.error, byte, -1) - - def test_byte_literal(self): - self.assertIsInstance(b'abc', bytes) - - -class TestBytes(unittest.TestCase): - """Tests for bytes objects.""" - - def setUp(self): - self.b1 = b'\xff\xff\xff\xff' - self.b2 = b'\x00\x00\x00\x00' - self.b3 = b'\xf0\xf0\xf0\xf0' - self.b4 = b'\x4d\x23\xca\xe2' - self.b5 = b'\x9b\x61\x3b\xdc' - self.b6 = b'\xff\xff' - - self.byte_strings = (self.b1, self.b2, self.b3, self.b4, self.b5, self.b6) - - def test_xor_bytes(self): - self.assertEqual(xor_bytes(self.b1, self.b2), b'\xff\xff\xff\xff') - self.assertEqual(xor_bytes(self.b1, self.b3), b'\x0f\x0f\x0f\x0f') - self.assertEqual(xor_bytes(self.b1, self.b4), b'\xb2\xdc\x35\x1d') - self.assertEqual(xor_bytes(self.b1, self.b5), b'\x64\x9e\xc4\x23') - self.assertEqual(xor_bytes(self.b2, self.b3), b'\xf0\xf0\xf0\xf0') - self.assertEqual(xor_bytes(self.b2, self.b4), b'\x4d\x23\xca\xe2') - self.assertEqual(xor_bytes(self.b2, self.b5), b'\x9b\x61\x3b\xdc') - self.assertEqual(xor_bytes(self.b3, self.b4), b'\xbd\xd3\x3a\x12') - self.assertEqual(xor_bytes(self.b3, self.b5), b'\x6b\x91\xcb\x2c') - self.assertEqual(xor_bytes(self.b4, self.b5), b'\xd6\x42\xf1\x3e') - - def test_xor_bytes_length(self): - self.assertEqual(xor_bytes(self.b1, self.b6), b'\x00\x00') - self.assertEqual(xor_bytes(self.b2, self.b6), b'\xff\xff') - self.assertEqual(xor_bytes(self.b3, self.b6), b'\x0f\x0f') - self.assertEqual(xor_bytes(self.b4, self.b6), b'\xb2\xdc') - self.assertEqual(xor_bytes(self.b5, self.b6), b'\x64\x9e') - self.assertEqual(xor_bytes(self.b6, b''), b'') - - def test_xor_bytes_commutative(self): - for first in self.byte_strings: - for second in self.byte_strings: - min_length = min(len(first), len(second)) - result = xor_bytes(first, second) - - self.assertEqual(result, xor_bytes(second, first)) - self.assertEqual(len(result), min_length) diff -Nru python-rsa-4.7.2/tests/test_integers.py python-rsa-4.8/tests/test_integers.py --- python-rsa-4.7.2/tests/test_integers.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_integers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Tests integer operations.""" - -import unittest - -import rsa -import rsa.core - - -class IntegerTest(unittest.TestCase): - def setUp(self): - (self.pub, self.priv) = rsa.newkeys(64) - - def test_enc_dec(self): - message = 42 - print("\tMessage: %d" % message) - - encrypted = rsa.core.encrypt_int(message, self.pub.e, self.pub.n) - print("\tEncrypted: %d" % encrypted) - - decrypted = rsa.core.decrypt_int(encrypted, self.priv.d, self.pub.n) - print("\tDecrypted: %d" % decrypted) - - self.assertEqual(message, decrypted) - - def test_sign_verify(self): - message = 42 - - signed = rsa.core.encrypt_int(message, self.priv.d, self.pub.n) - print("\tSigned: %d" % signed) - - verified = rsa.core.decrypt_int(signed, self.pub.e, self.pub.n) - print("\tVerified: %d" % verified) - - self.assertEqual(message, verified) diff -Nru python-rsa-4.7.2/tests/test_key.py python-rsa-4.8/tests/test_key.py --- python-rsa-4.7.2/tests/test_key.py 2021-02-15 20:41:12.000000000 +0000 +++ python-rsa-4.8/tests/test_key.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -""" -Some tests for the rsa/key.py file. -""" - -import unittest - -import rsa.key -import rsa.core - - -class BlindingTest(unittest.TestCase): - def test_blinding(self): - """Test blinding and unblinding. - - This is basically the doctest of the PrivateKey.blind method, but then - implemented as unittest to allow running on different Python versions. - """ - - pk = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - - message = 12345 - encrypted = rsa.core.encrypt_int(message, pk.e, pk.n) - - blinded_1, unblind_1 = pk.blind(encrypted) # blind before decrypting - decrypted = rsa.core.decrypt_int(blinded_1, pk.d, pk.n) - unblinded_1 = pk.unblind(decrypted, unblind_1) - - self.assertEqual(unblinded_1, message) - - # Re-blinding should use a different blinding factor. - blinded_2, unblind_2 = pk.blind(encrypted) # blind before decrypting - self.assertNotEqual(blinded_1, blinded_2) - - # The unblinding should still work, though. - decrypted = rsa.core.decrypt_int(blinded_2, pk.d, pk.n) - unblinded_2 = pk.unblind(decrypted, unblind_2) - self.assertEqual(unblinded_2, message) - - -class KeyGenTest(unittest.TestCase): - def test_custom_exponent(self): - priv, pub = rsa.key.newkeys(16, exponent=3) - - self.assertEqual(3, priv.e) - self.assertEqual(3, pub.e) - - def test_default_exponent(self): - priv, pub = rsa.key.newkeys(16) - - self.assertEqual(0x10001, priv.e) - self.assertEqual(0x10001, pub.e) - - def test_exponents_coefficient_calculation(self): - pk = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - - self.assertEqual(pk.exp1, 55063) - self.assertEqual(pk.exp2, 10095) - self.assertEqual(pk.coef, 50797) - - def test_custom_getprime_func(self): - # List of primes to test with, in order [p, q, p, q, ....] - # By starting with two of the same primes, we test that this is - # properly rejected. - primes = [64123, 64123, 64123, 50957, 39317, 33107] - - def getprime(_): - return primes.pop(0) - - # This exponent will cause two other primes to be generated. - exponent = 136407 - - (p, q, e, d) = rsa.key.gen_keys( - 64, accurate=False, getprime_func=getprime, exponent=exponent - ) - self.assertEqual(39317, p) - self.assertEqual(33107, q) - - -class HashTest(unittest.TestCase): - """Test hashing of keys""" - - def test_hash_possible(self): - priv, pub = rsa.key.newkeys(16) - - # This raises a TypeError when hashing isn't possible. - hash(priv) - hash(pub) diff -Nru python-rsa-4.7.2/tests/test_load_save_keys.py python-rsa-4.8/tests/test_load_save_keys.py --- python-rsa-4.7.2/tests/test_load_save_keys.py 2021-02-24 10:40:11.000000000 +0000 +++ python-rsa-4.8/tests/test_load_save_keys.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,217 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Unittest for saving and loading keys.""" - -import base64 -import os.path -import pickle -import unittest -import warnings -from unittest import mock - -import rsa.key - -B64PRIV_DER = b'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt' -PRIVATE_DER = base64.standard_b64decode(B64PRIV_DER) - -B64PUB_DER = b'MAwCBQDeKYlRAgMBAAE=' -PUBLIC_DER = base64.standard_b64decode(B64PUB_DER) - -PRIVATE_PEM = b'''\ ------BEGIN CONFUSING STUFF----- -Cruft before the key - ------BEGIN RSA PRIVATE KEY----- -Comment: something blah - -''' + B64PRIV_DER + b''' ------END RSA PRIVATE KEY----- - -Stuff after the key ------END CONFUSING STUFF----- -''' - -CLEAN_PRIVATE_PEM = b'''\ ------BEGIN RSA PRIVATE KEY----- -''' + B64PRIV_DER + b''' ------END RSA PRIVATE KEY----- -''' - -PUBLIC_PEM = b'''\ ------BEGIN CONFUSING STUFF----- -Cruft before the key - ------BEGIN RSA PUBLIC KEY----- -Comment: something blah - -''' + B64PUB_DER + b''' ------END RSA PUBLIC KEY----- - -Stuff after the key ------END CONFUSING STUFF----- -''' - -CLEAN_PUBLIC_PEM = b'''\ ------BEGIN RSA PUBLIC KEY----- -''' + B64PUB_DER + b''' ------END RSA PUBLIC KEY----- -''' - - -class DerTest(unittest.TestCase): - """Test saving and loading DER keys.""" - - def test_load_private_key(self): - """Test loading private DER keys.""" - - key = rsa.key.PrivateKey.load_pkcs1(PRIVATE_DER, 'DER') - expected = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - - self.assertEqual(expected, key) - self.assertEqual(key.exp1, 55063) - self.assertEqual(key.exp2, 10095) - self.assertEqual(key.coef, 50797) - - @mock.patch('pyasn1.codec.der.decoder.decode') - def test_load_malformed_private_key(self, der_decode): - """Test loading malformed private DER keys.""" - - # Decode returns an invalid exp2 value. - der_decode.return_value = ( - [0, 3727264081, 65537, 3349121513, 65063, 57287, 55063, 0, 50797], - 0, - ) - - with warnings.catch_warnings(record=True) as w: - # Always print warnings - warnings.simplefilter('always') - - # Load 3 keys - for _ in range(3): - key = rsa.key.PrivateKey.load_pkcs1(PRIVATE_DER, 'DER') - - # Check that 3 warnings were generated. - self.assertEqual(3, len(w)) - - for warning in w: - self.assertTrue(issubclass(warning.category, UserWarning)) - self.assertIn('malformed', str(warning.message)) - - # Check that we are creating the key with correct values - self.assertEqual(key.exp1, 55063) - self.assertEqual(key.exp2, 10095) - self.assertEqual(key.coef, 50797) - - def test_save_private_key(self): - """Test saving private DER keys.""" - - key = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - der = key.save_pkcs1('DER') - - self.assertIsInstance(der, bytes) - self.assertEqual(PRIVATE_DER, der) - - def test_load_public_key(self): - """Test loading public DER keys.""" - - key = rsa.key.PublicKey.load_pkcs1(PUBLIC_DER, 'DER') - expected = rsa.key.PublicKey(3727264081, 65537) - - self.assertEqual(expected, key) - - def test_save_public_key(self): - """Test saving public DER keys.""" - - key = rsa.key.PublicKey(3727264081, 65537) - der = key.save_pkcs1('DER') - - self.assertIsInstance(der, bytes) - self.assertEqual(PUBLIC_DER, der) - - -class PemTest(unittest.TestCase): - """Test saving and loading PEM keys.""" - - def test_load_private_key(self): - """Test loading private PEM files.""" - - key = rsa.key.PrivateKey.load_pkcs1(PRIVATE_PEM, 'PEM') - expected = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - - self.assertEqual(expected, key) - self.assertEqual(key.exp1, 55063) - self.assertEqual(key.exp2, 10095) - self.assertEqual(key.coef, 50797) - - def test_save_private_key(self): - """Test saving private PEM files.""" - - key = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - pem = key.save_pkcs1('PEM') - - self.assertIsInstance(pem, bytes) - self.assertEqual(CLEAN_PRIVATE_PEM, pem) - - def test_load_public_key(self): - """Test loading public PEM files.""" - - key = rsa.key.PublicKey.load_pkcs1(PUBLIC_PEM, 'PEM') - expected = rsa.key.PublicKey(3727264081, 65537) - - self.assertEqual(expected, key) - - def test_save_public_key(self): - """Test saving public PEM files.""" - - key = rsa.key.PublicKey(3727264081, 65537) - pem = key.save_pkcs1('PEM') - - self.assertIsInstance(pem, bytes) - self.assertEqual(CLEAN_PUBLIC_PEM, pem) - - def test_load_from_disk(self): - """Test loading a PEM file from disk.""" - - fname = os.path.join(os.path.dirname(__file__), 'private.pem') - with open(fname, mode='rb') as privatefile: - keydata = privatefile.read() - privkey = rsa.key.PrivateKey.load_pkcs1(keydata) - - self.assertEqual(15945948582725241569, privkey.p) - self.assertEqual(14617195220284816877, privkey.q) - - -class PickleTest(unittest.TestCase): - """Test saving and loading keys by pickling.""" - - def test_private_key(self): - pk = rsa.key.PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) - - pickled = pickle.dumps(pk) - unpickled = pickle.loads(pickled) - self.assertEqual(pk, unpickled) - - for attr in rsa.key.AbstractKey.__slots__: - self.assertTrue(hasattr(unpickled, attr)) - - def test_public_key(self): - pk = rsa.key.PublicKey(3727264081, 65537) - - pickled = pickle.dumps(pk) - unpickled = pickle.loads(pickled) - - self.assertEqual(pk, unpickled) - for attr in rsa.key.AbstractKey.__slots__: - self.assertTrue(hasattr(unpickled, attr)) diff -Nru python-rsa-4.7.2/tests/test_mypy.py python-rsa-4.8/tests/test_mypy.py --- python-rsa-4.7.2/tests/test_mypy.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_mypy.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -import pathlib -import unittest - -import mypy.api - -test_modules = ['rsa', 'tests'] - - -class MypyRunnerTest(unittest.TestCase): - def test_run_mypy(self): - proj_root = pathlib.Path(__file__).parent.parent - args = ['--incremental', '--ignore-missing-imports'] + [str(proj_root / dirname) for dirname - in test_modules] - - result = mypy.api.run(args) - - stdout, stderr, status = result - - messages = [] - if stderr: - messages.append(stderr) - if stdout: - messages.append(stdout) - if status: - messages.append('Mypy failed with status %d' % status) - if messages and not all('Success' in message for message in messages): - self.fail('\n'.join(['Mypy errors:'] + messages)) diff -Nru python-rsa-4.7.2/tests/test_parallel.py python-rsa-4.8/tests/test_parallel.py --- python-rsa-4.7.2/tests/test_parallel.py 2018-09-16 11:47:18.000000000 +0000 +++ python-rsa-4.8/tests/test_parallel.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -"""Test for multiprocess prime generation.""" - -import unittest - -import rsa.prime -import rsa.parallel -import rsa.common - - -class ParallelTest(unittest.TestCase): - """Tests for multiprocess prime generation.""" - - def test_parallel_primegen(self): - p = rsa.parallel.getprime(1024, 3) - - self.assertFalse(rsa.prime.is_prime(p - 1)) - self.assertTrue(rsa.prime.is_prime(p)) - self.assertFalse(rsa.prime.is_prime(p + 1)) - - self.assertEqual(1024, rsa.common.bit_size(p)) diff -Nru python-rsa-4.7.2/tests/test_pem.py python-rsa-4.8/tests/test_pem.py --- python-rsa-4.7.2/tests/test_pem.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_pem.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -#!/usr/bin/env python -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest - -from rsa.pem import _markers -import rsa.key - -# 512-bit key. Too small for practical purposes, but good enough for testing with. -public_key_pem = ''' ------BEGIN PUBLIC KEY----- -MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKH0aYP9ZFuctlPnXhEyHjgc8ltKKx9M -0c+h4sKMXwjhjbQAZdtWIw8RRghpUJnKj+6bN2XzZDazyULxgPhtax0CAwEAAQ== ------END PUBLIC KEY----- -''' - -private_key_pem = ''' ------BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBAKH0aYP9ZFuctlPnXhEyHjgc8ltKKx9M0c+h4sKMXwjhjbQAZdtW -Iw8RRghpUJnKj+6bN2XzZDazyULxgPhtax0CAwEAAQJADwR36EpNzQTqDzusCFIq -ZS+h9X8aIovgBK3RNhMIGO2ThpsnhiDTcqIvgQ56knbl6B2W4iOl54tJ6CNtf6l6 -zQIhANTaNLFGsJfOvZHcI0WL1r89+1A4JVxR+lpslJJwAvgDAiEAwsjqqZ2wY2F0 -F8p1J98BEbtjU2mEZIVCMn6vQuhWdl8CIDRL4IJl4eGKlB0QP0JJF1wpeGO/R76l -DaPF5cMM7k3NAiEAss28m/ck9BWBfFVdNjx/vsdFZkx2O9AX9EJWoBSnSgECIQCa -+sVQMUVJFGsdE/31C7wCIbE3IpB7ziABZ7mN+V3Dhg== ------END RSA PRIVATE KEY----- -''' - -# Private key components -prime1 = 96275860229939261876671084930484419185939191875438854026071315955024109172739 -prime2 = 88103681619592083641803383393198542599284510949756076218404908654323473741407 - - -class TestMarkers(unittest.TestCase): - def test_values(self): - self.assertEqual(_markers('RSA PRIVATE KEY'), - (b'-----BEGIN RSA PRIVATE KEY-----', - b'-----END RSA PRIVATE KEY-----')) - - -class TestBytesAndStrings(unittest.TestCase): - """Test that we can use PEM in both Unicode strings and bytes.""" - - def test_unicode_public(self): - key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem) - self.assertEqual(prime1 * prime2, key.n) - - def test_bytes_public(self): - key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem.encode('ascii')) - self.assertEqual(prime1 * prime2, key.n) - - def test_unicode_private(self): - key = rsa.key.PrivateKey.load_pkcs1(private_key_pem) - self.assertEqual(prime1 * prime2, key.n) - - def test_bytes_private(self): - key = rsa.key.PrivateKey.load_pkcs1(private_key_pem.encode('ascii')) - self.assertEqual(prime1, key.p) - self.assertEqual(prime2, key.q) - - -class TestByteOutput(unittest.TestCase): - """Tests that PEM and DER are returned as bytes.""" - - def test_bytes_public(self): - key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem) - self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) - self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) - - def test_bytes_private(self): - key = rsa.key.PrivateKey.load_pkcs1(private_key_pem) - self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) - self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) - - -class TestByteInput(unittest.TestCase): - """Tests that PEM and DER can be loaded from bytes.""" - - def test_bytes_public(self): - key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem.encode('ascii')) - self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) - self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) - - def test_bytes_private(self): - key = rsa.key.PrivateKey.load_pkcs1(private_key_pem.encode('ascii')) - self.assertIsInstance(key.save_pkcs1(format='DER'), bytes) - self.assertIsInstance(key.save_pkcs1(format='PEM'), bytes) diff -Nru python-rsa-4.7.2/tests/test_pkcs1.py python-rsa-4.8/tests/test_pkcs1.py --- python-rsa-4.7.2/tests/test_pkcs1.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_pkcs1.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,218 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Tests string operations.""" - -import struct -import sys -import unittest - -import rsa -from rsa import pkcs1 -from rsa._compat import byte - - -class BinaryTest(unittest.TestCase): - def setUp(self): - (self.pub, self.priv) = rsa.newkeys(256) - - def test_enc_dec(self): - message = struct.pack('>IIII', 0, 0, 0, 1) - print("\tMessage: %r" % message) - - encrypted = pkcs1.encrypt(message, self.pub) - print("\tEncrypted: %r" % encrypted) - - decrypted = pkcs1.decrypt(encrypted, self.priv) - print("\tDecrypted: %r" % decrypted) - - self.assertEqual(message, decrypted) - - def test_decoding_failure(self): - message = struct.pack('>IIII', 0, 0, 0, 1) - encrypted = pkcs1.encrypt(message, self.pub) - - # Alter the encrypted stream - a = encrypted[5] - self.assertIsInstance(a, int) - - altered_a = (a + 1) % 256 - encrypted = encrypted[:5] + byte(altered_a) + encrypted[6:] - - self.assertRaises(pkcs1.DecryptionError, pkcs1.decrypt, encrypted, - self.priv) - - def test_randomness(self): - """Encrypting the same message twice should result in different - cryptos. - """ - - message = struct.pack('>IIII', 0, 0, 0, 1) - encrypted1 = pkcs1.encrypt(message, self.pub) - encrypted2 = pkcs1.encrypt(message, self.pub) - - self.assertNotEqual(encrypted1, encrypted2) - - -class ExtraZeroesTest(unittest.TestCase): - def setUp(self): - # Key, cyphertext, and plaintext taken from https://github.com/sybrenstuvel/python-rsa/issues/146 - self.private_key = rsa.PrivateKey.load_pkcs1( - "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAs1EKK81M5kTFtZSuUFnhKy8FS2WNXaWVmi/fGHG4CLw98+Yo\n0nkuUarVwSS0O9pFPcpc3kvPKOe9Tv+6DLS3Qru21aATy2PRqjqJ4CYn71OYtSwM\n/ZfSCKvrjXybzgu+sBmobdtYm+sppbdL+GEHXGd8gdQw8DDCZSR6+dPJFAzLZTCd\nB+Ctwe/RXPF+ewVdfaOGjkZIzDoYDw7n+OHnsYCYozkbTOcWHpjVevipR+IBpGPi\n1rvKgFnlcG6d/tj0hWRl/6cS7RqhjoiNEtxqoJzpXs/Kg8xbCxXbCchkf11STA8u\ndiCjQWuWI8rcDwl69XMmHJjIQAqhKvOOQ8rYTQIDAQABAoIBABpQLQ7qbHtp4h1Y\nORAfcFRW7Q74UvtH/iEHH1TF8zyM6wZsYtcn4y0mxYE3Mp+J0xlTJbeVJkwZXYVH\nL3UH29CWHSlR+TWiazTwrCTRVJDhEoqbcTiRW8fb+o/jljVxMcVDrpyYUHNo2c6w\njBxhmKPtp66hhaDpds1Cwi0A8APZ8Z2W6kya/L/hRBzMgCz7Bon1nYBMak5PQEwV\nF0dF7Wy4vIjvCzO6DSqA415DvJDzUAUucgFudbANNXo4HJwNRnBpymYIh8mHdmNJ\n/MQ0YLSqUWvOB57dh7oWQwe3UsJ37ZUorTugvxh3NJ7Tt5ZqbCQBEECb9ND63gxo\n/a3YR/0CgYEA7BJc834xCi/0YmO5suBinWOQAF7IiRPU+3G9TdhWEkSYquupg9e6\nK9lC5k0iP+t6I69NYF7+6mvXDTmv6Z01o6oV50oXaHeAk74O3UqNCbLe9tybZ/+F\ndkYlwuGSNttMQBzjCiVy0+y0+Wm3rRnFIsAtd0RlZ24aN3bFTWJINIsCgYEAwnQq\nvNmJe9SwtnH5c/yCqPhKv1cF/4jdQZSGI6/p3KYNxlQzkHZ/6uvrU5V27ov6YbX8\nvKlKfO91oJFQxUD6lpTdgAStI3GMiJBJIZNpyZ9EWNSvwUj28H34cySpbZz3s4Xd\nhiJBShgy+fKURvBQwtWmQHZJ3EGrcOI7PcwiyYcCgYEAlql5jSUCY0ALtidzQogW\nJ+B87N+RGHsBuJ/0cxQYinwg+ySAAVbSyF1WZujfbO/5+YBN362A/1dn3lbswCnH\nK/bHF9+fZNqvwprPnceQj5oK1n4g6JSZNsy6GNAhosT+uwQ0misgR8SQE4W25dDG\nkdEYsz+BgCsyrCcu8J5C+tUCgYAFVPQbC4f2ikVyKzvgz0qx4WUDTBqRACq48p6e\n+eLatv7nskVbr7QgN+nS9+Uz80ihR0Ev1yCAvnwmM/XYAskcOea87OPmdeWZlQM8\nVXNwINrZ6LMNBLgorfuTBK1UoRo1pPUHCYdqxbEYI2unak18mikd2WB7Fp3h0YI4\nVpGZnwKBgBxkAYnZv+jGI4MyEKdsQgxvROXXYOJZkWzsKuKxVkVpYP2V4nR2YMOJ\nViJQ8FUEnPq35cMDlUk4SnoqrrHIJNOvcJSCqM+bWHAioAsfByLbUPM8sm3CDdIk\nXVJl32HuKYPJOMIWfc7hIfxLRHnCN+coz2M6tgqMDs0E/OfjuqVZ\n-----END RSA PRIVATE KEY-----", - format='PEM') - self.cyphertext = bytes.fromhex( - "4501b4d669e01b9ef2dc800aa1b06d49196f5a09fe8fbcd037323c60eaf027bfb98432be4e4a26c567ffec718bcbea977dd26812fa071c33808b4d5ebb742d9879806094b6fbeea63d25ea3141733b60e31c6912106e1b758a7fe0014f075193faa8b4622bfd5d3013f0a32190a95de61a3604711bc62945f95a6522bd4dfed0a994ef185b28c281f7b5e4c8ed41176d12d9fc1b837e6a0111d0132d08a6d6f0580de0c9eed8ed105531799482d1e466c68c23b0c222af7fc12ac279bc4ff57e7b4586d209371b38c4c1035edd418dc5f960441cb21ea2bedbfea86de0d7861e81021b650a1de51002c315f1e7c12debe4dcebf790caaa54a2f26b149cf9e77d" - ) - self.plaintext = bytes.fromhex("54657374") - - def test_unmodified(self): - message = rsa.decrypt(self.cyphertext, self.private_key) - self.assertEqual(message, self.plaintext) - - def test_prepend_zeroes(self): - cyphertext = bytes.fromhex("0000") + self.cyphertext - with self.assertRaises(rsa.DecryptionError): - rsa.decrypt(cyphertext, self.private_key) - - def test_append_zeroes(self): - cyphertext = self.cyphertext + bytes.fromhex("0000") - with self.assertRaises(rsa.DecryptionError): - rsa.decrypt(cyphertext, self.private_key) - - -class SignatureTest(unittest.TestCase): - def setUp(self): - (self.pub, self.priv) = rsa.newkeys(512) - - def test_sign_verify(self): - """Test happy flow of sign and verify""" - - message = b'je moeder' - signature = pkcs1.sign(message, self.priv, 'SHA-256') - self.assertEqual('SHA-256', pkcs1.verify(message, signature, self.pub)) - - - @unittest.skipIf(sys.version_info < (3, 6), "SHA3 requires Python 3.6+") - def test_sign_verify_sha3(self): - """Test happy flow of sign and verify with SHA3-256""" - - message = b'je moeder' - signature = pkcs1.sign(message, self.priv, 'SHA3-256') - self.assertEqual('SHA3-256', pkcs1.verify(message, signature, self.pub)) - - def test_find_signature_hash(self): - """Test happy flow of sign and find_signature_hash""" - - message = b'je moeder' - signature = pkcs1.sign(message, self.priv, 'SHA-256') - - self.assertEqual('SHA-256', pkcs1.find_signature_hash(signature, self.pub)) - - def test_alter_message(self): - """Altering the message should let the verification fail.""" - - signature = pkcs1.sign(b'je moeder', self.priv, 'SHA-256') - self.assertRaises(pkcs1.VerificationError, pkcs1.verify, - b'mijn moeder', signature, self.pub) - - def test_sign_different_key(self): - """Signing with another key should let the verification fail.""" - - (otherpub, _) = rsa.newkeys(512) - - message = b'je moeder' - signature = pkcs1.sign(message, self.priv, 'SHA-256') - self.assertRaises(pkcs1.VerificationError, pkcs1.verify, - message, signature, otherpub) - - def test_multiple_signings(self): - """Signing the same message twice should return the same signatures.""" - - message = struct.pack('>IIII', 0, 0, 0, 1) - signature1 = pkcs1.sign(message, self.priv, 'SHA-1') - signature2 = pkcs1.sign(message, self.priv, 'SHA-1') - - self.assertEqual(signature1, signature2) - - def test_split_hash_sign(self): - """Hashing and then signing should match with directly signing the message. """ - - message = b'je moeder' - msg_hash = pkcs1.compute_hash(message, 'SHA-256') - signature1 = pkcs1.sign_hash(msg_hash, self.priv, 'SHA-256') - - # Calculate the signature using the unified method - signature2 = pkcs1.sign(message, self.priv, 'SHA-256') - - self.assertEqual(signature1, signature2) - - def test_hash_sign_verify(self): - """Test happy flow of hash, sign, and verify""" - - message = b'je moeder' - msg_hash = pkcs1.compute_hash(message, 'SHA-224') - signature = pkcs1.sign_hash(msg_hash, self.priv, 'SHA-224') - - self.assertTrue(pkcs1.verify(message, signature, self.pub)) - - def test_prepend_zeroes(self): - """Prepending the signature with zeroes should be detected.""" - - message = b'je moeder' - signature = pkcs1.sign(message, self.priv, 'SHA-256') - signature = bytes.fromhex('0000') + signature - with self.assertRaises(rsa.VerificationError): - pkcs1.verify(message, signature, self.pub) - - def test_apppend_zeroes(self): - """Apppending the signature with zeroes should be detected.""" - - message = b'je moeder' - signature = pkcs1.sign(message, self.priv, 'SHA-256') - signature = signature + bytes.fromhex('0000') - with self.assertRaises(rsa.VerificationError): - pkcs1.verify(message, signature, self.pub) - - -class PaddingSizeTest(unittest.TestCase): - def test_too_little_padding(self): - """Padding less than 8 bytes should be rejected.""" - - # Construct key that will be small enough to need only 7 bytes of padding. - # This key is 168 bit long, and was generated with rsa.newkeys(nbits=168). - self.private_key = rsa.PrivateKey.load_pkcs1(b''' ------BEGIN RSA PRIVATE KEY----- -MHkCAQACFgCIGbbNSkIRLtprxka9NgOf5UxgxCMCAwEAAQIVQqymO0gHubdEVS68 -CdCiWmOJxVfRAgwBQM+e1JJwMKmxSF0CCmya6CFxO8Evdn8CDACMM3AlVC4FhlN8 -3QIKC9cjoam/swMirwIMAR7Br9tdouoH7jAE ------END RSA PRIVATE KEY----- - ''') - self.public_key = rsa.PublicKey(n=self.private_key.n, e=self.private_key.e) - - cyphertext = self.encrypt_with_short_padding(b'op je hoofd') - with self.assertRaises(rsa.DecryptionError): - rsa.decrypt(cyphertext, self.private_key) - - def encrypt_with_short_padding(self, message: bytes) -> bytes: - # This is a copy of rsa.pkcs1.encrypt() adjusted to use the wrong padding length. - keylength = rsa.common.byte_size(self.public_key.n) - - # The word 'padding' has 7 letters, so is one byte short of a valid padding length. - padded = b'\x00\x02padding\x00' + message - - payload = rsa.transform.bytes2int(padded) - encrypted_value = rsa.core.encrypt_int(payload, self.public_key.e, self.public_key.n) - cyphertext = rsa.transform.int2bytes(encrypted_value, keylength) - - return cyphertext diff -Nru python-rsa-4.7.2/tests/test_pkcs1_v2.py python-rsa-4.8/tests/test_pkcs1_v2.py --- python-rsa-4.7.2/tests/test_pkcs1_v2.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_pkcs1_v2.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Tests PKCS #1 version 2 functionality. - -Most of the mocked values come from the test vectors found at: -http://www.itomorrowmag.com/emc-plus/rsa-labs/standards-initiatives/pkcs-rsa-cryptography-standard.htm -""" - -import unittest - -from rsa import pkcs1_v2 - - -class MGFTest(unittest.TestCase): - def test_oaep_int_db_mask(self): - seed = ( - b'\xaa\xfd\x12\xf6\x59\xca\xe6\x34\x89\xb4\x79\xe5\x07\x6d\xde\xc2' - b'\xf0\x6c\xb5\x8f' - ) - db = ( - b'\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90' - b'\xaf\xd8\x07\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xd4\x36\xe9\x95\x69' - b'\xfd\x32\xa7\xc8\xa0\x5b\xbc\x90\xd3\x2c\x49' - ) - masked_db = ( - b'\xdc\xd8\x7d\x5c\x68\xf1\xee\xa8\xf5\x52\x67\xc3\x1b\x2e\x8b\xb4' - b'\x25\x1f\x84\xd7\xe0\xb2\xc0\x46\x26\xf5\xaf\xf9\x3e\xdc\xfb\x25' - b'\xc9\xc2\xb3\xff\x8a\xe1\x0e\x83\x9a\x2d\xdb\x4c\xdc\xfe\x4f\xf4' - b'\x77\x28\xb4\xa1\xb7\xc1\x36\x2b\xaa\xd2\x9a\xb4\x8d\x28\x69\xd5' - b'\x02\x41\x21\x43\x58\x11\x59\x1b\xe3\x92\xf9\x82\xfb\x3e\x87\xd0' - b'\x95\xae\xb4\x04\x48\xdb\x97\x2f\x3a\xc1\x4f\x7b\xc2\x75\x19\x52' - b'\x81\xce\x32\xd2\xf1\xb7\x6d\x4d\x35\x3e\x2d' - ) - - # dbMask = MGF(seed, length(DB)) - db_mask = pkcs1_v2.mgf1(seed, length=len(db)) - expected_db_mask = ( - b'\x06\xe1\xde\xb2\x36\x9a\xa5\xa5\xc7\x07\xd8\x2c\x8e\x4e\x93\x24' - b'\x8a\xc7\x83\xde\xe0\xb2\xc0\x46\x26\xf5\xaf\xf9\x3e\xdc\xfb\x25' - b'\xc9\xc2\xb3\xff\x8a\xe1\x0e\x83\x9a\x2d\xdb\x4c\xdc\xfe\x4f\xf4' - b'\x77\x28\xb4\xa1\xb7\xc1\x36\x2b\xaa\xd2\x9a\xb4\x8d\x28\x69\xd5' - b'\x02\x41\x21\x43\x58\x11\x59\x1b\xe3\x92\xf9\x82\xfb\x3e\x87\xd0' - b'\x95\xae\xb4\x04\x48\xdb\x97\x2f\x3a\xc1\x4e\xaf\xf4\x9c\x8c\x3b' - b'\x7c\xfc\x95\x1a\x51\xec\xd1\xdd\xe6\x12\x64' - ) - - self.assertEqual(db_mask, expected_db_mask) - - # seedMask = MGF(maskedDB, length(seed)) - seed_mask = pkcs1_v2.mgf1(masked_db, length=len(seed)) - expected_seed_mask = ( - b'\x41\x87\x0b\x5a\xb0\x29\xe6\x57\xd9\x57\x50\xb5\x4c\x28\x3c\x08' - b'\x72\x5d\xbe\xa9' - ) - - self.assertEqual(seed_mask, expected_seed_mask) - - def test_invalid_hasher(self): - """Tests an invalid hasher generates an exception""" - with self.assertRaises(ValueError): - pkcs1_v2.mgf1(b'\x06\xe1\xde\xb2', length=8, hasher='SHA2') - - def test_invalid_length(self): - with self.assertRaises(OverflowError): - pkcs1_v2.mgf1(b'\x06\xe1\xde\xb2', length=2**50) diff -Nru python-rsa-4.7.2/tests/test_prime.py python-rsa-4.8/tests/test_prime.py --- python-rsa-4.7.2/tests/test_prime.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_prime.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Tests prime functions.""" - -import unittest - -import rsa.prime -import rsa.randnum - - -class PrimeTest(unittest.TestCase): - def test_is_prime(self): - """Test some common primes.""" - - # Test some trivial numbers - self.assertFalse(rsa.prime.is_prime(-1)) - self.assertFalse(rsa.prime.is_prime(0)) - self.assertFalse(rsa.prime.is_prime(1)) - self.assertTrue(rsa.prime.is_prime(2)) - self.assertFalse(rsa.prime.is_prime(42)) - self.assertTrue(rsa.prime.is_prime(41)) - - # Test some slightly larger numbers - self.assertEqual( - [907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997], - [x for x in range(901, 1000) if rsa.prime.is_prime(x)] - ) - - # Test around the 50th millionth known prime. - self.assertTrue(rsa.prime.is_prime(982451653)) - self.assertFalse(rsa.prime.is_prime(982451653 * 961748941)) - - def test_miller_rabin_primality_testing(self): - """Uses monkeypatching to ensure certain random numbers. - - This allows us to predict/control the code path. - """ - - randints = [] - - def fake_randint(maxvalue): - return randints.pop(0) - - orig_randint = rsa.randnum.randint - rsa.randnum.randint = fake_randint - try: - # 'n is composite' - randints.append(2630484832) # causes the 'n is composite' case with n=3784949785 - self.assertEqual(False, rsa.prime.miller_rabin_primality_testing(2787998641, 7)) - self.assertEqual([], randints) - - # 'Exit inner loop and continue with next witness' - randints.extend([ - 2119139098, # causes 'Exit inner loop and continue with next witness' - # the next witnesses for the above case: - 3051067716, 3603501763, 3230895847, 3687808133, 3760099987, 4026931495, 3022471882, - ]) - self.assertEqual(True, rsa.prime.miller_rabin_primality_testing(2211417913, - len(randints))) - self.assertEqual([], randints) - finally: - rsa.randnum.randint = orig_randint - - def test_mersenne_primes(self): - """Tests first known Mersenne primes. - - Mersenne primes are prime numbers that can be written in the form - `Mn = 2**n - 1` for some integer `n`. For the list of known Mersenne - primes, see: - https://en.wikipedia.org/wiki/Mersenne_prime#List_of_known_Mersenne_primes - """ - - # List of known Mersenne exponents. - known_mersenne_exponents = [ - 2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, - 2203, 2281, 4423, - ] - - # Test Mersenne primes. - for exp in known_mersenne_exponents: - self.assertTrue(rsa.prime.is_prime(2**exp - 1)) - - def test_get_primality_testing_rounds(self): - """Test round calculation for primality testing.""" - - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 63), 10) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 127), 10) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 255), 10) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 511), 7) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 767), 7) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 1023), 4) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 1279), 4) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 1535), 3) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 2047), 3) - self.assertEqual(rsa.prime.get_primality_testing_rounds(1 << 4095), 3) diff -Nru python-rsa-4.7.2/tests/test_strings.py python-rsa-4.8/tests/test_strings.py --- python-rsa-4.7.2/tests/test_strings.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_strings.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Tests string operations.""" - -from __future__ import absolute_import - -import unittest - -import rsa - -unicode_string = u"Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ" - - -class StringTest(unittest.TestCase): - def setUp(self): - (self.pub, self.priv) = rsa.newkeys(384) - - def test_enc_dec(self): - message = unicode_string.encode('utf-8') - print("\tMessage: %r" % message) - - encrypted = rsa.encrypt(message, self.pub) - print("\tEncrypted: %r" % encrypted) - - decrypted = rsa.decrypt(encrypted, self.priv) - print("\tDecrypted: %r" % decrypted) - - self.assertEqual(message, decrypted) diff -Nru python-rsa-4.7.2/tests/test_transform.py python-rsa-4.8/tests/test_transform.py --- python-rsa-4.7.2/tests/test_transform.py 2021-01-10 10:09:07.000000000 +0000 +++ python-rsa-4.8/tests/test_transform.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -# Copyright 2011 Sybren A. Stüvel -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -from rsa.transform import int2bytes, bytes2int - - -class Test_int2bytes(unittest.TestCase): - def test_accuracy(self): - self.assertEqual(int2bytes(123456789), b'\x07[\xcd\x15') - - def test_codec_identity(self): - self.assertEqual(bytes2int(int2bytes(123456789, 128)), 123456789) - - def test_chunk_size(self): - self.assertEqual(int2bytes(123456789, 6), b'\x00\x00\x07[\xcd\x15') - self.assertEqual(int2bytes(123456789, 7), - b'\x00\x00\x00\x07[\xcd\x15') - - def test_zero(self): - self.assertEqual(int2bytes(0, 4), b'\x00' * 4) - self.assertEqual(int2bytes(0, 7), b'\x00' * 7) - self.assertEqual(int2bytes(0), b'\x00') - - def test_correctness_against_base_implementation(self): - # Slow test. - values = [ - 1 << 512, - 1 << 8192, - 1 << 77, - ] - for value in values: - self.assertEqual(bytes2int(int2bytes(value)), - value, - "Boom %d" % value) - - def test_raises_OverflowError_when_chunk_size_is_insufficient(self): - self.assertRaises(OverflowError, int2bytes, 123456789, 3) - self.assertRaises(OverflowError, int2bytes, 299999999999, 4) - - def test_raises_ValueError_when_negative_integer(self): - self.assertRaises(ValueError, int2bytes, -1) - - def test_raises_TypeError_when_not_integer(self): - self.assertRaises(TypeError, int2bytes, None)