1
2
3
4 """Abstract class for RSA."""
5
6 from .cryptomath import *
7 from . import tlshashlib as hashlib
8 from ..errors import MaskTooLongError, MessageTooLongError, EncodingError, \
9 InvalidSignature, UnknownRSAType
13 """This is an abstract base class for RSA keys.
14
15 Particular implementations of RSA keys, such as
16 L{openssl_rsakey.OpenSSL_RSAKey},
17 L{python_rsakey.Python_RSAKey}, and
18 L{pycrypto_rsakey.PyCrypto_RSAKey},
19 inherit from this.
20
21 To create or parse an RSA key, don't use one of these classes
22 directly. Instead, use the factory functions in
23 L{tlslite.utils.keyfactory}.
24 """
25
27 """Create a new RSA key.
28
29 If n and e are passed in, the new key will be initialized.
30
31 @type n: int
32 @param n: RSA modulus.
33
34 @type e: int
35 @param e: RSA public exponent.
36 """
37 raise NotImplementedError()
38
40 """Return the length of this key in bits.
41
42 @rtype: int
43 """
44 return numBits(self.n)
45
47 """Return whether or not this key has a private component.
48
49 @rtype: bool
50 """
51 raise NotImplementedError()
52
53 - def hashAndSign(self, bytes, rsaScheme='PKCS1', hAlg='sha1', sLen=0):
54 """Hash and sign the passed-in bytes.
55
56 This requires the key to have a private component. It performs
57 a PKCS1 or PSS signature on the passed-in data with selected hash
58 algorithm.
59
60 @type bytes: str or L{bytearray} of unsigned bytes
61 @param bytes: The value which will be hashed and signed.
62
63 @type rsaScheme: str
64 @param rsaScheme: The type of RSA scheme that will be applied,
65 "PKCS1" for RSASSA-PKCS#1 v1.5 signature and "PSS"
66 for RSASSA-PSS with MGF1 signature method
67
68 @type hAlg: str
69 @param hAlg: The hash algorithm that will be used
70
71 @type sLen: int
72 @param sLen: The length of intended salt value, applicable only
73 for RSASSA-PSS signatures
74
75 @rtype: L{bytearray} of unsigned bytes.
76 @return: A PKCS1 or PSS signature on the passed-in data.
77 """
78 if rsaScheme == "PKCS1":
79 hashBytes = secureHash(bytearray(bytes), hAlg)
80 prefixedHashBytes = self.addPKCS1Prefix(hashBytes, hAlg)
81 sigBytes = self.sign(prefixedHashBytes)
82 elif rsaScheme == "PSS":
83 sigBytes = self.RSASSA_PSS_sign(bytearray(bytes), hAlg, sLen)
84 else:
85 raise UnknownRSAType("Unknown RSA algorithm type")
86 return sigBytes
87
88 - def hashAndVerify(self, sigBytes, bytes, rsaScheme='PKCS1', hAlg='sha1',
89 sLen=0):
90 """Hash and verify the passed-in bytes with the signature.
91
92 This verifies a PKCS1 or PSS signature on the passed-in data
93 with selected hash algorithm.
94
95 @type sigBytes: L{bytearray} of unsigned bytes
96 @param sigBytes: A PKCS1 or PSS signature.
97
98 @type bytes: str or L{bytearray} of unsigned bytes
99 @param bytes: The value which will be hashed and verified.
100
101 @type rsaScheme: str
102 @param rsaScheme: The type of RSA scheme that will be applied,
103 "PKCS1" for RSASSA-PKCS#1 v1.5 signature and "PSS"
104 for RSASSA-PSS with MGF1 signature method
105
106 @type hAlg: str
107 @param hAlg: The hash algorithm that will be used
108
109 @type sLen: int
110 @param sLen: The length of intended salt value, applicable only
111 for RSASSA-PSS signatures
112
113 @rtype: bool
114 @return: Whether the signature matches the passed-in data.
115 """
116
117
118 if rsaScheme == "PKCS1" and hAlg == 'sha1':
119 hashBytes = secureHash(bytearray(bytes), hAlg)
120 prefixedHashBytes1 = self.addPKCS1SHA1Prefix(hashBytes, False)
121 prefixedHashBytes2 = self.addPKCS1SHA1Prefix(hashBytes, True)
122 result1 = self.verify(sigBytes, prefixedHashBytes1)
123 result2 = self.verify(sigBytes, prefixedHashBytes2)
124 return (result1 or result2)
125 elif rsaScheme == 'PKCS1':
126 hashBytes = secureHash(bytearray(bytes), hAlg)
127 prefixedHashBytes = self.addPKCS1Prefix(hashBytes, hAlg)
128 r = self.verify(sigBytes, prefixedHashBytes)
129 return r
130 elif rsaScheme == "PSS":
131 r = self.RSASSA_PSS_verify(bytearray(bytes), sigBytes, hAlg, sLen)
132 return r
133 else:
134 raise UnknownRSAType("Unknown RSA algorithm type")
135
136 - def MGF1(self, mgfSeed, maskLen, hAlg):
137 """Generate mask from passed-in seed.
138
139 This generates mask based on passed-in seed and output maskLen.
140
141 @type mgfSeed: L{bytearray}
142 @param mgfSeed: Seed from which mask will be generated.
143
144 @type maskLen: int
145 @param maskLen: Wished length of the mask, in octets
146
147 @rtype: L{bytearray}
148 @return: Mask
149 """
150 hashLen = getattr(hashlib, hAlg)().digest_size
151 if maskLen > (2 ** 32) * hashLen:
152 raise MaskTooLongError("Incorrect parameter maskLen")
153 T = bytearray()
154 end = divceil(maskLen, hashLen)
155 for x in range(0, end):
156 C = numberToByteArray(x, 4)
157 T += secureHash(mgfSeed + C, hAlg)
158 return T[:maskLen]
159
161 """Encode the passed in message
162
163 This encodes the message using selected hash algorithm
164
165 @type M: bytearray
166 @param M: Message to be encoded
167
168 @type emBits: int
169 @param emBits: maximal length of returned EM
170
171 @type hAlg: str
172 @param hAlg: hash algorithm to be used
173
174 @type sLen: int
175 @param sLen: length of salt"""
176 hashLen = getattr(hashlib, hAlg)().digest_size
177 mHash = secureHash(M, hAlg)
178 emLen = divceil(emBits, 8)
179 if emLen < hashLen + sLen + 2:
180 raise EncodingError("The ending limit too short for " +
181 "selected hash and salt length")
182 salt = getRandomBytes(sLen)
183 M2 = bytearray(8) + mHash + salt
184 H = secureHash(M2, hAlg)
185 PS = bytearray(emLen - sLen - hashLen - 2)
186 DB = PS + bytearray(b'\x01') + salt
187 dbMask = self.MGF1(H, emLen - hashLen - 1, hAlg)
188 maskedDB = bytearray(i ^ j for i, j in zip(DB, dbMask))
189 mLen = emLen*8 - emBits
190 mask = (1 << 8 - mLen) - 1
191 maskedDB[0] &= mask
192 EM = maskedDB + H + bytearray(b'\xbc')
193 return EM
194
196 """"Sign the passed in message
197
198 This signs the message using selected hash algorithm
199
200 @type M: bytearray
201 @param M: Message to be signed
202
203 @type hAlg: str
204 @param hAlg: hash algorithm to be used
205
206 @type sLen: int
207 @param sLen: length of salt"""
208 EM = self.EMSA_PSS_encode(M, numBits(self.n) - 1, hAlg, sLen)
209 m = bytesToNumber(EM)
210 if m >= self.n:
211 raise MessageTooLongError("Encode output too long")
212 s = self._rawPrivateKeyOp(m)
213 S = numberToByteArray(s, numBytes(self.n))
214 return S
215
217 """Verify signature in passed in encoded message
218
219 This verifies the signature in encoded message
220
221 @type M: bytearray
222 @param M: Original not signed message
223
224 @type EM: bytearray
225 @param EM: Encoded message
226
227 @type emBits: int
228 @param emBits: Length of the encoded message in bits
229
230 @type hAlg: str
231 @param hAlg: hash algorithm to be used
232
233 @type sLen: int
234 @param sLen: Length of salt
235 """
236 hashLen = getattr(hashlib, hAlg)().digest_size
237 mHash = secureHash(M, hAlg)
238 emLen = divceil(emBits, 8)
239 if emLen < hashLen + sLen + 2:
240 raise InvalidSignature("Invalid signature")
241 if EM[-1] != 0xbc:
242 raise InvalidSignature("Invalid signature")
243 maskedDB = EM[0:emLen - hashLen - 1]
244 H = EM[emLen - hashLen - 1:emLen - hashLen - 1 + hashLen]
245 DBHelpMask = 1 << 8 - (8*emLen - emBits)
246 DBHelpMask -= 1
247 DBHelpMask = (~DBHelpMask) & 0xff
248 if maskedDB[0] & DBHelpMask != 0:
249 raise InvalidSignature("Invalid signature")
250 dbMask = self.MGF1(H, emLen - hashLen - 1, hAlg)
251 DB = bytearray(i ^ j for i, j in zip(maskedDB, dbMask))
252 mLen = emLen*8 - emBits
253 mask = (1 << 8 - mLen) - 1
254 DB[0] &= mask
255 if any(x != 0 for x in DB[0:emLen - hashLen - sLen - 2 - 1]):
256 raise InvalidSignature("Invalid signature")
257 if DB[emLen - hashLen - sLen - 2] != 0x01:
258 raise InvalidSignature("Invalid signature")
259 if sLen != 0:
260 salt = DB[-sLen:]
261 else:
262 salt = bytearray()
263 newM = bytearray(8) + mHash + salt
264 newH = secureHash(newM, hAlg)
265 if H == newH:
266 return True
267 else:
268 raise InvalidSignature("Invalid signature")
269
271 """Verify the signature in passed in message
272
273 This verifies the signature in the signed message
274
275 @type M: bytearray
276 @param M: Original message
277
278 @type S: bytearray
279 @param S: Signed message
280
281 @type hAlg: str
282 @param hAlg: Hash algorithm to be used
283
284 @type sLen: int
285 @param sLen: Length of salt
286 """
287 if len(bytearray(S)) != len(numberToByteArray(self.n)):
288 raise InvalidSignature
289 s = bytesToNumber(S)
290 m = self._rawPublicKeyOp(s)
291 EM = numberToByteArray(m, divceil(numBits(self.n) - 1, 8))
292 result = self.EMSA_PSS_verify(M, EM, numBits(self.n) - 1, hAlg, sLen)
293 if result:
294 return True
295 else:
296 raise InvalidSignature("Invalid signature")
297
298 - def sign(self, bytes):
299 """Sign the passed-in bytes.
300
301 This requires the key to have a private component. It performs
302 a PKCS1 signature on the passed-in data.
303
304 @type bytes: L{bytearray} of unsigned bytes
305 @param bytes: The value which will be signed.
306
307 @rtype: L{bytearray} of unsigned bytes.
308 @return: A PKCS1 signature on the passed-in data.
309 """
310 if not self.hasPrivateKey():
311 raise AssertionError()
312 paddedBytes = self._addPKCS1Padding(bytes, 1)
313 m = bytesToNumber(paddedBytes)
314 if m >= self.n:
315 raise ValueError()
316 c = self._rawPrivateKeyOp(m)
317 sigBytes = numberToByteArray(c, numBytes(self.n))
318 return sigBytes
319
320 - def verify(self, sigBytes, bytes):
321 """Verify the passed-in bytes with the signature.
322
323 This verifies a PKCS1 signature on the passed-in data.
324
325 @type sigBytes: L{bytearray} of unsigned bytes
326 @param sigBytes: A PKCS1 signature.
327
328 @type bytes: L{bytearray} of unsigned bytes
329 @param bytes: The value which will be verified.
330
331 @rtype: bool
332 @return: Whether the signature matches the passed-in data.
333 """
334 if len(sigBytes) != numBytes(self.n):
335 return False
336 paddedBytes = self._addPKCS1Padding(bytes, 1)
337 c = bytesToNumber(sigBytes)
338 if c >= self.n:
339 return False
340 m = self._rawPublicKeyOp(c)
341 checkBytes = numberToByteArray(m, numBytes(self.n))
342 return checkBytes == paddedBytes
343
345 """Encrypt the passed-in bytes.
346
347 This performs PKCS1 encryption of the passed-in data.
348
349 @type bytes: L{bytearray} of unsigned bytes
350 @param bytes: The value which will be encrypted.
351
352 @rtype: L{bytearray} of unsigned bytes.
353 @return: A PKCS1 encryption of the passed-in data.
354 """
355 paddedBytes = self._addPKCS1Padding(bytes, 2)
356 m = bytesToNumber(paddedBytes)
357 if m >= self.n:
358 raise ValueError()
359 c = self._rawPublicKeyOp(m)
360 encBytes = numberToByteArray(c, numBytes(self.n))
361 return encBytes
362
364 """Decrypt the passed-in bytes.
365
366 This requires the key to have a private component. It performs
367 PKCS1 decryption of the passed-in data.
368
369 @type encBytes: L{bytearray} of unsigned bytes
370 @param encBytes: The value which will be decrypted.
371
372 @rtype: L{bytearray} of unsigned bytes or None.
373 @return: A PKCS1 decryption of the passed-in data or None if
374 the data is not properly formatted.
375 """
376 if not self.hasPrivateKey():
377 raise AssertionError()
378 if len(encBytes) != numBytes(self.n):
379 return None
380 c = bytesToNumber(encBytes)
381 if c >= self.n:
382 return None
383 m = self._rawPrivateKeyOp(c)
384 decBytes = numberToByteArray(m, numBytes(self.n))
385
386 if decBytes[0] != 0 or decBytes[1] != 2:
387 return None
388
389 for x in range(1, len(decBytes)-1):
390 if decBytes[x]== 0:
391 break
392 else:
393 return None
394 return decBytes[x+1:]
395
397 raise NotImplementedError()
398
400 raise NotImplementedError()
401
403 """Return True if the write() method accepts a password for use
404 in encrypting the private key.
405
406 @rtype: bool
407 """
408 raise NotImplementedError()
409
410 - def write(self, password=None):
411 """Return a string containing the key.
412
413 @rtype: str
414 @return: A string describing the key, in whichever format (PEM)
415 is native to the implementation.
416 """
417 raise NotImplementedError()
418
420 """Generate a new key with the specified bit length.
421
422 @rtype: L{tlslite.utils.RSAKey.RSAKey}
423 """
424 raise NotImplementedError()
425 generate = staticmethod(generate)
426
427
428
429
430
431
432 @classmethod
434 """Add PKCS#1 v1.5 algorithm identifier prefix to SHA1 hash bytes"""
435
436
437
438
439
440
441
442
443 if not withNULL:
444 prefixBytes = bytearray([0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b,
445 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14])
446 else:
447 prefixBytes = cls._pkcs1Prefixes['sha1']
448 prefixedBytes = prefixBytes + hashBytes
449 return prefixedBytes
450
451 _pkcs1Prefixes = {'md5' : bytearray([0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
452 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
453 0x02, 0x05, 0x05, 0x00, 0x04, 0x10]),
454 'sha1' : bytearray([0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
455 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
456 0x00, 0x04, 0x14]),
457 'sha224' : bytearray([0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
458 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
459 0x04, 0x02, 0x04, 0x05, 0x00, 0x04,
460 0x1c]),
461 'sha256' : bytearray([0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
462 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
463 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
464 0x20]),
465 'sha384' : bytearray([0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
466 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
467 0x04, 0x02, 0x02, 0x05, 0x00, 0x04,
468 0x30]),
469 'sha512' : bytearray([0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
470 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
471 0x04, 0x02, 0x03, 0x05, 0x00, 0x04,
472 0x40])}
473
474 @classmethod
476 """Add the PKCS#1 v1.5 algorithm identifier prefix to hash bytes"""
477 hashName = hashName.lower()
478 assert hashName in cls._pkcs1Prefixes
479 prefixBytes = cls._pkcs1Prefixes[hashName]
480 return prefixBytes + data
481
483 padLength = (numBytes(self.n) - (len(bytes)+3))
484 if blockType == 1:
485 pad = [0xFF] * padLength
486 elif blockType == 2:
487 pad = bytearray(0)
488 while len(pad) < padLength:
489 padBytes = getRandomBytes(padLength * 2)
490 pad = [b for b in padBytes if b != 0]
491 pad = pad[:padLength]
492 else:
493 raise AssertionError()
494
495 padding = bytearray([0,blockType] + pad + [0])
496 paddedBytes = padding + bytes
497 return paddedBytes
498