Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
rsa.py296 linesDownload Raw Back to asymmetric
1# This file is dual licensed under the terms of the Apache License, Version2# 2.0, and the BSD License. See the LICENSE file in the root of this repository3# for complete details.4 5from __future__ import annotations6 7import abc8import random9import typing10from math import gcd, lcm11 12from cryptography.hazmat.bindings._rust import openssl as rust_openssl13from cryptography.hazmat.primitives import _serialization, hashes14from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding15from cryptography.hazmat.primitives.asymmetric import utils as asym_utils16 17 18class RSAPrivateKey(metaclass=abc.ABCMeta):19    @abc.abstractmethod20    def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes:21        """22        Decrypts the provided ciphertext.23        """24 25    @property26    @abc.abstractmethod27    def key_size(self) -> int:28        """29        The bit length of the public modulus.30        """31 32    @abc.abstractmethod33    def public_key(self) -> RSAPublicKey:34        """35        The RSAPublicKey associated with this private key.36        """37 38    @abc.abstractmethod39    def sign(40        self,41        data: bytes,42        padding: AsymmetricPadding,43        algorithm: asym_utils.Prehashed44        | hashes.HashAlgorithm45        | asym_utils.NoDigestInfo,46    ) -> bytes:47        """48        Signs the data.49        """50 51    @abc.abstractmethod52    def private_numbers(self) -> RSAPrivateNumbers:53        """54        Returns an RSAPrivateNumbers.55        """56 57    @abc.abstractmethod58    def private_bytes(59        self,60        encoding: _serialization.Encoding,61        format: _serialization.PrivateFormat,62        encryption_algorithm: _serialization.KeySerializationEncryption,63    ) -> bytes:64        """65        Returns the key serialized as bytes.66        """67 68    @abc.abstractmethod69    def __copy__(self) -> RSAPrivateKey:70        """71        Returns a copy.72        """73 74    @abc.abstractmethod75    def __deepcopy__(self, memo: dict) -> RSAPrivateKey:76        """77        Returns a deep copy.78        """79 80 81RSAPrivateKeyWithSerialization = RSAPrivateKey82RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey)83 84 85class RSAPublicKey(metaclass=abc.ABCMeta):86    @abc.abstractmethod87    def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes:88        """89        Encrypts the given plaintext.90        """91 92    @property93    @abc.abstractmethod94    def key_size(self) -> int:95        """96        The bit length of the public modulus.97        """98 99    @abc.abstractmethod100    def public_numbers(self) -> RSAPublicNumbers:101        """102        Returns an RSAPublicNumbers103        """104 105    @abc.abstractmethod106    def public_bytes(107        self,108        encoding: _serialization.Encoding,109        format: _serialization.PublicFormat,110    ) -> bytes:111        """112        Returns the key serialized as bytes.113        """114 115    @abc.abstractmethod116    def verify(117        self,118        signature: bytes,119        data: bytes,120        padding: AsymmetricPadding,121        algorithm: asym_utils.Prehashed | hashes.HashAlgorithm,122    ) -> None:123        """124        Verifies the signature of the data.125        """126 127    @abc.abstractmethod128    def recover_data_from_signature(129        self,130        signature: bytes,131        padding: AsymmetricPadding,132        algorithm: hashes.HashAlgorithm | asym_utils.NoDigestInfo | None,133    ) -> bytes:134        """135        Recovers the original data from the signature.136        """137 138    @abc.abstractmethod139    def __eq__(self, other: object) -> bool:140        """141        Checks equality.142        """143 144    @abc.abstractmethod145    def __copy__(self) -> RSAPublicKey:146        """147        Returns a copy.148        """149 150    @abc.abstractmethod151    def __deepcopy__(self, memo: dict) -> RSAPublicKey:152        """153        Returns a deep copy.154        """155 156 157RSAPublicKeyWithSerialization = RSAPublicKey158RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey)159 160RSAPrivateNumbers = rust_openssl.rsa.RSAPrivateNumbers161RSAPublicNumbers = rust_openssl.rsa.RSAPublicNumbers162 163 164def generate_private_key(165    public_exponent: int,166    key_size: int,167    backend: typing.Any = None,168) -> RSAPrivateKey:169    _verify_rsa_parameters(public_exponent, key_size)170    return rust_openssl.rsa.generate_private_key(public_exponent, key_size)171 172 173def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None:174    if public_exponent not in (3, 65537):175        raise ValueError(176            "public_exponent must be either 3 (for legacy compatibility) or "177            "65537. Almost everyone should choose 65537 here!"178        )179 180    if key_size < 1024:181        raise ValueError("key_size must be at least 1024-bits.")182 183 184def _modinv(e: int, m: int) -> int:185    """186    Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1187    """188    x1, x2 = 1, 0189    a, b = e, m190    while b > 0:191        q, r = divmod(a, b)192        xn = x1 - q * x2193        a, b, x1, x2 = b, r, x2, xn194    return x1 % m195 196 197def rsa_crt_iqmp(p: int, q: int) -> int:198    """199    Compute the CRT (q ** -1) % p value from RSA primes p and q.200    """201    if p <= 1 or q <= 1:202        raise ValueError("Values can't be <= 1")203    return _modinv(q, p)204 205 206def rsa_crt_dmp1(private_exponent: int, p: int) -> int:207    """208    Compute the CRT private_exponent % (p - 1) value from the RSA209    private_exponent (d) and p.210    """211    if private_exponent <= 1 or p <= 1:212        raise ValueError("Values can't be <= 1")213    return private_exponent % (p - 1)214 215 216def rsa_crt_dmq1(private_exponent: int, q: int) -> int:217    """218    Compute the CRT private_exponent % (q - 1) value from the RSA219    private_exponent (d) and q.220    """221    if private_exponent <= 1 or q <= 1:222        raise ValueError("Values can't be <= 1")223    return private_exponent % (q - 1)224 225 226def rsa_recover_private_exponent(e: int, p: int, q: int) -> int:227    """228    Compute the RSA private_exponent (d) given the public exponent (e)229    and the RSA primes p and q.230 231    This uses the Carmichael totient function to generate the232    smallest possible working value of the private exponent.233    """234    # This lambda_n is the Carmichael totient function.235    # The original RSA paper uses the Euler totient function236    # here: phi_n = (p - 1) * (q - 1)237    # Either version of the private exponent will work, but the238    # one generated by the older formulation may be larger239    # than necessary. (lambda_n always divides phi_n)240    if e <= 1 or p <= 1 or q <= 1:241        raise ValueError("Values can't be <= 1")242    return _modinv(e, lcm(p - 1, q - 1))243 244 245# Controls the number of iterations rsa_recover_prime_factors will perform246# to obtain the prime factors.247_MAX_RECOVERY_ATTEMPTS = 500248 249 250def rsa_recover_prime_factors(n: int, e: int, d: int) -> tuple[int, int]:251    """252    Compute factors p and q from the private exponent d. We assume that n has253    no more than two factors. This function is adapted from code in PyCrypto.254    """255    # reject invalid values early256    if d <= 1 or e <= 1:257        raise ValueError("d, e can't be <= 1")258    if 17 != pow(17, e * d, n):259        raise ValueError("n, d, e don't match")260    # See 8.2.2(i) in Handbook of Applied Cryptography.261    ktot = d * e - 1262    # The quantity d*e-1 is a multiple of phi(n), even,263    # and can be represented as t*2^s.264    t = ktot265    while t % 2 == 0:266        t = t // 2267    # Cycle through all multiplicative inverses in Zn.268    # The algorithm is non-deterministic, but there is a 50% chance269    # any candidate a leads to successful factoring.270    # See "Digitalized Signatures and Public Key Functions as Intractable271    # as Factorization", M. Rabin, 1979272    spotted = False273    tries = 0274    while not spotted and tries < _MAX_RECOVERY_ATTEMPTS:275        a = random.randint(2, n - 1)276        tries += 1277        k = t278        # Cycle through all values a^{t*2^i}=a^k279        while k < ktot:280            cand = pow(a, k, n)281            # Check if a^k is a non-trivial root of unity (mod n)282            if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:283                # We have found a number such that (cand-1)(cand+1)=0 (mod n).284                # Either of the terms divides n.285                p = gcd(cand + 1, n)286                spotted = True287                break288            k *= 2289    if not spotted:290        raise ValueError("Unable to compute factors p and q from exponent d.")291    # Found !292    q, r = divmod(n, p)293    assert r == 0294    p, q = sorted((p, q), reverse=True)295    return (p, q)296 
codekingpro/portable-devtools · Team Ai