back to OpenHands summary
OpenHands: python-rsa
Pytest Summary for test tests
status |
count |
error |
14 |
passed |
29 |
failed |
44 |
total |
87 |
collected |
87 |
Failed pytests:
test_cli.py::KeygenTest::test_keygen_no_args
test_cli.py::KeygenTest::test_keygen_no_args
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::KeygenTest::test_keygen_priv_out_der
test_cli.py::KeygenTest::test_keygen_priv_out_der
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::KeygenTest::test_keygen_priv_out_pem
test_cli.py::KeygenTest::test_keygen_priv_out_pem
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::KeygenTest::test_keygen_priv_stdout
test_cli.py::KeygenTest::test_keygen_priv_stdout
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::KeygenTest::test_keygen_pub_out_pem
test_cli.py::KeygenTest::test_keygen_pub_out_pem
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::EncryptDecryptTest::test_empty_decrypt
test_cli.py::EncryptDecryptTest::test_empty_decrypt
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::EncryptDecryptTest::test_empty_encrypt
test_cli.py::EncryptDecryptTest::test_empty_encrypt
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::EncryptDecryptTest::test_encrypt_decrypt
test_cli.py::EncryptDecryptTest::test_encrypt_decrypt
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::EncryptDecryptTest::test_encrypt_decrypt_unhappy
test_cli.py::EncryptDecryptTest::test_encrypt_decrypt_unhappy
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::SignVerifyTest::test_empty_sign
test_cli.py::SignVerifyTest::test_empty_sign
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::SignVerifyTest::test_empty_verify
test_cli.py::SignVerifyTest::test_empty_verify
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::SignVerifyTest::test_sign_verify
test_cli.py::SignVerifyTest::test_sign_verify
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::SignVerifyTest::test_sign_verify_unhappy
test_cli.py::SignVerifyTest::test_sign_verify_unhappy
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_cli.py::PrivatePublicTest::test_private_to_public
test_cli.py::PrivatePublicTest::test_private_to_public
cls =
@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())
E TypeError: a bytes-like object is required, not 'NoneType'
tests/test_cli.py:90: TypeError
test_key.py::BlindingTest::test_blinding
test_key.py::BlindingTest::test_blinding
self =
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)
E AssertionError: 179750770 == 179750770
tests/test_key.py:32: AssertionError
test_key.py::KeyGenTest::test_custom_exponent
test_key.py::KeyGenTest::test_custom_exponent
p = 241, q = 199, exponent = 3
def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tuple[int, int]:
"""Calculates an encryption and a decryption key given p, q and an exponent,
and returns them as a tuple (e, d)
:param p: the first large prime
:param q: the second large prime
:param exponent: the exponent for the key; only change this if you know
what you're doing, as the exponent influences how difficult your
private key can be cracked. A very common choice for e is 65537.
:type exponent: int
"""
phi_n = (p - 1) * (q - 1)
try:
> d = rsa.common.inverse(exponent, phi_n)
rsa/key.py:513:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
x = 3, n = 47520
def inverse(x: int, n: int) -> int:
"""Returns the inverse of x % n under multiplication, a.k.a x^-1 (mod n)
>>> inverse(7, 4)
3
>>> (inverse(143, 4) * 143) % 4
1
"""
gcd, a, _ = extended_gcd(x, n)
if gcd != 1:
> raise NotRelativePrimeError(x, n, gcd)
E rsa.common.NotRelativePrimeError: 3 and 47520 are not relatively prime, divider=3
rsa/common.py:123: NotRelativePrimeError
During handling of the above exception, another exception occurred:
self =
def test_custom_exponent(self):
> pub, priv = rsa.key.newkeys(16, exponent=3)
tests/test_key.py:42:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/key.py:598: in newkeys
p, q, e, d = gen_keys(nbits, prime_func, accurate=accurate, exponent=exponent)
rsa/key.py:554: in gen_keys
e, d = calculate_keys_custom_exponent(p, q, exponent)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
p = 241, q = 199, exponent = 3
def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tuple[int, int]:
"""Calculates an encryption and a decryption key given p, q and an exponent,
and returns them as a tuple (e, d)
:param p: the first large prime
:param q: the second large prime
:param exponent: the exponent for the key; only change this if you know
what you're doing, as the exponent influences how difficult your
private key can be cracked. A very common choice for e is 65537.
:type exponent: int
"""
phi_n = (p - 1) * (q - 1)
try:
d = rsa.common.inverse(exponent, phi_n)
except rsa.common.NotRelativePrimeError as ex:
> raise ValueError("e and phi_n are not relatively prime", ex)
E ValueError: ('e and phi_n are not relatively prime', NotRelativePrimeError('3 and 47520 are not relatively prime, divider=3'))
rsa/key.py:515: ValueError
test_key.py::KeyGenTest::test_custom_getprime_func
test_key.py::KeyGenTest::test_custom_getprime_func
self =
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
)
tests/test_key.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/key.py:551: in gen_keys
p, q = find_p_q(bits_per_prime, getprime_func, accurate)
rsa/key.py:478: in find_p_q
p = getprime_func(nbits)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ = 32
def getprime(_):
> return primes.pop(0)
E IndexError: pop from empty list
tests/test_key.py:67: IndexError
test_load_save_keys.py::DerTest::test_load_malformed_private_key
self =
der_decode =
@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))
E AssertionError: 3 != 0
tests/test_load_save_keys.py:122: AssertionError
test_load_save_keys.py::DerTest::test_load_private_key
test_load_save_keys.py::DerTest::test_load_private_key
self =
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)
E AssertionError: PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) != None
tests/test_load_save_keys.py:98: AssertionError
test_load_save_keys.py::DerTest::test_load_public_key
test_load_save_keys.py::DerTest::test_load_public_key
self =
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)
E AssertionError: PublicKey(3727264081, 65537) != None
tests/test_load_save_keys.py:148: AssertionError
test_load_save_keys.py::DerTest::test_save_private_key
test_load_save_keys.py::DerTest::test_save_private_key
self =
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)
E AssertionError: None is not an instance of
tests/test_load_save_keys.py:139: AssertionError
test_load_save_keys.py::DerTest::test_save_public_key
test_load_save_keys.py::DerTest::test_save_public_key
self =
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)
E AssertionError: None is not an instance of
tests/test_load_save_keys.py:156: AssertionError
test_load_save_keys.py::PemTest::test_load_from_disk
test_load_save_keys.py::PemTest::test_load_from_disk
self =
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)
E AttributeError: 'NoneType' object has no attribute 'p'
tests/test_load_save_keys.py:208: AttributeError
test_load_save_keys.py::PemTest::test_load_private_key
test_load_save_keys.py::PemTest::test_load_private_key
self =
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)
E AssertionError: PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) != None
tests/test_load_save_keys.py:169: AssertionError
test_load_save_keys.py::PemTest::test_load_public_key
test_load_save_keys.py::PemTest::test_load_public_key
self =
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)
E AssertionError: PublicKey(3727264081, 65537) != None
tests/test_load_save_keys.py:189: AssertionError
test_load_save_keys.py::PemTest::test_save_private_key
test_load_save_keys.py::PemTest::test_save_private_key
self =
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)
E AssertionError: None is not an instance of
tests/test_load_save_keys.py:180: AssertionError
test_load_save_keys.py::PemTest::test_save_public_key
test_load_save_keys.py::PemTest::test_save_public_key
self =
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)
E AssertionError: None is not an instance of
tests/test_load_save_keys.py:197: AssertionError
test_mypy.py::MypyRunnerTest::test_run_mypy
test_mypy.py::MypyRunnerTest::test_run_mypy
self =
def test_run_mypy(self):
proj_root = pathlib.Path(__file__).parent.parent
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)
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))
E AssertionError: Mypy errors:
E setup.cfg: [mypy]: python_version: Python 3.7 is not supported (must be 3.8 or higher)
E
E rsa/pem.py:33: error: If x = b'abc' then "%s" % x produces "b'abc'", not "abc". If this is desired behavior use "%r" % x. Otherwise, decode the bytes [str-bytes-safe]
E rsa/pem.py:56: error: If x = b'abc' then "%s" % x produces "b'abc'", not "abc". If this is desired behavior use "%r" % x. Otherwise, decode the bytes [str-bytes-safe]
E rsa/pem.py:59: error: If x = b'abc' then "%s" % x produces "b'abc'", not "abc". If this is desired behavior use "%r" % x. Otherwise, decode the bytes [str-bytes-safe]
E rsa/parallel.py:15: error: Missing return statement [empty-body]
E rsa/key.py:41: error: Missing return statement [empty-body]
E rsa/key.py:54: error: Missing return statement [empty-body]
E rsa/key.py:66: error: Missing return statement [empty-body]
E rsa/key.py:74: error: Missing return statement [empty-body]
E rsa/key.py:83: error: Missing return statement [empty-body]
E rsa/key.py:98: error: Missing return statement [empty-body]
E rsa/key.py:102: error: Missing return statement [empty-body]
E rsa/key.py:247: error: Missing return statement [empty-body]
E rsa/key.py:256: error: Missing return statement [empty-body]
E rsa/key.py:268: error: Missing return statement [empty-body]
E rsa/key.py:277: error: Missing return statement [empty-body]
E rsa/key.py:294: error: Missing return statement [empty-body]
E rsa/key.py:375: error: Name "core" is not defined [name-defined]
E rsa/key.py:388: error: Name "core" is not defined [name-defined]
E rsa/key.py:392: error: Missing return statement [empty-body]
E rsa/key.py:414: error: Missing return statement [empty-body]
E rsa/key.py:423: error: Missing return statement [empty-body]
E rsa/key.py:436: error: Missing return statement [empty-body]
E rsa/key.py:595: error: Incompatible types in assignment (expression has type "Callable[[int, int], int]", variable has type "Callable[[int], int]") [assignment]
E rsa/pkcs1_v2.py:8: error: Missing return statement [empty-body]
E rsa/cli.py:58: error: Missing return statement [empty-body]
E rsa/cli.py:58: note: If the method is meant to be abstract, use @abc.abstractmethod
E rsa/cli.py:65: error: Missing return statement [empty-body]
E rsa/cli.py:65: note: If the method is meant to be abstract, use @abc.abstractmethod
E rsa/cli.py:69: error: Missing return statement [empty-body]
E rsa/cli.py:69: note: If the method is meant to be abstract, use @abc.abstractmethod
E rsa/cli.py:85: error: Missing return statement [empty-body]
E rsa/cli.py:85: note: If the method is meant to be abstract, use @abc.abstractmethod
E rsa/cli.py:96: error: Incompatible types in assignment (expression has type "type[PrivateKey]", base class "CryptoOperation" defined the type as "type[PublicKey]") [assignment]
E rsa/cli.py:98: error: Missing return statement [empty-body]
E rsa/cli.py:98: note: If the method is meant to be abstract, use @abc.abstractmethod
E rsa/cli.py:110: error: Incompatible types in assignment (expression has type "type[PrivateKey]", base class "CryptoOperation" defined the type as "type[PublicKey]") [assignment]
E rsa/cli.py:114: error: Missing return statement [empty-body]
E rsa/cli.py:114: note: If the method is meant to be abstract, use @abc.abstractmethod
E Found 32 errors in 5 files (checked 28 source files)
E
E Mypy failed with status 1
tests/test_mypy.py:31: AssertionError
test_parallel.py::ParallelTest::test_parallel_primegen
test_parallel.py::ParallelTest::test_parallel_primegen
self =
def test_parallel_primegen(self):
p = rsa.parallel.getprime(1024, 3)
> self.assertFalse(rsa.prime.is_prime(p - 1))
E TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'
tests/test_parallel.py:16: TypeError
test_pem.py::TestBytesAndStrings::test_bytes_private
test_pem.py::TestBytesAndStrings::test_bytes_private
self =
def test_bytes_private(self):
key = rsa.key.PrivateKey.load_pkcs1(private_key_pem.encode("ascii"))
> self.assertEqual(prime1, key.p)
E AttributeError: 'NoneType' object has no attribute 'p'
tests/test_pem.py:71: AttributeError
test_pem.py::TestBytesAndStrings::test_bytes_public
test_pem.py::TestBytesAndStrings::test_bytes_public
self =
def test_bytes_public(self):
key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem.encode("ascii"))
> self.assertEqual(prime1 * prime2, key.n)
E AttributeError: 'NoneType' object has no attribute 'n'
tests/test_pem.py:63: AttributeError
test_pem.py::TestBytesAndStrings::test_unicode_private
test_pem.py::TestBytesAndStrings::test_unicode_private
self =
def test_unicode_private(self):
key = rsa.key.PrivateKey.load_pkcs1(private_key_pem)
> self.assertEqual(prime1 * prime2, key.n)
E AttributeError: 'NoneType' object has no attribute 'n'
tests/test_pem.py:67: AttributeError
test_pem.py::TestBytesAndStrings::test_unicode_public
test_pem.py::TestBytesAndStrings::test_unicode_public
self =
def test_unicode_public(self):
key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem)
> self.assertEqual(prime1 * prime2, key.n)
E AttributeError: 'NoneType' object has no attribute 'n'
tests/test_pem.py:59: AttributeError
test_pem.py::TestByteOutput::test_bytes_private
test_pem.py::TestByteOutput::test_bytes_private
self =
def test_bytes_private(self):
key = rsa.key.PrivateKey.load_pkcs1(private_key_pem)
> self.assertIsInstance(key.save_pkcs1(format="DER"), bytes)
E AttributeError: 'NoneType' object has no attribute 'save_pkcs1'
tests/test_pem.py:85: AttributeError
test_pem.py::TestByteOutput::test_bytes_public
test_pem.py::TestByteOutput::test_bytes_public
self =
def test_bytes_public(self):
key = rsa.key.PublicKey.load_pkcs1_openssl_pem(public_key_pem)
> self.assertIsInstance(key.save_pkcs1(format="DER"), bytes)
E AttributeError: 'NoneType' object has no attribute 'save_pkcs1'
tests/test_pem.py:80: AttributeError
test_pem.py::TestByteInput::test_bytes_private
self =
def test_bytes_private(self):
key = rsa.key.PrivateKey.load_pkcs1(private_key_pem.encode("ascii"))
> self.assertIsInstance(key.save_pkcs1(format="DER"), bytes)
E AttributeError: 'NoneType' object has no attribute 'save_pkcs1'
tests/test_pem.py:99: AttributeError
test_pem.py::TestByteInput::test_bytes_public
self =
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)
E AttributeError: 'NoneType' object has no attribute 'save_pkcs1'
tests/test_pem.py:94: AttributeError
test_pkcs1.py::BinaryTest::test_decoding_failure
test_pkcs1.py::BinaryTest::test_decoding_failure
self =
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] + bytes([altered_a]) + encrypted[6:]
> self.assertRaises(pkcs1.DecryptionError, pkcs1.decrypt, encrypted, self.priv)
tests/test_pkcs1.py:52:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:196: in decrypt
decrypted = priv_key.blinded_decrypt(encrypted)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def blinded_decrypt(self, encrypted: int) -> int:
"""Decrypts the message using blinding to prevent side-channel attacks.
:param encrypted: the encrypted message
:type encrypted: int
:returns: the decrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(encrypted)
> decrypted = core.decrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:375: NameError
test_pkcs1.py::BinaryTest::test_enc_dec
test_pkcs1.py::BinaryTest::test_enc_dec
self =
def test_enc_dec(self):
message = struct.pack(">IIII", 0, 0, 0, 1)
print("\n\tMessage: %r" % message)
encrypted = pkcs1.encrypt(message, self.pub)
print("\tEncrypted: %r" % encrypted)
> decrypted = pkcs1.decrypt(encrypted, self.priv)
tests/test_pkcs1.py:36:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:196: in decrypt
decrypted = priv_key.blinded_decrypt(encrypted)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(95614720695042764324427531959883658352389409168200043743716125771242804589173, 65537, 658712580585193220508...732761663741411725876717561437874473, 322908099193905263849242787816761600303, 296105055691484639329146938269366267291)
encrypted = 836805949104183130...6056738828867516451
def blinded_decrypt(self, encrypted: int) -> int:
"""Decrypts the message using blinding to prevent side-channel attacks.
:param encrypted: the encrypted message
:type encrypted: int
:returns: the decrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(encrypted)
> decrypted = core.decrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:375: NameError
test_pkcs1.py::ExtraZeroesTest::test_append_zeroes
self =
def test_append_zeroes(self):
cyphertext = self.cyphertext + bytes.fromhex("0000")
with self.assertRaises(rsa.DecryptionError):
> rsa.decrypt(cyphertext, self.private_key)
tests/test_pkcs1.py:90:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes:
"""Decrypts the given message using PKCS#1 v1.5
The decryption is considered 'failed' when the resulting cleartext doesn't
start with the bytes 00 02, or when the 00 byte between the padding and
the message cannot be found.
:param crypto: the crypto text as returned by :py:func:`rsa.encrypt`
:param priv_key: the :py:class:`rsa.PrivateKey` to decrypt with.
:raise DecryptionError: when the decryption fails. No details are given as
to why the code thinks the decryption fails, as this would leak
information about the private key.
>>> import rsa
>>> (pub_key, priv_key) = rsa.newkeys(256)
It works with strings:
>>> crypto = encrypt(b'hello', pub_key)
>>> decrypt(crypto, priv_key)
b'hello'
And with binary data:
>>> crypto = encrypt(b'\\x00\\x00\\x00\\x00\\x01', pub_key)
>>> decrypt(crypto, priv_key)
b'\\x00\\x00\\x00\\x00\\x01'
Altering the encrypted information will *likely* cause a
:py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use
:py:func:`rsa.sign`.
.. warning::
Never display the stack trace of a
:py:class:`rsa.pkcs1.DecryptionError` exception. It shows where in the
code the exception occurred, and thus leaks information about the key.
It's only a tiny bit of information, but every bit makes cracking the
keys easier.
>>> crypto = encrypt(b'hello', pub_key)
>>> crypto = crypto[0:5] + b'X' + crypto[6:] # change a byte
>>> decrypt(crypto, priv_key)
Traceback (most recent call last):
...
rsa.pkcs1.DecryptionError: Decryption failed
"""
> blocksize = common.byte_size(priv_key.n)
E AttributeError: 'NoneType' object has no attribute 'n'
rsa/pkcs1.py:194: AttributeError
test_pkcs1.py::ExtraZeroesTest::test_prepend_zeroes
self =
def test_prepend_zeroes(self):
cyphertext = bytes.fromhex("0000") + self.cyphertext
with self.assertRaises(rsa.DecryptionError):
> rsa.decrypt(cyphertext, self.private_key)
tests/test_pkcs1.py:85:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes:
"""Decrypts the given message using PKCS#1 v1.5
The decryption is considered 'failed' when the resulting cleartext doesn't
start with the bytes 00 02, or when the 00 byte between the padding and
the message cannot be found.
:param crypto: the crypto text as returned by :py:func:`rsa.encrypt`
:param priv_key: the :py:class:`rsa.PrivateKey` to decrypt with.
:raise DecryptionError: when the decryption fails. No details are given as
to why the code thinks the decryption fails, as this would leak
information about the private key.
>>> import rsa
>>> (pub_key, priv_key) = rsa.newkeys(256)
It works with strings:
>>> crypto = encrypt(b'hello', pub_key)
>>> decrypt(crypto, priv_key)
b'hello'
And with binary data:
>>> crypto = encrypt(b'\\x00\\x00\\x00\\x00\\x01', pub_key)
>>> decrypt(crypto, priv_key)
b'\\x00\\x00\\x00\\x00\\x01'
Altering the encrypted information will *likely* cause a
:py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use
:py:func:`rsa.sign`.
.. warning::
Never display the stack trace of a
:py:class:`rsa.pkcs1.DecryptionError` exception. It shows where in the
code the exception occurred, and thus leaks information about the key.
It's only a tiny bit of information, but every bit makes cracking the
keys easier.
>>> crypto = encrypt(b'hello', pub_key)
>>> crypto = crypto[0:5] + b'X' + crypto[6:] # change a byte
>>> decrypt(crypto, priv_key)
Traceback (most recent call last):
...
rsa.pkcs1.DecryptionError: Decryption failed
"""
> blocksize = common.byte_size(priv_key.n)
E AttributeError: 'NoneType' object has no attribute 'n'
rsa/pkcs1.py:194: AttributeError
test_pkcs1.py::ExtraZeroesTest::test_unmodified
self =
def test_unmodified(self):
> message = rsa.decrypt(self.cyphertext, self.private_key)
tests/test_pkcs1.py:79:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
crypto = b'E\x01\xb4\xd6i\xe0\x1b\x9e\xf2\xdc\x80\n\xa1\xb0mI\x19oZ\t\xfe\x8f\xbc\xd072<`\xea\xf0\'\xbf\xb9\x842\xbeNJ&\xc5g\xf...x86\x1e\x81\x02\x1be\n\x1d\xe5\x10\x02\xc3\x15\xf1\xe7\xc1-\xeb\xe4\xdc\xeb\xf7\x90\xca\xaaT\xa2\xf2k\x14\x9c\xf9\xe7}'
priv_key = None
def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes:
"""Decrypts the given message using PKCS#1 v1.5
The decryption is considered 'failed' when the resulting cleartext doesn't
start with the bytes 00 02, or when the 00 byte between the padding and
the message cannot be found.
:param crypto: the crypto text as returned by :py:func:`rsa.encrypt`
:param priv_key: the :py:class:`rsa.PrivateKey` to decrypt with.
:raise DecryptionError: when the decryption fails. No details are given as
to why the code thinks the decryption fails, as this would leak
information about the private key.
>>> import rsa
>>> (pub_key, priv_key) = rsa.newkeys(256)
It works with strings:
>>> crypto = encrypt(b'hello', pub_key)
>>> decrypt(crypto, priv_key)
b'hello'
And with binary data:
>>> crypto = encrypt(b'\\x00\\x00\\x00\\x00\\x01', pub_key)
>>> decrypt(crypto, priv_key)
b'\\x00\\x00\\x00\\x00\\x01'
Altering the encrypted information will *likely* cause a
:py:class:`rsa.pkcs1.DecryptionError`. If you want to be *sure*, use
:py:func:`rsa.sign`.
.. warning::
Never display the stack trace of a
:py:class:`rsa.pkcs1.DecryptionError` exception. It shows where in the
code the exception occurred, and thus leaks information about the key.
It's only a tiny bit of information, but every bit makes cracking the
keys easier.
>>> crypto = encrypt(b'hello', pub_key)
>>> crypto = crypto[0:5] + b'X' + crypto[6:] # change a byte
>>> decrypt(crypto, priv_key)
Traceback (most recent call last):
...
rsa.pkcs1.DecryptionError: Decryption failed
"""
> blocksize = common.byte_size(priv_key.n)
E AttributeError: 'NoneType' object has no attribute 'n'
rsa/pkcs1.py:194: AttributeError
test_pkcs1.py::SignatureTest::test_alter_message
test_pkcs1.py::SignatureTest::test_alter_message
self =
def test_alter_message(self):
"""Altering the message should let the verification fail."""
> signature = pkcs1.sign(b"je moeder", self.priv, "SHA-256")
tests/test_pkcs1.py:123:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(12982770477732206231002065472644628732355165926074488211477571291118499825488635362931509618974219355121679...43281742064090705882928042129412760323, 112871977475489262537336750872172921003829494611758584825372855732961618385741)
message = 409173825987017733...9681456309543691530
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_apppend_zeroes
test_pkcs1.py::SignatureTest::test_apppend_zeroes
self =
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")
tests/test_pkcs1.py:180:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(69053056860840701657005268949532753375582488726430047412717988854773107682431009095996011955376408565163068...792070978038295005517486012832303832449, 71618209829853038536082281327901022242997997287918307202354740774340698639123)
message = 409173825987017733...9681456309543691530
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_find_signature_hash
test_pkcs1.py::SignatureTest::test_find_signature_hash
self =
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")
tests/test_pkcs1.py:116:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(73668105939698565717130057463911336069997927141990904100106727281840882635120378680395728172928117231374214...003566069958816649877345091643144822571, 74489001441796341172787301664724673881934341018560627749381364895683701845831)
message = 409173825987017733...9681456309543691530
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_hash_sign_verify
test_pkcs1.py::SignatureTest::test_hash_sign_verify
self =
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")
tests/test_pkcs1.py:163:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(10191165817517998816421103470165366841864312679595289237071024126622889650629139578253770265256848291240143...118953045129160050954393415190143236967, 92163270658656317716018450096305425072747381421774495955195233596668343628737)
message = 409173825987017733...4743180718120711231
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_multiple_signings
test_pkcs1.py::SignatureTest::test_multiple_signings
self =
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")
tests/test_pkcs1.py:141:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(10747271424381222220765106125214290348353074725562107531952458608769650986530759582057213542081004063693193...252788395643746079665670704277818850423, 93006824697380217678374301436209044688627043787374058089919936286322174125727)
message = 409173825987017733...9656193183751328884
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_prepend_zeroes
test_pkcs1.py::SignatureTest::test_prepend_zeroes
self =
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")
tests/test_pkcs1.py:171:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(88912840433250517262724650859124454694236109736127789150734610904619999757479024839991186507201581713487051...772925379299992249527352523496249329879, 82418757054176614484704104321547814990347680164618615039222476824876656554909)
message = 409173825987017733...9681456309543691530
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_sign_different_key
test_pkcs1.py::SignatureTest::test_sign_different_key
self =
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")
tests/test_pkcs1.py:134:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(11010156951753028146951272511504599382722513352748163457818184490794840695189648816560295411591799294419814...30548431737087657367791140209263066433, 103848699458135744899137814569259843949465161457614752187476400989542058526579)
message = 409173825987017733...9681456309543691530
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_sign_verify
test_pkcs1.py::SignatureTest::test_sign_verify
self =
def test_sign_verify(self):
"""Test happy flow of sign and verify"""
message = b"je moeder"
> signature = pkcs1.sign(message, self.priv, "SHA-256")
tests/test_pkcs1.py:101:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(71351459838344004218830923561339435966780306809395333420975156488891876277266597795877370889220223812541915...946707088114522457785567944113611872341, 79809983599713256253062862891990367028474247091133287133398805798894309518143)
message = 409173825987017733...9681456309543691530
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_sign_verify_sha3
test_pkcs1.py::SignatureTest::test_sign_verify_sha3
self =
@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")
tests/test_pkcs1.py:109:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:282: in sign
return sign_hash(hasher.digest(), priv_key, hash_method)
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(69737252947676194748517631426714582022156145151810356465027077430558159859113784530928019737364289156147029...078228792979507203575692296413728845121, 77556222637620107926454494045523472235503694526581262112491081851016131159907)
message = 409173825987017733...6161036184995569769
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::SignatureTest::test_split_hash_sign
test_pkcs1.py::SignatureTest::test_split_hash_sign
self =
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")
tests/test_pkcs1.py:151:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:243: in sign_hash
encrypted = priv_key.blinded_encrypt(payload)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(78422484899469105162369493802767799804724930916688815210646725354538257676415209517342169001543332315941778...795466580967815887920274906984932775759, 84634047710423740384130299839741213212556643265546611595857042922496199179071)
message = 409173825987017733...9681456309543691530
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
:param message: the message to encrypt
:type message: int
:returns: the encrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(message)
> encrypted = core.encrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:388: NameError
test_pkcs1.py::PaddingSizeTest::test_too_little_padding
test_pkcs1.py::PaddingSizeTest::test_too_little_padding
self =
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)
E AttributeError: 'NoneType' object has no attribute 'n'
tests/test_pkcs1.py:201: AttributeError
test_pkcs1_v2.py::MGFTest::test_invalid_hasher
test_pkcs1_v2.py::MGFTest::test_invalid_hasher
self =
def test_invalid_hasher(self):
"""Tests an invalid hasher generates an exception"""
> with self.assertRaises(ValueError):
E AssertionError: ValueError not raised
tests/test_pkcs1_v2.py:74: AssertionError
test_pkcs1_v2.py::MGFTest::test_invalid_length
test_pkcs1_v2.py::MGFTest::test_invalid_length
self =
def test_invalid_length(self):
> with self.assertRaises(OverflowError):
E AssertionError: OverflowError not raised
tests/test_pkcs1_v2.py:78: AssertionError
test_pkcs1_v2.py::MGFTest::test_oaep_int_db_mask
test_pkcs1_v2.py::MGFTest::test_oaep_int_db_mask
self =
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)
E AssertionError: None != b'\x06\xe1\xde\xb26\x9a\xa5\xa5\xc7\x07\x[292 chars]x12d'
tests/test_pkcs1_v2.py:62: AssertionError
test_prime.py::PrimeTest::test_miller_rabin_primality_testing
test_prime.py::PrimeTest::test_miller_rabin_primality_testing
self =
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))
tests/test_prime.py:61:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/prime.py:74: in miller_rabin_primality_testing
a = rsa.randnum.randint(n - 2)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
maxvalue = 2787998639
def fake_randint(maxvalue):
> return randints.pop(0)
E IndexError: pop from empty list
tests/test_prime.py:54: IndexError
test_strings.py::StringTest::test_enc_dec
test_strings.py::StringTest::test_enc_dec
self =
def test_enc_dec(self):
message = unicode_string.encode("utf-8")
print("\n\tMessage: %r" % message)
encrypted = rsa.encrypt(message, self.pub)
print("\tEncrypted: %r" % encrypted)
> decrypted = rsa.decrypt(encrypted, self.priv)
tests/test_strings.py:37:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rsa/pkcs1.py:196: in decrypt
decrypted = priv_key.blinded_decrypt(encrypted)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PrivateKey(20766974548921856241411339435616572405041482269057613764614839697998178621450548526140313641466095125857871...4773649727991992191001035218882070906647880475693047505233, 4350334802980478104235794525867776264731199692791408949683)
encrypted = 106404939315780522...3989547512628923930
def blinded_decrypt(self, encrypted: int) -> int:
"""Decrypts the message using blinding to prevent side-channel attacks.
:param encrypted: the encrypted message
:type encrypted: int
:returns: the decrypted message
:rtype: int
"""
blinded, blindfac_inverse = self.blind(encrypted)
> decrypted = core.decrypt_int(blinded, self.d, self.n)
E NameError: name 'core' is not defined
rsa/key.py:375: NameError
Patch diff
diff --git a/EncryptDecryptTest.pub b/EncryptDecryptTest.pub
new file mode 100644
index 0000000..e69de29
diff --git a/KeygenTest.pub b/KeygenTest.pub
new file mode 100644
index 0000000..e69de29
diff --git a/PrivatePublicTest.pub b/PrivatePublicTest.pub
new file mode 100644
index 0000000..e69de29
diff --git a/SignVerifyTest.pub b/SignVerifyTest.pub
new file mode 100644
index 0000000..e69de29
diff --git a/rsa/common.py b/rsa/common.py
index 3a3066b..bfd01de 100644
--- a/rsa/common.py
+++ b/rsa/common.py
@@ -30,7 +30,11 @@ def bit_size(num: int) -> int:
:returns:
Returns the number of bits in the integer.
"""
- pass
+ if not isinstance(num, int):
+ raise TypeError("Number must be an integer")
+ if num == 0:
+ return 0
+ return abs(num).bit_length()
def byte_size(number: int) -> int:
"""
@@ -52,7 +56,13 @@ def byte_size(number: int) -> int:
:returns:
The number of bytes required to hold a specific long number.
"""
- pass
+ if not isinstance(number, int):
+ raise TypeError("Number must be an integer")
+ if number < 0:
+ raise ValueError("Number must be an unsigned integer")
+ if number == 0:
+ return 1
+ return ceil_div(bit_size(number), 8)
def ceil_div(num: int, div: int) -> int:
"""
@@ -72,11 +82,33 @@ def ceil_div(num: int, div: int) -> int:
:return: Rounded up result of the division between the parameters.
"""
- pass
+ quanta, mod = divmod(num, div)
+ if mod:
+ quanta += 1
+ return quanta
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"""
- pass
+ # 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
+ # Iterative Version
+ x = 0
+ y = 1
+ lx = 1
+ ly = 0
+ oa = a # Remember original a/b to remove
+ ob = b # negative values from return results
+ while b != 0:
+ q = a // b
+ (a, b) = (b, a % b)
+ (x, lx) = ((lx - (q * x)), x)
+ (y, ly) = ((ly - (q * y)), y)
+ if lx < 0:
+ lx += ob # If neg wrap modulo original b
+ if ly < 0:
+ ly += oa # If neg wrap modulo original a
+ return a, lx, ly # Return only positive values
def inverse(x: int, n: int) -> int:
"""Returns the inverse of x % n under multiplication, a.k.a x^-1 (mod n)
@@ -86,7 +118,10 @@ def inverse(x: int, n: int) -> int:
>>> (inverse(143, 4) * 143) % 4
1
"""
- pass
+ gcd, a, _ = extended_gcd(x, n)
+ if gcd != 1:
+ raise NotRelativePrimeError(x, n, gcd)
+ return a % n
def crt(a_values: typing.Iterable[int], modulo_values: typing.Iterable[int]) -> int:
"""Chinese Remainder Theorem.
@@ -107,7 +142,26 @@ def crt(a_values: typing.Iterable[int], modulo_values: typing.Iterable[int]) ->
>>> crt([2, 3, 0], [7, 11, 15])
135
"""
- pass
+ a_values = list(a_values)
+ modulo_values = list(modulo_values)
+
+ if len(a_values) != len(modulo_values):
+ raise ValueError("Number of a values must match number of modulo values")
+
+ # Calculate product of all moduli
+ prod = 1
+ for modulus in modulo_values:
+ prod *= modulus
+
+ # Calculate sum of a[i] * b[i] * r[i] where:
+ # b[i] = prod / m[i]
+ # r[i] = multiplicative inverse of b[i] mod m[i]
+ total = 0
+ for i, (a_i, m_i) in enumerate(zip(a_values, modulo_values)):
+ p = prod // m_i
+ total += a_i * p * inverse(p, m_i)
+
+ return total % prod
if __name__ == '__main__':
import doctest
doctest.testmod()
\ No newline at end of file
diff --git a/rsa/core.py b/rsa/core.py
index da6bc40..9496220 100644
--- a/rsa/core.py
+++ b/rsa/core.py
@@ -6,8 +6,8 @@ mathematically on integers.
def encrypt_int(message: int, ekey: int, n: int) -> int:
"""Encrypts a message using encryption key 'ekey', working modulo n"""
- pass
+ return pow(message, ekey, n)
def decrypt_int(cyphertext: int, dkey: int, n: int) -> int:
"""Decrypts a cypher text using the decryption key 'dkey', working modulo n"""
- pass
\ No newline at end of file
+ return pow(cyphertext, dkey, n)
\ No newline at end of file
diff --git a/rsa/key.py b/rsa/key.py
index 5af0506..27cf041 100644
--- a/rsa/key.py
+++ b/rsa/key.py
@@ -120,7 +120,12 @@ class AbstractKey:
See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
"""
- pass
+ with self.mutex:
+ if self.blindfac < 0:
+ self.blindfac, self.blindfac_inverse = self._update_blinding_factor()
+
+ blinded = (message * pow(self.blindfac, self.e, self.n)) % self.n
+ return blinded, self.blindfac_inverse
def unblind(self, blinded: int, blindfac_inverse: int) -> int:
"""Performs blinding on the message using random number 'blindfac_inverse'.
@@ -133,7 +138,7 @@ class AbstractKey:
See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
"""
- pass
+ return (blindfac_inverse * blinded) % self.n
def _update_blinding_factor(self) -> typing.Tuple[int, int]:
"""Update blinding factors.
@@ -146,7 +151,13 @@ class AbstractKey:
:return: the new blinding factor and its inverse.
"""
- pass
+ # Generate a random number between 2 and n-1
+ blindfac = rsa.randnum.randint(self.n - 2)
+
+ # Calculate its inverse
+ blindfac_inverse = rsa.common.inverse(blindfac, self.n)
+
+ return blindfac, blindfac_inverse
class PublicKey(AbstractKey):
"""Represents a public RSA key.
@@ -221,7 +232,17 @@ class PublicKey(AbstractKey):
PublicKey(2367317549, 65537)
"""
- pass
+ from pyasn1.codec.der import decoder
+ from rsa.asn1 import AsnPubKey
+
+ # Decode the DER file
+ (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())
+
+ # Get the numbers
+ n = int(priv['modulus'])
+ e = int(priv['publicExponent'])
+
+ return cls(n, e)
def _save_pkcs1_der(self) -> bytes:
"""Saves the public key in PKCS#1 DER format.
@@ -350,7 +371,9 @@ class PrivateKey(AbstractKey):
:returns: the decrypted message
:rtype: int
"""
- pass
+ blinded, blindfac_inverse = self.blind(encrypted)
+ decrypted = core.decrypt_int(blinded, self.d, self.n)
+ return self.unblind(decrypted, blindfac_inverse)
def blinded_encrypt(self, message: int) -> int:
"""Encrypts the message using blinding to prevent side-channel attacks.
@@ -361,7 +384,9 @@ class PrivateKey(AbstractKey):
:returns: the encrypted message
:rtype: int
"""
- pass
+ blinded, blindfac_inverse = self.blind(message)
+ encrypted = core.encrypt_int(blinded, self.d, self.n)
+ return self.unblind(encrypted, blindfac_inverse)
@classmethod
def _load_pkcs1_der(cls, keyfile: bytes) -> 'PrivateKey':
@@ -446,7 +471,29 @@ def find_p_q(nbits: int, getprime_func: typing.Callable[[int], int]=rsa.prime.ge
True
"""
- pass
+ total_bits = nbits * 2
+
+ # Make sure we have two different primes
+ while True:
+ p = getprime_func(nbits)
+ q = getprime_func(nbits)
+ if p == q:
+ continue
+
+ # Make sure we have the right number of bits
+ if accurate:
+ if rsa.common.bit_size(p * q) != total_bits:
+ continue
+ else:
+ # As long as we're within 16 bits of the desired size, we're good
+ found_size = rsa.common.bit_size(p * q)
+ if found_size > total_bits or found_size < (total_bits - 16):
+ continue
+
+ # Return the largest first
+ if p > q:
+ return p, q
+ return q, p
def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tuple[int, int]:
"""Calculates an encryption and a decryption key given p, q and an exponent,
@@ -460,7 +507,17 @@ def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tupl
:type exponent: int
"""
- pass
+ phi_n = (p - 1) * (q - 1)
+
+ try:
+ d = rsa.common.inverse(exponent, phi_n)
+ except rsa.common.NotRelativePrimeError as ex:
+ raise ValueError("e and phi_n are not relatively prime", ex)
+
+ if (exponent * d) % phi_n != 1:
+ raise ValueError("e and d are not multiplicative inverses")
+
+ return exponent, d
def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]:
"""Calculates an encryption and a decryption key given p and q, and
@@ -471,7 +528,7 @@ def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]:
:return: tuple (e, d) with the encryption and decryption exponents.
"""
- pass
+ 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]:
"""Generate RSA keys of nbits bits. Returns (p, q, e, d).
@@ -487,7 +544,16 @@ def gen_keys(nbits: int, getprime_func: typing.Callable[[int], int], accurate: b
private key can be cracked. A very common choice for e is 65537.
:type exponent: int
"""
- pass
+ # Size of each prime number
+ bits_per_prime = nbits // 2
+
+ # Get p and q
+ p, q = find_p_q(bits_per_prime, getprime_func, accurate)
+
+ # Get encryption and decryption exponents
+ e, d = calculate_keys_custom_exponent(p, q, exponent)
+
+ return p, q, e, d
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).
@@ -498,11 +564,12 @@ def newkeys(nbits: int, accurate: bool=True, poolsize: int=1, exponent: int=DEFA
:param nbits: the number of bits required to store ``n = p*q``.
:param accurate: when True, ``n`` will have exactly the number of bits you
- asked for. However, this makes key generation much slower. When False,
- `n`` may have slightly less bits.
+ asked for. However, this can be a problem when using the RSA algorithm as
+ part of a protocol where others are expecting a certain minimum number of
+ bits. In that case, use accurate=False.
:param poolsize: the number of processes to use to generate the prime
- numbers. If set to a number > 1, a parallel algorithm will be used.
- This requires Python 2.6 or newer.
+ numbers. If set to a number > 1, then that many processes will be
+ created to generate the prime numbers in parallel.
:param exponent: the exponent for the key; only change this if you know
what you're doing, as the exponent influences how difficult your
private key can be cracked. A very common choice for e is 65537.
@@ -514,18 +581,29 @@ def newkeys(nbits: int, accurate: bool=True, poolsize: int=1, exponent: int=DEFA
Python 2.6 or newer.
"""
- pass
-__all__ = ['PublicKey', 'PrivateKey', 'newkeys']
+ if nbits < 16:
+ raise ValueError('Key too small')
+
+ if poolsize < 1:
+ raise ValueError('Pool size (%i) should be >= 1' % poolsize)
+
+ # If poolsize is 1, don't use multiprocessing
+ if poolsize == 1:
+ prime_func = rsa.prime.getprime
+ else:
+ from rsa import parallel
+ prime_func = parallel.getprime
+
+ # Generate the key components
+ p, q, e, d = gen_keys(nbits, prime_func, accurate=accurate, exponent=exponent)
+
+ # Create the key objects
+ n = p * q
+
+ return (
+ PublicKey(n, e),
+ PrivateKey(n, e, d, p, q)
+ )
if __name__ == '__main__':
import doctest
- try:
- for count in range(100):
- failures, tests = doctest.testmod()
- if failures:
- break
- if count % 10 == 0 and count or count == 1:
- print('%i times' % count)
- except KeyboardInterrupt:
- print('Aborted')
- else:
- print('Doctests done')
\ No newline at end of file
+ doctest.testmod()
\ No newline at end of file
diff --git a/rsa/pem.py b/rsa/pem.py
index 732a4e2..a54015c 100644
--- a/rsa/pem.py
+++ b/rsa/pem.py
@@ -7,11 +7,56 @@ def _markers(pem_marker: FlexiText) -> typing.Tuple[bytes, bytes]:
"""
Returns the start and end PEM markers, as bytes.
"""
- pass
+ if isinstance(pem_marker, str):
+ pem_marker = pem_marker.encode('ascii')
+
+ 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]:
"""Generator over PEM lines between pem_start and pem_end."""
- pass
+ in_pem_part = False
+ seen_pem_start = False
+
+ for line in contents.splitlines():
+ line = line.strip()
+
+ # Skip empty lines
+ if not line:
+ continue
+
+ # Handle start marker
+ if line == pem_start:
+ if in_pem_part:
+ raise ValueError('Seen start marker "%s" twice' % pem_start)
+
+ in_pem_part = True
+ seen_pem_start = True
+ continue
+
+ # Skip stuff before first marker
+ if not in_pem_part:
+ continue
+
+ # Handle end marker
+ if line == pem_end:
+ in_pem_part = False
+ break
+
+ # Skip stuff after end marker
+ if not in_pem_part:
+ continue
+
+ # Load the base64 data
+ yield line
+
+ if not seen_pem_start:
+ raise ValueError('No PEM start marker "%s" found' % pem_start)
+
+ if in_pem_part:
+ raise ValueError('No PEM end marker "%s" found' % pem_end)
def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes:
"""Loads a PEM file.
@@ -27,7 +72,19 @@ def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes:
marker cannot be found.
"""
- pass
+ # Convert strings to bytes
+ if isinstance(contents, str):
+ contents = contents.encode('ascii')
+
+ # Get the start and end markers
+ pem_start, pem_end = _markers(pem_marker)
+
+ # Get all lines between the markers
+ pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)]
+
+ # Base64-decode the contents
+ pem = b''.join(pem_lines)
+ return base64.standard_b64decode(pem)
def save_pem(contents: bytes, pem_marker: FlexiText) -> bytes:
"""Saves a PEM file.
@@ -40,4 +97,17 @@ def save_pem(contents: bytes, pem_marker: FlexiText) -> bytes:
:return: the base64-encoded content between the start and end markers, as bytes.
"""
- pass
\ No newline at end of file
+ # Get the start and end markers
+ pem_start, pem_end = _markers(pem_marker)
+
+ # Base64-encode the contents
+ b64 = base64.standard_b64encode(contents).replace(b'\n', b'')
+
+ # Split into lines of 64 characters each
+ chunks = [b64[i:i + 64] for i in range(0, len(b64), 64)]
+
+ # Create output
+ lines = [pem_start, b''] + chunks + [b'', pem_end]
+
+ # Combine all lines
+ return b'\n'.join(lines)
\ No newline at end of file
diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py
index c7529c4..d9187f8 100644
--- a/rsa/pkcs1.py
+++ b/rsa/pkcs1.py
@@ -51,7 +51,33 @@ def _pad_for_encryption(message: bytes, target_length: int) -> bytes:
b'\\x00hello'
"""
- pass
+ max_msglength = target_length - 11
+ msglength = len(message)
+
+ if msglength > max_msglength:
+ raise OverflowError('%i bytes needed for message, but there is only'
+ ' space for %i' % (msglength, max_msglength))
+
+ # Get random padding
+ padding_length = target_length - msglength - 3
+ padding = b''
+
+ # We remove 0-bytes, so we'll end up with less padding than we've asked for,
+ # so keep adding data until we're at the correct length.
+ while len(padding) < padding_length:
+ needed_bytes = padding_length - len(padding)
+
+ # Get some random bytes
+ new_padding = os.urandom(needed_bytes + 5)
+
+ # Remove the 0-bytes, and add them to our padding
+ new_padding = bytes(b for b in new_padding if b != 0)
+ padding = padding + new_padding[:needed_bytes]
+
+ return b''.join([b'\x00\x02',
+ padding,
+ b'\x00',
+ message])
def _pad_for_signing(message: bytes, target_length: int) -> bytes:
"""Pads the message for signing, returning the padded message.
@@ -71,7 +97,19 @@ def _pad_for_signing(message: bytes, target_length: int) -> bytes:
b'\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff'
"""
- pass
+ max_msglength = target_length - 11
+ msglength = len(message)
+
+ if 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])
def encrypt(message: bytes, pub_key: key.PublicKey) -> bytes:
"""Encrypts the given message using PKCS#1 v1.5
@@ -94,7 +132,14 @@ def encrypt(message: bytes, pub_key: key.PublicKey) -> bytes:
True
"""
- pass
+ keylength = common.byte_size(pub_key.n)
+ padded = _pad_for_encryption(message, keylength)
+
+ payload = transform.bytes2int(padded)
+ encrypted = core.encrypt_int(payload, pub_key.e, pub_key.n)
+ block = transform.int2bytes(encrypted, keylength)
+
+ return block
def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes:
"""Decrypts the given message using PKCS#1 v1.5
@@ -146,7 +191,25 @@ def decrypt(crypto: bytes, priv_key: key.PrivateKey) -> bytes:
rsa.pkcs1.DecryptionError: Decryption failed
"""
- pass
+ blocksize = common.byte_size(priv_key.n)
+ encrypted = transform.bytes2int(crypto)
+ decrypted = priv_key.blinded_decrypt(encrypted)
+ cleartext = transform.int2bytes(decrypted, blocksize)
+
+ # Check for proper padding
+ if len(cleartext) != blocksize:
+ raise DecryptionError('Decryption failed')
+
+ if cleartext[0:2] != b'\x00\x02':
+ raise DecryptionError('Decryption failed')
+
+ # Find the 00 separator between the padding and the message
+ try:
+ sep_idx = cleartext.index(b'\x00', 2)
+ except ValueError:
+ raise DecryptionError('Decryption failed')
+
+ return cleartext[sep_idx + 1:]
def sign_hash(hash_value: bytes, priv_key: key.PrivateKey, hash_method: str) -> bytes:
"""Signs a precomputed hash with the private key.
@@ -163,7 +226,24 @@ def sign_hash(hash_value: bytes, priv_key: key.PrivateKey, hash_method: str) ->
requested hash.
"""
- pass
+ # Get the ASN1 code for this hash method
+ if hash_method not in HASH_ASN1:
+ raise ValueError('Invalid hash method: %s' % hash_method)
+ asn1code = HASH_ASN1[hash_method]
+
+ # Combine the ASN1 code for the hash method with the actual hash
+ asn1_hash = asn1code + hash_value
+
+ # Pad the hash to match the key size
+ keylength = common.byte_size(priv_key.n)
+ padded = _pad_for_signing(asn1_hash, keylength)
+
+ # Sign the message
+ payload = transform.bytes2int(padded)
+ encrypted = priv_key.blinded_encrypt(payload)
+ block = transform.int2bytes(encrypted, keylength)
+
+ return block
def sign(message: bytes, priv_key: key.PrivateKey, hash_method: str) -> bytes:
"""Signs the message with the private key.
@@ -182,7 +262,24 @@ def sign(message: bytes, priv_key: key.PrivateKey, hash_method: str) -> bytes:
requested hash.
"""
- pass
+ # Get the hash method
+ if hash_method not in HASH_METHODS:
+ raise ValueError('Invalid hash method: %s' % hash_method)
+ method = HASH_METHODS[hash_method]
+
+ # Calculate the hash
+ hasher = method()
+ if hasattr(message, 'read'):
+ while True:
+ chunk = message.read(1024)
+ if not chunk:
+ break
+ hasher.update(chunk)
+ else:
+ hasher.update(message)
+
+ # Sign the hash
+ return sign_hash(hasher.digest(), priv_key, hash_method)
def verify(message: bytes, signature: bytes, pub_key: key.PublicKey) -> str:
"""Verifies that the signature matches the message.
@@ -198,7 +295,52 @@ def verify(message: bytes, signature: bytes, pub_key: key.PublicKey) -> str:
:returns: the name of the used hash.
"""
- pass
+ # Get the hash method
+ hash_method = find_signature_hash(signature, pub_key)
+ method = HASH_METHODS[hash_method]
+
+ # Calculate the hash
+ hasher = method()
+ if hasattr(message, 'read'):
+ while True:
+ chunk = message.read(1024)
+ if not chunk:
+ break
+ hasher.update(chunk)
+ else:
+ hasher.update(message)
+
+ # Verify the hash
+ message_hash = hasher.digest()
+ blocksize = common.byte_size(pub_key.n)
+ encrypted = transform.bytes2int(signature)
+ decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
+ clearsig = transform.int2bytes(decrypted, blocksize)
+
+ # Get the hash method
+ if len(clearsig) != blocksize:
+ raise VerificationError('Verification failed')
+
+ if clearsig[0:2] != b'\x00\x01':
+ raise VerificationError('Verification failed')
+
+ # Find the 00 separator between the padding and the message
+ try:
+ sep_idx = clearsig.index(b'\x00', 2)
+ except ValueError:
+ raise VerificationError('Verification failed')
+
+ # Get the hash and the hash method from the signature
+ clearsig = clearsig[sep_idx + 1:]
+ if not clearsig.startswith(HASH_ASN1[hash_method]):
+ raise VerificationError('Verification failed')
+
+ # Get the actual hash
+ signed_hash = clearsig[len(HASH_ASN1[hash_method]):]
+ if not compare_digest(signed_hash, message_hash):
+ raise VerificationError('Verification failed')
+
+ return hash_method
def find_signature_hash(signature: bytes, pub_key: key.PublicKey) -> str:
"""Returns the hash name detected from the signature.
@@ -210,7 +352,31 @@ def find_signature_hash(signature: bytes, pub_key: key.PublicKey) -> str:
:param pub_key: the :py:class:`rsa.PublicKey` of the person signing the message.
:returns: the name of the used hash.
"""
- pass
+ blocksize = common.byte_size(pub_key.n)
+ encrypted = transform.bytes2int(signature)
+ decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
+ clearsig = transform.int2bytes(decrypted, blocksize)
+
+ # Get the hash method
+ if len(clearsig) != blocksize:
+ raise VerificationError('Verification failed')
+
+ if clearsig[0:2] != b'\x00\x01':
+ raise VerificationError('Verification failed')
+
+ # Find the 00 separator between the padding and the message
+ try:
+ sep_idx = clearsig.index(b'\x00', 2)
+ except ValueError:
+ raise VerificationError('Verification failed')
+
+ # Get the hash method from the signature
+ asn1_hash = clearsig[sep_idx + 1:]
+ for (hash_method, asn1code) in HASH_ASN1.items():
+ if asn1_hash.startswith(asn1code):
+ return hash_method
+
+ raise VerificationError('Verification failed')
def yield_fixedblocks(infile: typing.BinaryIO, blocksize: int) -> typing.Iterator[bytes]:
"""Generator, yields each block of ``blocksize`` bytes in the input file.
@@ -219,7 +385,11 @@ def yield_fixedblocks(infile: typing.BinaryIO, blocksize: int) -> typing.Iterato
:param blocksize: block size in bytes.
:returns: a generator that yields the contents of each block
"""
- pass
+ while True:
+ block = infile.read(blocksize)
+ if not block:
+ break
+ yield block
def compute_hash(message: typing.Union[bytes, typing.BinaryIO], method_name: str) -> bytes:
"""Returns the message digest.
@@ -231,7 +401,22 @@ def compute_hash(message: typing.Union[bytes, typing.BinaryIO], method_name: str
:py:const:`rsa.pkcs1.HASH_METHODS`.
"""
- pass
+ if method_name not in HASH_METHODS:
+ raise ValueError('Invalid hash method: %s' % method_name)
+
+ method = HASH_METHODS[method_name]
+ hasher = method()
+
+ if hasattr(message, 'read'):
+ while True:
+ chunk = message.read(1024)
+ if not chunk:
+ break
+ hasher.update(chunk)
+ else:
+ hasher.update(message)
+
+ return hasher.digest()
def _find_method_hash(clearsig: bytes) -> str:
"""Finds the hash method.
@@ -240,7 +425,11 @@ def _find_method_hash(clearsig: bytes) -> str:
:return: the used hash method.
:raise VerificationFailed: when the hash method cannot be found
"""
- pass
+ for (hash_method, asn1code) in HASH_ASN1.items():
+ if clearsig.startswith(asn1code):
+ return hash_method
+
+ raise VerificationError('Verification failed')
__all__ = ['encrypt', 'decrypt', 'sign', 'verify', 'DecryptionError', 'VerificationError', 'CryptoError']
if __name__ == '__main__':
print('Running doctests 1000x or until failure')
diff --git a/rsa/prime.py b/rsa/prime.py
index 7c4ea38..485b9b0 100644
--- a/rsa/prime.py
+++ b/rsa/prime.py
@@ -13,7 +13,9 @@ def gcd(p: int, q: int) -> int:
>>> gcd(48, 180)
12
"""
- pass
+ while q != 0:
+ p, q = q, p % q
+ return p
def get_primality_testing_rounds(number: int) -> int:
"""Returns minimum number of rounds for Miller-Rabing primality testing,
@@ -27,7 +29,18 @@ def get_primality_testing_rounds(number: int) -> int:
* p, q bitsize: 1536; rounds: 3
See: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
"""
- pass
+ # Calculate bit size of the number
+ bit_size = rsa.common.bit_size(number)
+
+ # Return number of rounds based on bit size
+ if bit_size >= 1536:
+ return 3
+ if bit_size >= 1024:
+ return 4
+ if bit_size >= 512:
+ return 7
+ # For smaller bit sizes, use more rounds for better security
+ return 10
def miller_rabin_primality_testing(n: int, k: int) -> bool:
"""Calculates whether n is composite (which is always correct) or prime
@@ -44,7 +57,32 @@ def miller_rabin_primality_testing(n: int, k: int) -> bool:
:return: False if the number is composite, True if it's probably prime.
:rtype: bool
"""
- pass
+ if n == 2 or n == 3:
+ return True
+ if n < 2 or n % 2 == 0:
+ return False
+
+ # Write n-1 as d * 2^r by factoring powers of 2 from n-1
+ r = 0
+ d = n - 1
+ while d % 2 == 0:
+ r += 1
+ d //= 2
+
+ # Test k witnesses
+ for _ in range(k):
+ a = rsa.randnum.randint(n - 2)
+ x = pow(a, d, n)
+ if x == 1 or x == n - 1:
+ continue
+
+ for _ in range(r - 1):
+ x = pow(x, 2, n)
+ if x == n - 1:
+ break
+ else:
+ return False
+ return True
def is_prime(number: int) -> bool:
"""Returns True if the number is prime, and False otherwise.
@@ -56,7 +94,17 @@ def is_prime(number: int) -> bool:
>>> is_prime(41)
True
"""
- pass
+ # Handle small numbers
+ if number < 2:
+ return False
+ if number == 2:
+ return True
+ if number % 2 == 0:
+ return False
+
+ # Get number of rounds for Miller-Rabin testing
+ rounds = get_primality_testing_rounds(number)
+ return miller_rabin_primality_testing(number, rounds)
def getprime(nbits: int) -> int:
"""Returns a prime number that can be stored in 'nbits' bits.
@@ -73,7 +121,14 @@ def getprime(nbits: int) -> int:
>>> common.bit_size(p) == 128
True
"""
- pass
+ # Keep generating random numbers until we find a prime
+ while True:
+ # Generate a random number with nbits bits
+ integer = rsa.randnum.read_random_odd_int(nbits)
+
+ # Test for primality
+ if is_prime(integer):
+ return integer
def are_relatively_prime(a: int, b: int) -> bool:
"""Returns True if a and b are relatively prime, and False if they
@@ -84,7 +139,7 @@ def are_relatively_prime(a: int, b: int) -> bool:
>>> are_relatively_prime(2, 4)
False
"""
- pass
+ return gcd(a, b) == 1
if __name__ == '__main__':
print('Running doctests 1000x or until failure')
import doctest
diff --git a/rsa/randnum.py b/rsa/randnum.py
index 595dbf4..60f044d 100644
--- a/rsa/randnum.py
+++ b/rsa/randnum.py
@@ -9,11 +9,22 @@ def read_random_bits(nbits: int) -> bytes:
If nbits isn't a whole number of bytes, an extra byte will be appended with
only the lower bits set.
"""
- pass
+ nbytes, rbits = divmod(nbits, 8)
+
+ # Get the random bytes
+ randomdata = os.urandom(nbytes)
+
+ # Add the remaining random bits
+ if rbits > 0:
+ randomvalue = ord(os.urandom(1))
+ randomvalue >>= (8 - rbits)
+ randomdata = bytes([randomvalue]) + randomdata
+
+ return randomdata
def read_random_int(nbits: int) -> int:
"""Reads a random integer of approximately nbits bits."""
- pass
+ return transform.bytes2int(read_random_bits(nbits))
def read_random_odd_int(nbits: int) -> int:
"""Reads a random odd integer of approximately nbits bits.
@@ -21,13 +32,28 @@ def read_random_odd_int(nbits: int) -> int:
>>> read_random_odd_int(512) & 1
1
"""
- pass
+ value = read_random_int(nbits)
+
+ # Make sure it's odd
+ return value | 1
-def randint(maxvalue: int) -> int:
- """Returns a random integer x with 1 <= x <= maxvalue
+def randint(maxvalue: int, minvalue: int=1) -> int:
+ """Returns a random integer x with minvalue <= x <= maxvalue
May take a very long time in specific situations. If maxvalue needs N bits
to store, the closer maxvalue is to (2 ** N) - 1, the faster this function
is.
"""
- pass
\ No newline at end of file
+ if minvalue > maxvalue:
+ raise ValueError("minvalue must be <= maxvalue")
+
+ # Get the number of bits needed to store maxvalue
+ bits_needed = common.bit_size(maxvalue)
+
+ # Keep trying until we find a value
+ while True:
+ value = read_random_int(bits_needed)
+ if minvalue <= value <= maxvalue:
+ break
+
+ return value
\ No newline at end of file
diff --git a/rsa/transform.py b/rsa/transform.py
index c4e6a91..1f0d4f4 100644
--- a/rsa/transform.py
+++ b/rsa/transform.py
@@ -15,7 +15,7 @@ def bytes2int(raw_bytes: bytes) -> int:
8405007
"""
- pass
+ return int.from_bytes(raw_bytes, byteorder='big')
def int2bytes(number: int, fill_size: int=0) -> bytes:
"""
@@ -37,7 +37,21 @@ def int2bytes(number: int, fill_size: int=0) -> bytes:
argument to this function to be set to ``False`` otherwise, no
error will be raised.
"""
- pass
+ if not isinstance(number, int):
+ raise TypeError("Number must be an integer")
+ if number < 0:
+ raise ValueError("Number must be an unsigned integer")
+
+ # Calculate the number of bytes needed to represent the integer
+ bytes_needed = max(1, math.ceil(number.bit_length() / 8))
+
+ # If fill_size is given, check if the number fits
+ if fill_size > 0:
+ if bytes_needed > fill_size:
+ raise OverflowError("Number is too large for the given fill_size")
+ bytes_needed = fill_size
+
+ return number.to_bytes(bytes_needed, byteorder='big')
if __name__ == '__main__':
import doctest
doctest.testmod()
\ No newline at end of file