blob: 27db671af8cbcf229cc8c0138fc8de4be9b6b546 [file] [log] [blame]
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import abc
try:
# Only available in math in 3.5+
from math import gcd
except ImportError:
from fractions import gcd
import six
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import RSABackend
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKey(object):
@abc.abstractmethod
def signer(self, padding, algorithm):
"""
Returns an AsymmetricSignatureContext used for signing data.
"""
@abc.abstractmethod
def decrypt(self, ciphertext, padding):
"""
Decrypts the provided ciphertext.
"""
@abc.abstractproperty
def key_size(self):
"""
The bit length of the public modulus.
"""
@abc.abstractmethod
def public_key(self):
"""
The RSAPublicKey associated with this private key.
"""
@abc.abstractmethod
def sign(self, data, padding, algorithm):
"""
Signs the data.
"""
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKeyWithSerialization(RSAPrivateKey):
@abc.abstractmethod
def private_numbers(self):
"""
Returns an RSAPrivateNumbers.
"""
@abc.abstractmethod
def private_bytes(self, encoding, format, encryption_algorithm):
"""
Returns the key serialized as bytes.
"""
@six.add_metaclass(abc.ABCMeta)
class RSAPublicKey(object):
@abc.abstractmethod
def verifier(self, signature, padding, algorithm):
"""
Returns an AsymmetricVerificationContext used for verifying signatures.
"""
@abc.abstractmethod
def encrypt(self, plaintext, padding):
"""
Encrypts the given plaintext.
"""
@abc.abstractproperty
def key_size(self):
"""
The bit length of the public modulus.
"""
@abc.abstractmethod
def public_numbers(self):
"""
Returns an RSAPublicNumbers
"""
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
Returns the key serialized as bytes.
"""
@abc.abstractmethod
def verify(self, signature, data, padding, algorithm):
"""
Verifies the signature of the data.
"""
RSAPublicKeyWithSerialization = RSAPublicKey
def generate_private_key(public_exponent, key_size, backend):
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
"Backend object does not implement RSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
_verify_rsa_parameters(public_exponent, key_size)
return backend.generate_rsa_private_key(public_exponent, key_size)
def _verify_rsa_parameters(public_exponent, key_size):
if public_exponent < 3:
raise ValueError("public_exponent must be >= 3.")
if public_exponent & 1 == 0:
raise ValueError("public_exponent must be odd.")
if key_size < 512:
raise ValueError("key_size must be at least 512-bits.")
def _check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp,
public_exponent, modulus):
if modulus < 3:
raise ValueError("modulus must be >= 3.")
if p >= modulus:
raise ValueError("p must be < modulus.")
if q >= modulus:
raise ValueError("q must be < modulus.")
if dmp1 >= modulus:
raise ValueError("dmp1 must be < modulus.")
if dmq1 >= modulus:
raise ValueError("dmq1 must be < modulus.")
if iqmp >= modulus:
raise ValueError("iqmp must be < modulus.")
if private_exponent >= modulus:
raise ValueError("private_exponent must be < modulus.")
if public_exponent < 3 or public_exponent >= modulus:
raise ValueError("public_exponent must be >= 3 and < modulus.")
if public_exponent & 1 == 0:
raise ValueError("public_exponent must be odd.")
if dmp1 & 1 == 0:
raise ValueError("dmp1 must be odd.")
if dmq1 & 1 == 0:
raise ValueError("dmq1 must be odd.")
if p * q != modulus:
raise ValueError("p*q must equal modulus.")
def _check_public_key_components(e, n):
if n < 3:
raise ValueError("n must be >= 3.")
if e < 3 or e >= n:
raise ValueError("e must be >= 3 and < n.")
if e & 1 == 0:
raise ValueError("e must be odd.")
def _modinv(e, m):
"""
Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
"""
x1, y1, x2, y2 = 1, 0, 0, 1
a, b = e, m
while b > 0:
q, r = divmod(a, b)
xn, yn = x1 - q * x2, y1 - q * y2
a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn
return x1 % m
def rsa_crt_iqmp(p, q):
"""
Compute the CRT (q ** -1) % p value from RSA primes p and q.
"""
return _modinv(q, p)
def rsa_crt_dmp1(private_exponent, p):
"""
Compute the CRT private_exponent % (p - 1) value from the RSA
private_exponent (d) and p.
"""
return private_exponent % (p - 1)
def rsa_crt_dmq1(private_exponent, q):
"""
Compute the CRT private_exponent % (q - 1) value from the RSA
private_exponent (d) and q.
"""
return private_exponent % (q - 1)
# Controls the number of iterations rsa_recover_prime_factors will perform
# to obtain the prime factors. Each iteration increments by 2 so the actual
# maximum attempts is half this number.
_MAX_RECOVERY_ATTEMPTS = 1000
def rsa_recover_prime_factors(n, e, d):
"""
Compute factors p and q from the private exponent d. We assume that n has
no more than two factors. This function is adapted from code in PyCrypto.
"""
# See 8.2.2(i) in Handbook of Applied Cryptography.
ktot = d * e - 1
# The quantity d*e-1 is a multiple of phi(n), even,
# and can be represented as t*2^s.
t = ktot
while t % 2 == 0:
t = t // 2
# Cycle through all multiplicative inverses in Zn.
# The algorithm is non-deterministic, but there is a 50% chance
# any candidate a leads to successful factoring.
# See "Digitalized Signatures and Public Key Functions as Intractable
# as Factorization", M. Rabin, 1979
spotted = False
a = 2
while not spotted and a < _MAX_RECOVERY_ATTEMPTS:
k = t
# Cycle through all values a^{t*2^i}=a^k
while k < ktot:
cand = pow(a, k, n)
# Check if a^k is a non-trivial root of unity (mod n)
if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
# We have found a number such that (cand-1)(cand+1)=0 (mod n).
# Either of the terms divides n.
p = gcd(cand + 1, n)
spotted = True
break
k *= 2
# This value was not any good... let's try another!
a += 2
if not spotted:
raise ValueError("Unable to compute factors p and q from exponent d.")
# Found !
q, r = divmod(n, p)
assert r == 0
p, q = sorted((p, q), reverse=True)
return (p, q)
class RSAPrivateNumbers(object):
def __init__(self, p, q, d, dmp1, dmq1, iqmp,
public_numbers):
if (
not isinstance(p, six.integer_types) or
not isinstance(q, six.integer_types) or
not isinstance(d, six.integer_types) or
not isinstance(dmp1, six.integer_types) or
not isinstance(dmq1, six.integer_types) or
not isinstance(iqmp, six.integer_types)
):
raise TypeError(
"RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must"
" all be an integers."
)
if not isinstance(public_numbers, RSAPublicNumbers):
raise TypeError(
"RSAPrivateNumbers public_numbers must be an RSAPublicNumbers"
" instance."
)
self._p = p
self._q = q
self._d = d
self._dmp1 = dmp1
self._dmq1 = dmq1
self._iqmp = iqmp
self._public_numbers = public_numbers
p = utils.read_only_property("_p")
q = utils.read_only_property("_q")
d = utils.read_only_property("_d")
dmp1 = utils.read_only_property("_dmp1")
dmq1 = utils.read_only_property("_dmq1")
iqmp = utils.read_only_property("_iqmp")
public_numbers = utils.read_only_property("_public_numbers")
def private_key(self, backend):
return backend.load_rsa_private_numbers(self)
def __eq__(self, other):
if not isinstance(other, RSAPrivateNumbers):
return NotImplemented
return (
self.p == other.p and
self.q == other.q and
self.d == other.d and
self.dmp1 == other.dmp1 and
self.dmq1 == other.dmq1 and
self.iqmp == other.iqmp and
self.public_numbers == other.public_numbers
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((
self.p,
self.q,
self.d,
self.dmp1,
self.dmq1,
self.iqmp,
self.public_numbers,
))
class RSAPublicNumbers(object):
def __init__(self, e, n):
if (
not isinstance(e, six.integer_types) or
not isinstance(n, six.integer_types)
):
raise TypeError("RSAPublicNumbers arguments must be integers.")
self._e = e
self._n = n
e = utils.read_only_property("_e")
n = utils.read_only_property("_n")
def public_key(self, backend):
return backend.load_rsa_public_numbers(self)
def __repr__(self):
return "<RSAPublicNumbers(e={0.e}, n={0.n})>".format(self)
def __eq__(self, other):
if not isinstance(other, RSAPublicNumbers):
return NotImplemented
return self.e == other.e and self.n == other.n
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.e, self.n))