• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tlsfuzzer / tlslite-ng / 17615324909

10 Sep 2025 01:30PM UTC coverage: 76.448% (-6.9%) from 83.378%
17615324909

Pull #556

github

web-flow
Merge 281134490 into b0f903667
Pull Request #556: ML-DSA support

4073 of 5975 branches covered (68.17%)

Branch coverage included in aggregate %.

27 of 132 new or added lines in 9 files covered. (20.45%)

928 existing lines in 40 files now uncovered.

11378 of 14236 relevant lines covered (79.92%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.95
/tlslite/utils/python_rsakey.py
1
# Author: Trevor Perrin
2
# See the LICENSE file for legal information regarding use of this file.
3

4
"""Pure-Python RSA implementation."""
1✔
5
import threading
1✔
6
from .cryptomath import *
1✔
7
from .rsakey import *
1✔
8
from .pem import *
1✔
9
from .deprecations import deprecated_params
1✔
10
if GMPY2_LOADED:
1!
UNCOV
11
    from gmpy2 import mpz
×
12
elif gmpyLoaded:
1!
UNCOV
13
    from gmpy import mpz
×
14

15
class Python_RSAKey(RSAKey):
1✔
16
    def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0,
1✔
17
                 key_type="rsa"):
18
        """Initialise key directly from integers.
19

20
        see also generate() and parsePEM()."""
21
        if (n and not e) or (e and not n):
1!
22
            raise AssertionError()
×
23
        if gmpyLoaded or GMPY2_LOADED:
1!
UNCOV
24
            n = mpz(n)
×
UNCOV
25
            e = mpz(e)
×
UNCOV
26
            d = mpz(d)
×
UNCOV
27
            p = mpz(p)
×
UNCOV
28
            q = mpz(q)
×
UNCOV
29
            dP = mpz(dP)
×
UNCOV
30
            dQ = mpz(dQ)
×
UNCOV
31
            qInv = mpz(qInv)
×
32
        self.n = n
1✔
33
        self.e = e
1✔
34
        if p and not q or not p and q:
1✔
35
            raise ValueError("p and q must be set or left unset together")
1✔
36
        if not d and p and q:
1✔
37
            t = lcm(p - 1, q - 1)
1✔
38
            d = invMod(e, t)
1✔
39
        self.d = d
1✔
40
        self.p = p
1✔
41
        self.q = q
1✔
42
        if not dP and p:
1✔
43
            dP = d % (p - 1)
1✔
44
        self.dP = dP
1✔
45
        if not dQ and q:
1✔
46
            dQ = d % (q - 1)
1✔
47
        self.dQ = dQ
1✔
48
        if not qInv:
1✔
49
            qInv = invMod(q, p)
1✔
50
        self.qInv = qInv
1✔
51
        self.blinder = 0
1✔
52
        self.unblinder = 0
1✔
53
        self._lock = threading.Lock()
1✔
54
        self.key_type = key_type
1✔
55

56
    def hasPrivateKey(self):
1✔
57
        """
58
        Does the key has the associated private key (True) or is it only
59
        the public part (False).
60
        """
61
        return self.d != 0
1✔
62

63
    def _rawPrivateKeyOp(self, message):
1✔
64
        n = self.n
1✔
65
        with self._lock:
1✔
66
            # Create blinding values, on the first pass:
67
            if not self.blinder:
1✔
68
                self.unblinder = getRandomNumber(2, n)
1✔
69
                self.blinder = powMod(invMod(self.unblinder, n), self.e,
1✔
70
                                      n)
71
            unblinder = self.unblinder
1✔
72
            blinder = self.blinder
1✔
73

74
            # Update blinding values
75
            self.blinder = (blinder * blinder) % n
1✔
76
            self.unblinder = (unblinder * unblinder) % n
1✔
77

78
        # Blind the input
79
        message = (message * blinder) % n
1✔
80

81
        # Perform the RSA operation
82
        cipher = self._rawPrivateKeyOpHelper(message)
1✔
83

84
        # Unblind the output
85
        cipher = (cipher * unblinder) % n
1✔
86

87
        # Return the output
88
        return cipher
1✔
89

90
    def _rawPrivateKeyOpHelper(self, m):
1✔
91
        #Non-CRT version
92
        #c = pow(m, self.d, self.n)
93

94
        #CRT version  (~3x faster).
95
        p, q = self.p, self.q
1✔
96
        s1 = pow(m, self.dP, p)
1✔
97
        s2 = pow(m, self.dQ, q)
1✔
98
        h = ((s1 - s2) * self.qInv) % p
1✔
99
        c = s2 + q * h
1✔
100
        return c
1✔
101

102
    def _rawPublicKeyOp(self, ciphertext):
1✔
103
        msg = pow(ciphertext, self.e, self.n)
1✔
104
        return msg
1✔
105

106
    def acceptsPassword(self):
1✔
107
        """Does it support encrypted key files."""
108
        return False
×
109

110
    @staticmethod
1✔
111
    def generate(bits, key_type="rsa"):
1✔
112
        """Generate a private key with modulus 'bits' bit big.
113

114
        key_type can be "rsa" for a universal rsaEncryption key or
115
        "rsa-pss" for a key that can be used only for RSASSA-PSS."""
116
        # p, q, and t are standard names for the variables in RSA, so
117
        # ignore the fact those are one character long variable names
118
        # pylint: disable=invalid-name
119
        key = Python_RSAKey()
1✔
120
        while True:
1✔
121
            p = getRandomPrime(bits//2, False)
1✔
122
            q = getRandomPrime(bits//2, False)
1✔
123
            if gmpyLoaded or GMPY2_LOADED:
1!
UNCOV
124
                p = mpz(p)
×
UNCOV
125
                q = mpz(q)
×
126
            t = lcm(p-1, q-1)
1✔
127
            # since we need to calculate inverse of 65537 mod t, they
128
            # must be relatively prime (coprime)
129
            if gcd(t, 65537) == 1:
1!
130
                break
1✔
131
        key.n = p * q
1✔
132
        if gmpyLoaded or GMPY2_LOADED:
1!
UNCOV
133
            key.e = mpz(65537)
×
134
        else:
135
            key.e = 65537
1✔
136
        key.d = invMod(key.e, t)
1✔
137
        key.p = p
1✔
138
        key.q = q
1✔
139
        key.dP = key.d % (p-1)
1✔
140
        key.dQ = key.d % (q-1)
1✔
141
        key.qInv = invMod(q, p)
1✔
142
        key.key_type = key_type
1✔
143
        # pylint: enable=invalid-name
144
        return key
1✔
145

146
    @staticmethod
1✔
147
    @deprecated_params({"data": "s", "password_callback": "passwordCallback"})
1✔
148
    def parsePEM(data, password_callback=None):
1✔
149
        """Parse a string containing a PEM-encoded <privateKey>."""
150
        from .python_key import Python_Key
1✔
151
        return Python_Key.parsePEM(data, password_callback)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc