• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Abstract class for RSA."""
2
3from cryptomath import *
4
5
6class RSAKey:
7    """This is an abstract base class for RSA keys.
8
9    Particular implementations of RSA keys, such as
10    L{OpenSSL_RSAKey.OpenSSL_RSAKey},
11    L{Python_RSAKey.Python_RSAKey}, and
12    L{PyCrypto_RSAKey.PyCrypto_RSAKey},
13    inherit from this.
14
15    To create or parse an RSA key, don't use one of these classes
16    directly.  Instead, use the factory functions in
17    L{tlslite.utils.keyfactory}.
18    """
19
20    def __init__(self, n=0, e=0):
21        """Create a new RSA key.
22
23        If n and e are passed in, the new key will be initialized.
24
25        @type n: int
26        @param n: RSA modulus.
27
28        @type e: int
29        @param e: RSA public exponent.
30        """
31        raise NotImplementedError()
32
33    def __len__(self):
34        """Return the length of this key in bits.
35
36        @rtype: int
37        """
38        return numBits(self.n)
39
40    def hasPrivateKey(self):
41        """Return whether or not this key has a private component.
42
43        @rtype: bool
44        """
45        raise NotImplementedError()
46
47    def hash(self):
48        """Return the cryptoID <keyHash> value corresponding to this
49        key.
50
51        @rtype: str
52        """
53        raise NotImplementedError()
54
55    def getSigningAlgorithm(self):
56        """Return the cryptoID sigAlgo value corresponding to this key.
57
58        @rtype: str
59        """
60        return "pkcs1-sha1"
61
62    def hashAndSign(self, bytes):
63        """Hash and sign the passed-in bytes.
64
65        This requires the key to have a private component.  It performs
66        a PKCS1-SHA1 signature on the passed-in data.
67
68        @type bytes: str or L{array.array} of unsigned bytes
69        @param bytes: The value which will be hashed and signed.
70
71        @rtype: L{array.array} of unsigned bytes.
72        @return: A PKCS1-SHA1 signature on the passed-in data.
73        """
74        if not isinstance(bytes, type("")):
75            bytes = bytesToString(bytes)
76        hashBytes = stringToBytes(sha.sha(bytes).digest())
77        prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes)
78        sigBytes = self.sign(prefixedHashBytes)
79        return sigBytes
80
81    def hashAndVerify(self, sigBytes, bytes):
82        """Hash and verify the passed-in bytes with the signature.
83
84        This verifies a PKCS1-SHA1 signature on the passed-in data.
85
86        @type sigBytes: L{array.array} of unsigned bytes
87        @param sigBytes: A PKCS1-SHA1 signature.
88
89        @type bytes: str or L{array.array} of unsigned bytes
90        @param bytes: The value which will be hashed and verified.
91
92        @rtype: bool
93        @return: Whether the signature matches the passed-in data.
94        """
95        if not isinstance(bytes, type("")):
96            bytes = bytesToString(bytes)
97        hashBytes = stringToBytes(sha.sha(bytes).digest())
98        prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes)
99        return self.verify(sigBytes, prefixedHashBytes)
100
101    def sign(self, bytes):
102        """Sign the passed-in bytes.
103
104        This requires the key to have a private component.  It performs
105        a PKCS1 signature on the passed-in data.
106
107        @type bytes: L{array.array} of unsigned bytes
108        @param bytes: The value which will be signed.
109
110        @rtype: L{array.array} of unsigned bytes.
111        @return: A PKCS1 signature on the passed-in data.
112        """
113        if not self.hasPrivateKey():
114            raise AssertionError()
115        paddedBytes = self._addPKCS1Padding(bytes, 1)
116        m = bytesToNumber(paddedBytes)
117        if m >= self.n:
118            raise ValueError()
119        c = self._rawPrivateKeyOp(m)
120        sigBytes = numberToBytes(c)
121        return sigBytes
122
123    def verify(self, sigBytes, bytes):
124        """Verify the passed-in bytes with the signature.
125
126        This verifies a PKCS1 signature on the passed-in data.
127
128        @type sigBytes: L{array.array} of unsigned bytes
129        @param sigBytes: A PKCS1 signature.
130
131        @type bytes: L{array.array} of unsigned bytes
132        @param bytes: The value which will be verified.
133
134        @rtype: bool
135        @return: Whether the signature matches the passed-in data.
136        """
137        paddedBytes = self._addPKCS1Padding(bytes, 1)
138        c = bytesToNumber(sigBytes)
139        if c >= self.n:
140            return False
141        m = self._rawPublicKeyOp(c)
142        checkBytes = numberToBytes(m)
143        return checkBytes == paddedBytes
144
145    def encrypt(self, bytes):
146        """Encrypt the passed-in bytes.
147
148        This performs PKCS1 encryption of the passed-in data.
149
150        @type bytes: L{array.array} of unsigned bytes
151        @param bytes: The value which will be encrypted.
152
153        @rtype: L{array.array} of unsigned bytes.
154        @return: A PKCS1 encryption of the passed-in data.
155        """
156        paddedBytes = self._addPKCS1Padding(bytes, 2)
157        m = bytesToNumber(paddedBytes)
158        if m >= self.n:
159            raise ValueError()
160        c = self._rawPublicKeyOp(m)
161        encBytes = numberToBytes(c)
162        return encBytes
163
164    def decrypt(self, encBytes):
165        """Decrypt the passed-in bytes.
166
167        This requires the key to have a private component.  It performs
168        PKCS1 decryption of the passed-in data.
169
170        @type encBytes: L{array.array} of unsigned bytes
171        @param encBytes: The value which will be decrypted.
172
173        @rtype: L{array.array} of unsigned bytes or None.
174        @return: A PKCS1 decryption of the passed-in data or None if
175        the data is not properly formatted.
176        """
177        if not self.hasPrivateKey():
178            raise AssertionError()
179        c = bytesToNumber(encBytes)
180        if c >= self.n:
181            return None
182        m = self._rawPrivateKeyOp(c)
183        decBytes = numberToBytes(m)
184        if (len(decBytes) != numBytes(self.n)-1): #Check first byte
185            return None
186        if decBytes[0] != 2: #Check second byte
187            return None
188        for x in range(len(decBytes)-1): #Scan through for zero separator
189            if decBytes[x]== 0:
190                break
191        else:
192            return None
193        return decBytes[x+1:] #Return everything after the separator
194
195    def _rawPrivateKeyOp(self, m):
196        raise NotImplementedError()
197
198    def _rawPublicKeyOp(self, c):
199        raise NotImplementedError()
200
201    def acceptsPassword(self):
202        """Return True if the write() method accepts a password for use
203        in encrypting the private key.
204
205        @rtype: bool
206        """
207        raise NotImplementedError()
208
209    def write(self, password=None):
210        """Return a string containing the key.
211
212        @rtype: str
213        @return: A string describing the key, in whichever format (PEM
214        or XML) is native to the implementation.
215        """
216        raise NotImplementedError()
217
218    def writeXMLPublicKey(self, indent=''):
219        """Return a string containing the key.
220
221        @rtype: str
222        @return: A string describing the public key, in XML format.
223        """
224        return Python_RSAKey(self.n, self.e).write(indent)
225
226    def generate(bits):
227        """Generate a new key with the specified bit length.
228
229        @rtype: L{tlslite.utils.RSAKey.RSAKey}
230        """
231        raise NotImplementedError()
232    generate = staticmethod(generate)
233
234
235    # **************************************************************************
236    # Helper Functions for RSA Keys
237    # **************************************************************************
238
239    def _addPKCS1SHA1Prefix(self, bytes):
240        prefixBytes = createByteArraySequence(\
241            [48,33,48,9,6,5,43,14,3,2,26,5,0,4,20])
242        prefixedBytes = prefixBytes + bytes
243        return prefixedBytes
244
245    def _addPKCS1Padding(self, bytes, blockType):
246        padLength = (numBytes(self.n) - (len(bytes)+3))
247        if blockType == 1: #Signature padding
248            pad = [0xFF] * padLength
249        elif blockType == 2: #Encryption padding
250            pad = createByteArraySequence([])
251            while len(pad) < padLength:
252                padBytes = getRandomBytes(padLength * 2)
253                pad = [b for b in padBytes if b != 0]
254                pad = pad[:padLength]
255        else:
256            raise AssertionError()
257
258        #NOTE: To be proper, we should add [0,blockType].  However,
259        #the zero is lost when the returned padding is converted
260        #to a number, so we don't even bother with it.  Also,
261        #adding it would cause a misalignment in verify()
262        padding = createByteArraySequence([blockType] + pad + [0])
263        paddedBytes = padding + bytes
264        return paddedBytes
265