aboutsummaryrefslogtreecommitdiffstats
path: root/tests/hazmat/primitives/test_rsa.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/hazmat/primitives/test_rsa.py')
-rw-r--r--tests/hazmat/primitives/test_rsa.py1273
1 files changed, 809 insertions, 464 deletions
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index eb12df8d..e6482651 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -6,12 +6,10 @@ from __future__ import absolute_import, division, print_function
import binascii
import itertools
-import math
import os
import pytest
-from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidSignature, _Reasons
)
@@ -19,38 +17,43 @@ from cryptography.hazmat.backends.interfaces import (
PEMSerializationBackend, RSABackend
)
from cryptography.hazmat.primitives import hashes, serialization
-from cryptography.hazmat.primitives.asymmetric import padding, rsa
+from cryptography.hazmat.primitives.asymmetric import (
+ padding, rsa, utils as asym_utils
+)
from cryptography.hazmat.primitives.asymmetric.rsa import (
RSAPrivateNumbers, RSAPublicNumbers
)
+from cryptography.utils import CryptographyDeprecationWarning
from .fixtures_rsa import (
RSA_KEY_1024, RSA_KEY_1025, RSA_KEY_1026, RSA_KEY_1027, RSA_KEY_1028,
RSA_KEY_1029, RSA_KEY_1030, RSA_KEY_1031, RSA_KEY_1536, RSA_KEY_2048,
- RSA_KEY_512, RSA_KEY_512_ALT, RSA_KEY_522, RSA_KEY_599, RSA_KEY_745,
- RSA_KEY_768,
+ RSA_KEY_2048_ALT, RSA_KEY_512, RSA_KEY_512_ALT, RSA_KEY_522, RSA_KEY_599,
+ RSA_KEY_745, RSA_KEY_768,
)
from .utils import (
_check_rsa_private_numbers, generate_rsa_verification_test
)
+from ...doubles import (
+ DummyAsymmetricPadding, DummyHashAlgorithm, DummyKeySerializationEncryption
+)
from ...utils import (
- load_pkcs1_vectors, load_rsa_nist_vectors, load_vectors_from_file,
- raises_unsupported_algorithm
+ load_nist_vectors, load_pkcs1_vectors, load_rsa_nist_vectors,
+ load_vectors_from_file, raises_unsupported_algorithm
)
-@utils.register_interface(padding.AsymmetricPadding)
-class DummyPadding(object):
- name = "UNSUPPORTED-PADDING"
-
-
class DummyMGF(object):
_salt_length = 0
-@utils.register_interface(serialization.KeySerializationEncryption)
-class DummyKeyEncryption(object):
- pass
+def _check_rsa_private_numbers_if_serializable(key):
+ if isinstance(key, rsa.RSAPrivateKeyWithSerialization):
+ _check_rsa_private_numbers(key.private_numbers())
+
+
+def test_check_rsa_private_numbers_if_serializable():
+ _check_rsa_private_numbers_if_serializable("notserializable")
def _flatten_pkcs1_examples(vectors):
@@ -64,6 +67,60 @@ def _flatten_pkcs1_examples(vectors):
return flattened_vectors
+def _build_oaep_sha2_vectors():
+ base_path = os.path.join("asymmetric", "RSA", "oaep-custom")
+ vectors = []
+ hashalgs = [
+ hashes.SHA1(),
+ hashes.SHA224(),
+ hashes.SHA256(),
+ hashes.SHA384(),
+ hashes.SHA512(),
+ ]
+ for mgf1alg, oaepalg in itertools.product(hashalgs, hashalgs):
+ if mgf1alg.name == "sha1" and oaepalg.name == "sha1":
+ # We need to generate the cartesian product of the permutations
+ # of all the SHAs above, but SHA1/SHA1 is something we already
+ # tested previously and thus did not generate custom vectors for.
+ continue
+
+ examples = _flatten_pkcs1_examples(
+ load_vectors_from_file(
+ os.path.join(
+ base_path,
+ "oaep-{}-{}.txt".format(
+ mgf1alg.name, oaepalg.name
+ )
+ ),
+ load_pkcs1_vectors
+ )
+ )
+ # We've loaded the files, but the loaders don't give us any information
+ # about the mgf1 or oaep hash algorithms. We know this info so we'll
+ # just add that to the end of the tuple
+ for private, public, vector in examples:
+ vectors.append((private, public, vector, mgf1alg, oaepalg))
+ return vectors
+
+
+def _skip_pss_hash_algorithm_unsupported(backend, hash_alg):
+ if not backend.rsa_padding_supported(
+ padding.PSS(
+ mgf=padding.MGF1(hash_alg),
+ salt_length=padding.PSS.MAX_LENGTH
+ )
+ ):
+ pytest.skip(
+ "Does not support {} in MGF1 using PSS.".format(hash_alg.name)
+ )
+
+
+@pytest.mark.requires_backend_interface(interface=RSABackend)
+def test_skip_pss_hash_algorithm_unsupported(backend):
+ with pytest.raises(pytest.skip.Exception):
+ _skip_pss_hash_algorithm_unsupported(backend, DummyHashAlgorithm())
+
+
def test_modular_inverse():
p = int(
"d1f9f6c09fd3d38987f7970247b85a6da84907753d42ec52bc23b745093f4fff5cff3"
@@ -85,21 +142,6 @@ def test_modular_inverse():
)
-def _skip_if_no_serialization(key, backend):
- if not isinstance(
- key,
- (rsa.RSAPrivateKeyWithSerialization, rsa.RSAPublicKeyWithSerialization)
- ):
- pytest.skip(
- "{0} does not support RSA key serialization".format(backend)
- )
-
-
-def test_skip_if_no_serialization():
- with pytest.raises(pytest.skip.Exception):
- _skip_if_no_serialization("notakeywithserialization", "backend")
-
-
@pytest.mark.requires_backend_interface(interface=RSABackend)
class TestRSA(object):
@pytest.mark.parametrize(
@@ -113,10 +155,9 @@ class TestRSA(object):
skey = rsa.generate_private_key(public_exponent, key_size, backend)
assert skey.key_size == key_size
- if isinstance(skey, rsa.RSAPrivateKeyWithSerialization):
- _check_rsa_private_numbers(skey.private_numbers())
- pkey = skey.public_key()
- assert isinstance(pkey.public_numbers(), rsa.RSAPublicNumbers)
+ _check_rsa_private_numbers_if_serializable(skey)
+ pkey = skey.public_key()
+ assert isinstance(pkey.public_numbers(), rsa.RSAPublicNumbers)
def test_generate_bad_public_exponent(self, backend):
with pytest.raises(ValueError):
@@ -177,6 +218,133 @@ class TestRSA(object):
assert public_num.n == public_num2.n
assert public_num.e == public_num2.e
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join("asymmetric", "RSA", "oaep-label.txt"),
+ load_nist_vectors)
+ )
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=b"label"
+ )
+ ),
+ skip_message="Does not support RSA OAEP labels"
+ )
+ def test_oaep_label_decrypt(self, vector, backend):
+ private_key = serialization.load_der_private_key(
+ binascii.unhexlify(vector["key"]), None, backend
+ )
+ assert vector["oaepdigest"] == b"SHA512"
+ decrypted = private_key.decrypt(
+ binascii.unhexlify(vector["input"]),
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA512()),
+ algorithm=hashes.SHA512(),
+ label=binascii.unhexlify(vector["oaeplabel"])
+ )
+ )
+ assert vector["output"][1:-1] == decrypted
+
+ @pytest.mark.parametrize(
+ ("msg", "label"),
+ [
+ (b"amazing encrypted msg", b"some label"),
+ (b"amazing encrypted msg", b""),
+ ]
+ )
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=b"label"
+ )
+ ),
+ skip_message="Does not support RSA OAEP labels"
+ )
+ def test_oaep_label_roundtrip(self, msg, label, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+ ct = private_key.public_key().encrypt(
+ msg,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=label
+ )
+ )
+ pt = private_key.decrypt(
+ ct,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=label
+ )
+ )
+ assert pt == msg
+
+ @pytest.mark.parametrize(
+ ("enclabel", "declabel"),
+ [
+ (b"label1", b"label2"),
+ (b"label3", b""),
+ (b"", b"label4"),
+ ]
+ )
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=b"label"
+ )
+ ),
+ skip_message="Does not support RSA OAEP labels"
+ )
+ def test_oaep_wrong_label(self, enclabel, declabel, backend):
+ private_key = RSA_KEY_2048.private_key(backend)
+ msg = b"test"
+ ct = private_key.public_key().encrypt(
+ msg, padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=enclabel
+ )
+ )
+ with pytest.raises(ValueError):
+ private_key.decrypt(
+ ct, padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=declabel
+ )
+ )
+
+ @pytest.mark.supported(
+ only_if=lambda backend: not backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=b"label"
+ )
+ ),
+ skip_message="Requires backend without RSA OAEP label support"
+ )
+ def test_unsupported_oaep_label_decrypt(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
+ private_key.decrypt(
+ b"0" * 64,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=b"label"
+ )
+ )
+
def test_rsa_generate_invalid_backend():
pretend_backend = object()
@@ -215,9 +383,11 @@ class TestRSASignature(object):
n=private["modulus"]
)
).private_key(backend)
- signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
- signer.update(binascii.unhexlify(example["message"]))
- signature = signer.finalize()
+ signature = private_key.sign(
+ binascii.unhexlify(example["message"]),
+ padding.PKCS1v15(),
+ hashes.SHA1()
+ )
assert binascii.hexlify(signature) == example["signature"]
@pytest.mark.supported(
@@ -255,56 +425,43 @@ class TestRSASignature(object):
e=public["public_exponent"],
n=public["modulus"]
).public_key(backend)
- signer = private_key.signer(
+ signature = private_key.sign(
+ binascii.unhexlify(example["message"]),
padding.PSS(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA1()
)
- signer.update(binascii.unhexlify(example["message"]))
- signature = signer.finalize()
- assert len(signature) == math.ceil(private_key.key_size / 8.0)
+ assert len(signature) == (private_key.key_size + 7) // 8
# PSS signatures contain randomness so we can't do an exact
# signature check. Instead we'll verify that the signature created
# successfully verifies.
- verifier = public_key.verifier(
+ public_key.verify(
signature,
+ binascii.unhexlify(example["message"]),
padding.PSS(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA1(),
)
- verifier.update(binascii.unhexlify(example["message"]))
- verifier.verify()
@pytest.mark.parametrize(
"hash_alg",
[hashes.SHA224(), hashes.SHA256(), hashes.SHA384(), hashes.SHA512()]
)
def test_pss_signing_sha2(self, hash_alg, backend):
- if not backend.rsa_padding_supported(
- padding.PSS(
- mgf=padding.MGF1(hash_alg),
- salt_length=padding.PSS.MAX_LENGTH
- )
- ):
- pytest.skip(
- "Does not support {0} in MGF1 using PSS.".format(hash_alg.name)
- )
+ _skip_pss_hash_algorithm_unsupported(backend, hash_alg)
private_key = RSA_KEY_768.private_key(backend)
public_key = private_key.public_key()
pss = padding.PSS(
mgf=padding.MGF1(hash_alg),
salt_length=padding.PSS.MAX_LENGTH
)
- signer = private_key.signer(pss, hash_alg)
- signer.update(b"testing signature")
- signature = signer.finalize()
- verifier = public_key.verifier(signature, pss, hash_alg)
- verifier.update(b"testing signature")
- verifier.verify()
+ msg = b"testing signature"
+ signature = private_key.sign(msg, pss, hash_alg)
+ public_key.verify(signature, msg, pss, hash_alg)
@pytest.mark.supported(
only_if=lambda backend: (
@@ -320,15 +477,14 @@ class TestRSASignature(object):
)
def test_pss_minimum_key_size_for_digest(self, backend):
private_key = RSA_KEY_522.private_key(backend)
- signer = private_key.signer(
+ private_key.sign(
+ b"no failure",
padding.PSS(
mgf=padding.MGF1(hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA512()
)
- signer.update(b"no failure")
- signer.finalize()
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -346,7 +502,8 @@ class TestRSASignature(object):
def test_pss_signing_digest_too_large_for_key_size(self, backend):
private_key = RSA_KEY_512.private_key(backend)
with pytest.raises(ValueError):
- private_key.signer(
+ private_key.sign(
+ b"msg",
padding.PSS(
mgf=padding.MGF1(hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH
@@ -365,16 +522,15 @@ class TestRSASignature(object):
)
def test_pss_signing_salt_length_too_long(self, backend):
private_key = RSA_KEY_512.private_key(backend)
- signer = private_key.signer(
- padding.PSS(
- mgf=padding.MGF1(hashes.SHA1()),
- salt_length=1000000
- ),
- hashes.SHA1()
- )
- signer.update(b"failure coming")
with pytest.raises(ValueError):
- signer.finalize()
+ private_key.sign(
+ b"failure coming",
+ padding.PSS(
+ mgf=padding.MGF1(hashes.SHA1()),
+ salt_length=1000000
+ ),
+ hashes.SHA1()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -384,7 +540,8 @@ class TestRSASignature(object):
)
def test_use_after_finalize(self, backend):
private_key = RSA_KEY_512.private_key(backend)
- signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
+ with pytest.warns(CryptographyDeprecationWarning):
+ signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
signer.update(b"sign me")
signer.finalize()
with pytest.raises(AlreadyFinalized):
@@ -395,12 +552,12 @@ class TestRSASignature(object):
def test_unsupported_padding(self, backend):
private_key = RSA_KEY_512.private_key(backend)
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
- private_key.signer(DummyPadding(), hashes.SHA1())
+ private_key.sign(b"msg", DummyAsymmetricPadding(), hashes.SHA1())
def test_padding_incorrect_type(self, backend):
private_key = RSA_KEY_512.private_key(backend)
with pytest.raises(TypeError):
- private_key.signer("notpadding", hashes.SHA1())
+ private_key.sign(b"msg", "notpadding", hashes.SHA1())
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -411,7 +568,8 @@ class TestRSASignature(object):
def test_unsupported_pss_mgf(self, backend):
private_key = RSA_KEY_512.private_key(backend)
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF):
- private_key.signer(
+ private_key.sign(
+ b"msg",
padding.PSS(
mgf=DummyMGF(),
salt_length=padding.PSS.MAX_LENGTH
@@ -427,13 +585,12 @@ class TestRSASignature(object):
)
def test_pkcs1_digest_too_large_for_key_size(self, backend):
private_key = RSA_KEY_599.private_key(backend)
- signer = private_key.signer(
- padding.PKCS1v15(),
- hashes.SHA512()
- )
- signer.update(b"failure coming")
with pytest.raises(ValueError):
- signer.finalize()
+ private_key.sign(
+ b"failure coming",
+ padding.PKCS1v15(),
+ hashes.SHA512()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -443,12 +600,104 @@ class TestRSASignature(object):
)
def test_pkcs1_minimum_key_size(self, backend):
private_key = RSA_KEY_745.private_key(backend)
- signer = private_key.signer(
+ private_key.sign(
+ b"no failure",
padding.PKCS1v15(),
hashes.SHA512()
)
- signer.update(b"no failure")
- signer.finalize()
+
+ def test_sign(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ message = b"one little message"
+ pkcs = padding.PKCS1v15()
+ algorithm = hashes.SHA1()
+ signature = private_key.sign(message, pkcs, algorithm)
+ public_key = private_key.public_key()
+ public_key.verify(signature, message, pkcs, algorithm)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0)
+ ),
+ skip_message="Does not support PSS."
+ )
+ def test_prehashed_sign(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ message = b"one little message"
+ h = hashes.Hash(hashes.SHA1(), backend)
+ h.update(message)
+ digest = h.finalize()
+ pss = padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0)
+ prehashed_alg = asym_utils.Prehashed(hashes.SHA1())
+ signature = private_key.sign(digest, pss, prehashed_alg)
+ public_key = private_key.public_key()
+ public_key.verify(signature, message, pss, hashes.SHA1())
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.hash_supported(
+ hashes.BLAKE2s(digest_size=32)),
+ skip_message="Does not support BLAKE2s",
+ )
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0)
+ ),
+ skip_message="Does not support PSS."
+ )
+ def test_unsupported_hash(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ message = b"one little message"
+ pss = padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=0)
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH):
+ private_key.sign(message, pss, hashes.BLAKE2s(32))
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0)
+ ),
+ skip_message="Does not support PSS."
+ )
+ def test_prehashed_digest_mismatch(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ message = b"one little message"
+ h = hashes.Hash(hashes.SHA512(), backend)
+ h.update(message)
+ digest = h.finalize()
+ pss = padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0)
+ prehashed_alg = asym_utils.Prehashed(hashes.SHA1())
+ with pytest.raises(ValueError):
+ private_key.sign(digest, pss, prehashed_alg)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.PKCS1v15()
+ ),
+ skip_message="Does not support PKCS1v1.5."
+ )
+ def test_prehashed_unsupported_in_signer_ctx(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ with pytest.raises(TypeError), \
+ pytest.warns(CryptographyDeprecationWarning):
+ private_key.signer(
+ padding.PKCS1v15(),
+ asym_utils.Prehashed(hashes.SHA1())
+ )
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.PKCS1v15()
+ ),
+ skip_message="Does not support PKCS1v1.5."
+ )
+ def test_prehashed_unsupported_in_verifier_ctx(self, backend):
+ public_key = RSA_KEY_512.private_key(backend).public_key()
+ with pytest.raises(TypeError), \
+ pytest.warns(CryptographyDeprecationWarning):
+ public_key.verifier(
+ b"0" * 64,
+ padding.PKCS1v15(),
+ asym_utils.Prehashed(hashes.SHA1())
+ )
@pytest.mark.requires_backend_interface(interface=RSABackend)
@@ -473,13 +722,12 @@ class TestRSAVerification(object):
e=public["public_exponent"],
n=public["modulus"]
).public_key(backend)
- verifier = public_key.verifier(
+ public_key.verify(
binascii.unhexlify(example["signature"]),
+ binascii.unhexlify(example["message"]),
padding.PKCS1v15(),
hashes.SHA1()
)
- verifier.update(binascii.unhexlify(example["message"]))
- verifier.verify()
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -490,17 +738,51 @@ class TestRSAVerification(object):
def test_invalid_pkcs1v15_signature_wrong_data(self, backend):
private_key = RSA_KEY_512.private_key(backend)
public_key = private_key.public_key()
- signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
- signer.update(b"sign me")
- signature = signer.finalize()
- verifier = public_key.verifier(
- signature,
- padding.PKCS1v15(),
- hashes.SHA1()
+ signature = private_key.sign(
+ b"sign me", padding.PKCS1v15(), hashes.SHA1()
)
- verifier.update(b"incorrect data")
with pytest.raises(InvalidSignature):
- verifier.verify()
+ public_key.verify(
+ signature,
+ b"incorrect data",
+ padding.PKCS1v15(),
+ hashes.SHA1()
+ )
+
+ def test_invalid_signature_sequence_removed(self, backend):
+ """
+ This test comes from wycheproof
+ """
+ key_der = binascii.unhexlify(
+ b"30820122300d06092a864886f70d01010105000382010f003082010a02820101"
+ b"00a2b451a07d0aa5f96e455671513550514a8a5b462ebef717094fa1fee82224"
+ b"e637f9746d3f7cafd31878d80325b6ef5a1700f65903b469429e89d6eac88450"
+ b"97b5ab393189db92512ed8a7711a1253facd20f79c15e8247f3d3e42e46e48c9"
+ b"8e254a2fe9765313a03eff8f17e1a029397a1fa26a8dce26f490ed81299615d9"
+ b"814c22da610428e09c7d9658594266f5c021d0fceca08d945a12be82de4d1ece"
+ b"6b4c03145b5d3495d4ed5411eb878daf05fd7afc3e09ada0f1126422f590975a"
+ b"1969816f48698bcbba1b4d9cae79d460d8f9f85e7975005d9bc22c4e5ac0f7c1"
+ b"a45d12569a62807d3b9a02e5a530e773066f453d1f5b4c2e9cf7820283f742b9"
+ b"d50203010001"
+ )
+ sig = binascii.unhexlify(
+ b"498209f59a0679a1f926eccf3056da2cba553d7ab3064e7c41ad1d739f038249"
+ b"f02f5ad12ee246073d101bc3cdb563e8b6be61562056422b7e6c16ad53deb12a"
+ b"f5de744197753a35859833f41bb59c6597f3980132b7478fd0b95fd27dfad64a"
+ b"20fd5c25312bbd41a85286cd2a83c8df5efa0779158d01b0747ff165b055eb28"
+ b"80ea27095700a295593196d8c5922cf6aa9d7e29b5056db5ded5eb20aeb31b89"
+ b"42e26b15a5188a4934cd7e39cfe379a197f49a204343a493452deebca436ee61"
+ b"4f4daf989e355544489f7e69ffa8ccc6a1e81cf0ab33c3e6d7591091485a6a31"
+ b"bda3b33946490057b9a3003d3fd9daf7c4778b43fd46144d945d815f12628ff4"
+ )
+ public_key = serialization.load_der_public_key(key_der, backend)
+ with pytest.raises(InvalidSignature):
+ public_key.verify(
+ sig,
+ binascii.unhexlify(b"313233343030"),
+ padding.PKCS1v15(),
+ hashes.SHA256()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -512,17 +794,12 @@ class TestRSAVerification(object):
private_key = RSA_KEY_512.private_key(backend)
private_key2 = RSA_KEY_512_ALT.private_key(backend)
public_key = private_key2.public_key()
- signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
- signer.update(b"sign me")
- signature = signer.finalize()
- verifier = public_key.verifier(
- signature,
- padding.PKCS1v15(),
- hashes.SHA1()
- )
- verifier.update(b"sign me")
+ msg = b"sign me"
+ signature = private_key.sign(msg, padding.PKCS1v15(), hashes.SHA1())
with pytest.raises(InvalidSignature):
- verifier.verify()
+ public_key.verify(
+ signature, msg, padding.PKCS1v15(), hashes.SHA1()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -547,16 +824,15 @@ class TestRSAVerification(object):
e=public["public_exponent"],
n=public["modulus"]
).public_key(backend)
- verifier = public_key.verifier(
+ public_key.verify(
binascii.unhexlify(example["signature"]),
+ binascii.unhexlify(example["message"]),
padding.PSS(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
salt_length=20
),
hashes.SHA1()
)
- verifier.update(binascii.unhexlify(example["message"]))
- verifier.verify()
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -580,17 +856,16 @@ class TestRSAVerification(object):
b"0e68c3649df91c5bc3665f96e157efa75b71934aaa514d91e94ca8418d100f45"
b"6f05288e58525f99666bab052adcffdf7186eb40f583bd38d98c97d3d524808b"
)
- verifier = public_key.verifier(
- signature,
- padding.PSS(
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
- salt_length=padding.PSS.MAX_LENGTH
- ),
- hashes.SHA1()
- )
- verifier.update(b"incorrect data")
with pytest.raises(InvalidSignature):
- verifier.verify()
+ public_key.verify(
+ signature,
+ b"incorrect data",
+ padding.PSS(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ salt_length=padding.PSS.MAX_LENGTH
+ ),
+ hashes.SHA1()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -616,17 +891,16 @@ class TestRSAVerification(object):
),
e=65537
).public_key(backend)
- verifier = public_key.verifier(
- signature,
- padding.PSS(
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
- salt_length=padding.PSS.MAX_LENGTH
- ),
- hashes.SHA1()
- )
- verifier.update(b"sign me")
with pytest.raises(InvalidSignature):
- verifier.verify()
+ public_key.verify(
+ signature,
+ b"sign me",
+ padding.PSS(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ salt_length=padding.PSS.MAX_LENGTH
+ ),
+ hashes.SHA1()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -652,17 +926,16 @@ class TestRSAVerification(object):
),
e=65537
).public_key(backend)
- verifier = public_key.verifier(
- signature,
- padding.PSS(
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
- salt_length=padding.PSS.MAX_LENGTH
- ),
- hashes.SHA1()
- )
- verifier.update(b"sign me")
with pytest.raises(InvalidSignature):
- verifier.verify()
+ public_key.verify(
+ signature,
+ b"sign me",
+ padding.PSS(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ salt_length=padding.PSS.MAX_LENGTH
+ ),
+ hashes.SHA1()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -673,15 +946,16 @@ class TestRSAVerification(object):
def test_use_after_finalize(self, backend):
private_key = RSA_KEY_512.private_key(backend)
public_key = private_key.public_key()
- signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1())
- signer.update(b"sign me")
- signature = signer.finalize()
-
- verifier = public_key.verifier(
- signature,
- padding.PKCS1v15(),
- hashes.SHA1()
+ signature = private_key.sign(
+ b"sign me", padding.PKCS1v15(), hashes.SHA1()
)
+
+ with pytest.warns(CryptographyDeprecationWarning):
+ verifier = public_key.verifier(
+ signature,
+ padding.PKCS1v15(),
+ hashes.SHA1()
+ )
verifier.update(b"sign me")
verifier.verify()
with pytest.raises(AlreadyFinalized):
@@ -693,13 +967,33 @@ class TestRSAVerification(object):
private_key = RSA_KEY_512.private_key(backend)
public_key = private_key.public_key()
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
- public_key.verifier(b"sig", DummyPadding(), hashes.SHA1())
+ public_key.verify(
+ b"sig", b"msg", DummyAsymmetricPadding(), hashes.SHA1()
+ )
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.PKCS1v15()
+ ),
+ skip_message="Does not support PKCS1v1.5."
+ )
+ def test_signature_not_bytes(self, backend):
+ public_key = RSA_KEY_512.public_numbers.public_key(backend)
+ signature = 1234
+
+ with pytest.raises(TypeError), \
+ pytest.warns(CryptographyDeprecationWarning):
+ public_key.verifier(
+ signature,
+ padding.PKCS1v15(),
+ hashes.SHA1()
+ )
def test_padding_incorrect_type(self, backend):
private_key = RSA_KEY_512.private_key(backend)
public_key = private_key.public_key()
with pytest.raises(TypeError):
- public_key.verifier(b"sig", "notpadding", hashes.SHA1())
+ public_key.verify(b"sig", b"msg", "notpadding", hashes.SHA1())
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -711,8 +1005,9 @@ class TestRSAVerification(object):
private_key = RSA_KEY_512.private_key(backend)
public_key = private_key.public_key()
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF):
- public_key.verifier(
+ public_key.verify(
b"sig",
+ b"msg",
padding.PSS(
mgf=DummyMGF(),
salt_length=padding.PSS.MAX_LENGTH
@@ -741,8 +1036,9 @@ class TestRSAVerification(object):
)
public_key = private_key.public_key()
with pytest.raises(ValueError):
- public_key.verifier(
+ public_key.verify(
signature,
+ b"msg doesn't matter",
padding.PSS(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH
@@ -772,19 +1068,50 @@ class TestRSAVerification(object):
),
e=65537
).public_key(backend)
- verifier = public_key.verifier(
- signature,
- padding.PSS(
- mgf=padding.MGF1(
- algorithm=hashes.SHA1(),
- ),
- salt_length=1000000
- ),
- hashes.SHA1()
- )
- verifier.update(b"sign me")
with pytest.raises(InvalidSignature):
- verifier.verify()
+ public_key.verify(
+ signature,
+ b"sign me",
+ padding.PSS(
+ mgf=padding.MGF1(
+ algorithm=hashes.SHA1(),
+ ),
+ salt_length=1000000
+ ),
+ hashes.SHA1()
+ )
+
+ def test_verify(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ message = b"one little message"
+ pkcs = padding.PKCS1v15()
+ algorithm = hashes.SHA1()
+ signature = private_key.sign(message, pkcs, algorithm)
+ public_key = private_key.public_key()
+ public_key.verify(signature, message, pkcs, algorithm)
+
+ def test_prehashed_verify(self, backend):
+ private_key = RSA_KEY_512.private_key(backend)
+ message = b"one little message"
+ h = hashes.Hash(hashes.SHA1(), backend)
+ h.update(message)
+ digest = h.finalize()
+ prehashed_alg = asym_utils.Prehashed(hashes.SHA1())
+ pkcs = padding.PKCS1v15()
+ signature = private_key.sign(message, pkcs, hashes.SHA1())
+ public_key = private_key.public_key()
+ public_key.verify(signature, digest, pkcs, prehashed_alg)
+
+ def test_prehashed_digest_mismatch(self, backend):
+ public_key = RSA_KEY_512.private_key(backend).public_key()
+ message = b"one little message"
+ h = hashes.Hash(hashes.SHA1(), backend)
+ h.update(message)
+ data = h.finalize()
+ prehashed_alg = asym_utils.Prehashed(hashes.SHA512())
+ pkcs = padding.PKCS1v15()
+ with pytest.raises(ValueError):
+ public_key.verify(b"\x00" * 64, data, pkcs, prehashed_alg)
@pytest.mark.requires_backend_interface(interface=RSABackend)
@@ -1009,6 +1336,10 @@ class TestRSAPKCS1Verification(object):
class TestPSS(object):
+ def test_calculate_max_pss_salt_length(self):
+ with pytest.raises(TypeError):
+ padding.calculate_max_pss_salt_length(object(), hashes.SHA256())
+
def test_invalid_salt_length_not_integer(self):
with pytest.raises(TypeError):
padding.PSS(
@@ -1096,14 +1427,14 @@ class TestRSADecryption(object):
)
).private_key(backend)
ciphertext = binascii.unhexlify(example["encryption"])
- assert len(ciphertext) == math.ceil(skey.key_size / 8.0)
+ assert len(ciphertext) == (skey.key_size + 7) // 8
message = skey.decrypt(ciphertext, padding.PKCS1v15())
assert message == binascii.unhexlify(example["message"])
def test_unsupported_padding(self, backend):
private_key = RSA_KEY_512.private_key(backend)
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
- private_key.decrypt(b"0" * 64, DummyPadding())
+ private_key.decrypt(b"0" * 64, DummyAsymmetricPadding())
@pytest.mark.supported(
only_if=lambda backend: backend.rsa_padding_supported(
@@ -1193,6 +1524,119 @@ class TestRSADecryption(object):
)
assert message == binascii.unhexlify(example["message"])
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA224()),
+ algorithm=hashes.SHA224(),
+ label=None
+ )
+ ),
+ skip_message="Does not support OAEP using SHA224 MGF1 and SHA224 hash."
+ )
+ @pytest.mark.parametrize(
+ "vector",
+ _build_oaep_sha2_vectors()
+ )
+ def test_decrypt_oaep_sha2_vectors(self, vector, backend):
+ private, public, example, mgf1_alg, hash_alg = vector
+ skey = rsa.RSAPrivateNumbers(
+ p=private["p"],
+ q=private["q"],
+ d=private["private_exponent"],
+ dmp1=private["dmp1"],
+ dmq1=private["dmq1"],
+ iqmp=private["iqmp"],
+ public_numbers=rsa.RSAPublicNumbers(
+ e=private["public_exponent"],
+ n=private["modulus"]
+ )
+ ).private_key(backend)
+ message = skey.decrypt(
+ binascii.unhexlify(example["encryption"]),
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=mgf1_alg),
+ algorithm=hash_alg,
+ label=None
+ )
+ )
+ assert message == binascii.unhexlify(example["message"])
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=None
+ )
+ ),
+ skip_message="Does not support OAEP."
+ )
+ def test_invalid_oaep_decryption(self, backend):
+ # More recent versions of OpenSSL may raise RSA_R_OAEP_DECODING_ERROR
+ # This test triggers it and confirms that we properly handle it. Other
+ # backends should also return the proper ValueError.
+ private_key = RSA_KEY_512.private_key(backend)
+
+ ciphertext = private_key.public_key().encrypt(
+ b'secure data',
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=None
+ )
+ )
+
+ private_key_alt = RSA_KEY_512_ALT.private_key(backend)
+
+ with pytest.raises(ValueError):
+ private_key_alt.decrypt(
+ ciphertext,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=None
+ )
+ )
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=None
+ )
+ ),
+ skip_message="Does not support OAEP."
+ )
+ def test_invalid_oaep_decryption_data_to_large_for_modulus(self, backend):
+ key = RSA_KEY_2048_ALT.private_key(backend)
+
+ ciphertext = (
+ b'\xb1ph\xc0\x0b\x1a|\xe6\xda\xea\xb5\xd7%\x94\x07\xf96\xfb\x96'
+ b'\x11\x9b\xdc4\xea.-\x91\x80\x13S\x94\x04m\xe9\xc5/F\x1b\x9b:\\'
+ b'\x1d\x04\x16ML\xae\xb32J\x01yuA\xbb\x83\x1c\x8f\xf6\xa5\xdbp\xcd'
+ b'\nx\xc7\xf6\x15\xb2/\xdcH\xae\xe7\x13\x13by\r4t\x99\x0fc\x1f\xc1'
+ b'\x1c\xb1\xdd\xc5\x08\xd1\xee\xa1XQ\xb8H@L5v\xc3\xaf\xf2\r\x97'
+ b'\xed\xaa\xe7\xf1\xd4xai\xd3\x83\xd9\xaa9\xbfx\xe1\x87F \x01\xff'
+ b'L\xccv}ae\xb3\xfa\xf2B\xb8\xf9\x04H\x94\x85\xcb\x86\xbb\\ghx!W31'
+ b'\xc7;t\na_E\xc2\x16\xb0;\xa1\x18\t\x1b\xe1\xdb\x80>)\x15\xc6\x12'
+ b'\xcb\xeeg`\x8b\x9b\x1b\x05y4\xb0\x84M6\xcd\xa1\x827o\xfd\x96\xba'
+ b'Z#\x8d\xae\x01\xc9\xf2\xb6\xde\x89{8&eQ\x1e8\x03\x01#?\xb66\\'
+ b'\xad.\xe9\xfa!\x95 c{\xcaz\xe0*\tP\r\x91\x9a)B\xb5\xadN\xf4$\x83'
+ b'\t\xb5u\xab\x19\x99'
+ )
+
+ with pytest.raises(ValueError):
+ key.decrypt(
+ ciphertext,
+ padding.OAEP(
+ algorithm=hashes.SHA1(),
+ mgf=padding.MGF1(hashes.SHA1()),
+ label=None
+ )
+ )
+
def test_unsupported_oaep_mgf(self, backend):
private_key = RSA_KEY_512.private_key(backend)
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF):
@@ -1239,7 +1683,48 @@ class TestRSAEncryption(object):
public_key = private_key.public_key()
ct = public_key.encrypt(pt, pad)
assert ct != pt
- assert len(ct) == math.ceil(public_key.key_size / 8.0)
+ assert len(ct) == (public_key.key_size + 7) // 8
+ recovered_pt = private_key.decrypt(ct, pad)
+ assert recovered_pt == pt
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.rsa_padding_supported(
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA512(),
+ label=None
+ )
+ ),
+ skip_message="Does not support OAEP using SHA256 MGF1 and SHA512 hash."
+ )
+ @pytest.mark.parametrize(
+ ("mgf1hash", "oaephash"),
+ itertools.product([
+ hashes.SHA1(),
+ hashes.SHA224(),
+ hashes.SHA256(),
+ hashes.SHA384(),
+ hashes.SHA512(),
+ ], [
+ hashes.SHA1(),
+ hashes.SHA224(),
+ hashes.SHA256(),
+ hashes.SHA384(),
+ hashes.SHA512(),
+ ])
+ )
+ def test_rsa_encrypt_oaep_sha2(self, mgf1hash, oaephash, backend):
+ pad = padding.OAEP(
+ mgf=padding.MGF1(algorithm=mgf1hash),
+ algorithm=oaephash,
+ label=None
+ )
+ private_key = RSA_KEY_2048.private_key(backend)
+ pt = b"encrypt me using sha2 hashes!"
+ public_key = private_key.public_key()
+ ct = public_key.encrypt(pt, pad)
+ assert ct != pt
+ assert len(ct) == (public_key.key_size + 7) // 8
recovered_pt = private_key.decrypt(ct, pad)
assert recovered_pt == pt
@@ -1264,7 +1749,7 @@ class TestRSAEncryption(object):
public_key = private_key.public_key()
ct = public_key.encrypt(pt, pad)
assert ct != pt
- assert len(ct) == math.ceil(public_key.key_size / 8.0)
+ assert len(ct) == (public_key.key_size + 7) // 8
recovered_pt = private_key.decrypt(ct, pad)
assert recovered_pt == pt
@@ -1306,7 +1791,7 @@ class TestRSAEncryption(object):
public_key = private_key.public_key()
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING):
- public_key.encrypt(b"somedata", DummyPadding())
+ public_key.encrypt(b"somedata", DummyAsymmetricPadding())
with pytest.raises(TypeError):
public_key.encrypt(b"somedata", padding=object())
@@ -1367,304 +1852,81 @@ class TestRSANumbers(object):
with pytest.raises(TypeError):
rsa.RSAPublicNumbers(e=1, n=None)
- def test_private_numbers_invalid_types(self):
- public_numbers = rsa.RSAPublicNumbers(e=1, n=15)
-
- with pytest.raises(TypeError):
- rsa.RSAPrivateNumbers(
- p=None,
- q=5,
- d=1,
- dmp1=1,
- dmq1=1,
- iqmp=2,
- public_numbers=public_numbers
- )
-
- with pytest.raises(TypeError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=None,
- d=1,
- dmp1=1,
- dmq1=1,
- iqmp=2,
- public_numbers=public_numbers
- )
-
- with pytest.raises(TypeError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=5,
- d=None,
- dmp1=1,
- dmq1=1,
- iqmp=2,
- public_numbers=public_numbers
- )
-
- with pytest.raises(TypeError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=5,
- d=1,
- dmp1=None,
- dmq1=1,
- iqmp=2,
- public_numbers=public_numbers
- )
-
- with pytest.raises(TypeError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=5,
- d=1,
- dmp1=1,
- dmq1=None,
- iqmp=2,
- public_numbers=public_numbers
- )
-
+ @pytest.mark.parametrize(
+ ("p", "q", "d", "dmp1", "dmq1", "iqmp", "public_numbers"),
+ [
+ (None, 5, 1, 1, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)),
+ (3, None, 1, 1, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)),
+ (3, 5, None, 1, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)),
+ (3, 5, 1, None, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)),
+ (3, 5, 1, 1, None, 2, rsa.RSAPublicNumbers(e=1, n=15)),
+ (3, 5, 1, 1, 1, None, rsa.RSAPublicNumbers(e=1, n=15)),
+ (3, 5, 1, 1, 1, 2, None),
+ ]
+ )
+ def test_private_numbers_invalid_types(self, p, q, d, dmp1, dmq1, iqmp,
+ public_numbers):
with pytest.raises(TypeError):
rsa.RSAPrivateNumbers(
- p=3,
- q=5,
- d=1,
- dmp1=1,
- dmq1=1,
- iqmp=None,
+ p=p, q=q,
+ d=d,
+ dmp1=dmp1,
+ dmq1=dmq1,
+ iqmp=iqmp,
public_numbers=public_numbers
)
- with pytest.raises(TypeError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=5,
- d=1,
- dmp1=1,
- dmq1=1,
- iqmp=2,
- public_numbers=None
- )
-
- def test_invalid_public_numbers_argument_values(self, backend):
+ @pytest.mark.parametrize(
+ ("e", "n"),
+ [
+ (7, 2), # modulus < 3
+ (1, 15), # public_exponent < 3
+ (17, 15), # public_exponent > modulus
+ (14, 15), # public_exponent not odd
+ ]
+ )
+ def test_invalid_public_numbers_argument_values(self, e, n, backend):
# Start with public_exponent=7, modulus=15. Then change one value at a
# time to test the bounds.
- # Test a modulus < 3.
-
- with pytest.raises(ValueError):
- rsa.RSAPublicNumbers(e=7, n=2).public_key(backend)
-
- # Test a public_exponent < 3
with pytest.raises(ValueError):
- rsa.RSAPublicNumbers(e=1, n=15).public_key(backend)
+ rsa.RSAPublicNumbers(e=e, n=n).public_key(backend)
- # Test a public_exponent > modulus
- with pytest.raises(ValueError):
- rsa.RSAPublicNumbers(e=17, n=15).public_key(backend)
-
- # Test a public_exponent that is not odd.
- with pytest.raises(ValueError):
- rsa.RSAPublicNumbers(e=14, n=15).public_key(backend)
-
- def test_invalid_private_numbers_argument_values(self, backend):
+ @pytest.mark.parametrize(
+ ("p", "q", "d", "dmp1", "dmq1", "iqmp", "e", "n"),
+ [
+ (3, 11, 3, 1, 3, 2, 7, 2), # modulus < 3
+ (3, 11, 3, 1, 3, 2, 7, 35), # modulus != p * q
+ (37, 11, 3, 1, 3, 2, 7, 33), # p > modulus
+ (3, 37, 3, 1, 3, 2, 7, 33), # q > modulus
+ (3, 11, 3, 35, 3, 2, 7, 33), # dmp1 > modulus
+ (3, 11, 3, 1, 35, 2, 7, 33), # dmq1 > modulus
+ (3, 11, 3, 1, 3, 35, 7, 33), # iqmp > modulus
+ (3, 11, 37, 1, 3, 2, 7, 33), # d > modulus
+ (3, 11, 3, 1, 3, 2, 1, 33), # public_exponent < 3
+ (3, 11, 3, 1, 3, 35, 65537, 33), # public_exponent > modulus
+ (3, 11, 3, 1, 3, 2, 6, 33), # public_exponent is not odd
+ (3, 11, 3, 2, 3, 2, 7, 33), # dmp1 is not odd
+ (3, 11, 3, 1, 4, 2, 7, 33), # dmq1 is not odd
+ ]
+ )
+ def test_invalid_private_numbers_argument_values(self, p, q, d, dmp1, dmq1,
+ iqmp, e, n, backend):
# Start with p=3, q=11, private_exponent=3, public_exponent=7,
# modulus=33, dmp1=1, dmq1=3, iqmp=2. Then change one value at
# a time to test the bounds.
- # Test a modulus < 3.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=2
- )
- ).private_key(backend)
-
- # Test a modulus != p * q.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=35
- )
- ).private_key(backend)
-
- # Test a p > modulus.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=37,
- q=11,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
- )
- ).private_key(backend)
-
- # Test a q > modulus.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=37,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
- )
- ).private_key(backend)
-
- # Test a dmp1 > modulus.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=35,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
- )
- ).private_key(backend)
-
- # Test a dmq1 > modulus.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=35,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
- )
- ).private_key(backend)
-
- # Test an iqmp > modulus.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=35,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
- )
- ).private_key(backend)
-
- # Test a private_exponent > modulus
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=37,
- dmp1=1,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
- )
- ).private_key(backend)
-
- # Test a public_exponent < 3
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=1,
- n=33
- )
- ).private_key(backend)
-
- # Test a public_exponent > modulus
with pytest.raises(ValueError):
rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=35,
+ p=p,
+ q=q,
+ d=d,
+ dmp1=dmp1,
+ dmq1=dmq1,
+ iqmp=iqmp,
public_numbers=rsa.RSAPublicNumbers(
- e=65537,
- n=33
- )
- ).private_key(backend)
-
- # Test a public_exponent that is not odd.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=6,
- n=33
- )
- ).private_key(backend)
-
- # Test a dmp1 that is not odd.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=2,
- dmq1=3,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
- )
- ).private_key(backend)
-
- # Test a dmq1 that is not odd.
- with pytest.raises(ValueError):
- rsa.RSAPrivateNumbers(
- p=3,
- q=11,
- d=3,
- dmp1=1,
- dmq1=4,
- iqmp=2,
- public_numbers=rsa.RSAPublicNumbers(
- e=7,
- n=33
+ e=e,
+ n=n
)
).private_key(backend)
@@ -1721,6 +1983,22 @@ class TestRSANumbersEquality(object):
)
assert num != object()
+ def test_public_numbers_hash(self):
+ pub1 = RSAPublicNumbers(3, 17)
+ pub2 = RSAPublicNumbers(3, 17)
+ pub3 = RSAPublicNumbers(7, 21)
+
+ assert hash(pub1) == hash(pub2)
+ assert hash(pub1) != hash(pub3)
+
+ def test_private_numbers_hash(self):
+ priv1 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 2))
+ priv2 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 2))
+ priv3 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 3))
+
+ assert hash(priv1) == hash(priv2)
+ assert hash(priv1) != hash(priv3)
+
class TestRSAPrimeFactorRecovery(object):
@pytest.mark.parametrize(
@@ -1739,10 +2017,11 @@ class TestRSAPrimeFactorRecovery(object):
private["private_exponent"]
)
# Unfortunately there is no convention on which prime should be p
- # and which one q. The function we use always makes p < q, but the
- # NIST vectors are not so consistent. Accordingly we verify we've
+ # and which one q. The function we use always makes p > q, but the
+ # NIST vectors are not so consistent. Accordingly, we verify we've
# recovered the proper (p, q) by sorting them and asserting on that.
assert sorted([p, q]) == sorted([private["p"], private["q"]])
+ assert p > q
def test_invalid_recover_prime_factors(self):
with pytest.raises(ValueError):
@@ -1769,7 +2048,6 @@ class TestRSAPrivateKeySerialization(object):
)
def test_private_bytes_encrypted_pem(self, backend, fmt, password):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
serialized = key.private_bytes(
serialization.Encoding.PEM,
fmt,
@@ -1783,6 +2061,20 @@ class TestRSAPrivateKeySerialization(object):
assert loaded_priv_num == priv_num
@pytest.mark.parametrize(
+ ("encoding", "fmt"),
+ [
+ (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8),
+ (serialization.Encoding.DER, serialization.PrivateFormat.Raw),
+ (serialization.Encoding.Raw, serialization.PrivateFormat.Raw),
+ (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8),
+ ]
+ )
+ def test_private_bytes_rejects_invalid(self, encoding, fmt, backend):
+ key = RSA_KEY_2048.private_key(backend)
+ with pytest.raises(ValueError):
+ key.private_bytes(encoding, fmt, serialization.NoEncryption())
+
+ @pytest.mark.parametrize(
("fmt", "password"),
[
[serialization.PrivateFormat.PKCS8, b"s"],
@@ -1793,7 +2085,6 @@ class TestRSAPrivateKeySerialization(object):
)
def test_private_bytes_encrypted_der(self, backend, fmt, password):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
serialized = key.private_bytes(
serialization.Encoding.DER,
fmt,
@@ -1834,7 +2125,6 @@ class TestRSAPrivateKeySerialization(object):
def test_private_bytes_unencrypted(self, backend, encoding, fmt,
loader_func):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
serialized = key.private_bytes(
encoding, fmt, serialization.NoEncryption()
)
@@ -1878,7 +2168,6 @@ class TestRSAPrivateKeySerialization(object):
def test_private_bytes_traditional_der_encrypted_invalid(self, backend):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
with pytest.raises(ValueError):
key.private_bytes(
serialization.Encoding.DER,
@@ -1888,7 +2177,6 @@ class TestRSAPrivateKeySerialization(object):
def test_private_bytes_invalid_encoding(self, backend):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.private_bytes(
"notencoding",
@@ -1898,7 +2186,6 @@ class TestRSAPrivateKeySerialization(object):
def test_private_bytes_invalid_format(self, backend):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.private_bytes(
serialization.Encoding.PEM,
@@ -1908,7 +2195,6 @@ class TestRSAPrivateKeySerialization(object):
def test_private_bytes_invalid_encryption_algorithm(self, backend):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.private_bytes(
serialization.Encoding.PEM,
@@ -1918,12 +2204,11 @@ class TestRSAPrivateKeySerialization(object):
def test_private_bytes_unsupported_encryption_type(self, backend):
key = RSA_KEY_2048.private_key(backend)
- _skip_if_no_serialization(key, backend)
with pytest.raises(ValueError):
key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.TraditionalOpenSSL,
- DummyKeyEncryption()
+ DummyKeySerializationEncryption()
)
@@ -1966,18 +2251,78 @@ class TestRSAPEMPublicKeySerialization(object):
key_path, lambda pemfile: pemfile.read(), mode="rb"
)
key = loader_func(key_bytes, backend)
- _skip_if_no_serialization(key, backend)
serialized = key.public_bytes(encoding, format)
assert serialized == key_bytes
+ def test_public_bytes_openssh(self, backend):
+ key_bytes = load_vectors_from_file(
+ os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"),
+ lambda pemfile: pemfile.read(), mode="rb"
+ )
+ key = serialization.load_pem_public_key(key_bytes, backend)
+
+ ssh_bytes = key.public_bytes(
+ serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH
+ )
+ assert ssh_bytes == (
+ b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC7JHoJfg6yNzLMOWet8Z49a4KD"
+ b"0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkkFPZk/7x0"
+ b"xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAvSKAFKEvy"
+ b"D43si00DQnXWrYHAEQ=="
+ )
+
+ with pytest.raises(ValueError):
+ key.public_bytes(
+ serialization.Encoding.PEM, serialization.PublicFormat.OpenSSH
+ )
+ with pytest.raises(ValueError):
+ key.public_bytes(
+ serialization.Encoding.DER, serialization.PublicFormat.OpenSSH
+ )
+ with pytest.raises(ValueError):
+ key.public_bytes(
+ serialization.Encoding.OpenSSH,
+ serialization.PublicFormat.PKCS1,
+ )
+ with pytest.raises(ValueError):
+ key.public_bytes(
+ serialization.Encoding.OpenSSH,
+ serialization.PublicFormat.SubjectPublicKeyInfo,
+ )
+
def test_public_bytes_invalid_encoding(self, backend):
key = RSA_KEY_2048.private_key(backend).public_key()
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.public_bytes("notencoding", serialization.PublicFormat.PKCS1)
def test_public_bytes_invalid_format(self, backend):
key = RSA_KEY_2048.private_key(backend).public_key()
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.public_bytes(serialization.Encoding.PEM, "invalidformat")
+
+ @pytest.mark.parametrize(
+ ("encoding", "fmt"),
+ [
+ (
+ serialization.Encoding.Raw,
+ serialization.PublicFormat.SubjectPublicKeyInfo
+ ),
+ (serialization.Encoding.Raw, serialization.PublicFormat.PKCS1),
+ ] + list(itertools.product(
+ [
+ serialization.Encoding.Raw,
+ serialization.Encoding.X962,
+ serialization.Encoding.PEM,
+ serialization.Encoding.DER
+ ],
+ [
+ serialization.PublicFormat.Raw,
+ serialization.PublicFormat.UncompressedPoint,
+ serialization.PublicFormat.CompressedPoint
+ ]
+ ))
+ )
+ def test_public_bytes_rejects_invalid(self, encoding, fmt, backend):
+ key = RSA_KEY_2048.private_key(backend).public_key()
+ with pytest.raises(ValueError):
+ key.public_bytes(encoding, fmt)