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 rsaScheme = rsaScheme.lower()
79 hAlg = hAlg.lower()
80 hashBytes = secureHash(bytearray(bytes), hAlg)
81 return self.sign(hashBytes, padding=rsaScheme, hashAlg=hAlg,
82 saltLen=sLen)
83
84 - def hashAndVerify(self, sigBytes, bytes, rsaScheme='PKCS1', hAlg='sha1',
85 sLen=0):
86 """Hash and verify the passed-in bytes with the signature.
87
88 This verifies a PKCS1 or PSS signature on the passed-in data
89 with selected hash algorithm.
90
91 @type sigBytes: L{bytearray} of unsigned bytes
92 @param sigBytes: A PKCS1 or PSS signature.
93
94 @type bytes: str or L{bytearray} of unsigned bytes
95 @param bytes: The value which will be hashed and verified.
96
97 @type rsaScheme: str
98 @param rsaScheme: The type of RSA scheme that will be applied,
99 "PKCS1" for RSASSA-PKCS#1 v1.5 signature and "PSS"
100 for RSASSA-PSS with MGF1 signature method
101
102 @type hAlg: str
103 @param hAlg: The hash algorithm that will be used
104
105 @type sLen: int
106 @param sLen: The length of intended salt value, applicable only
107 for RSASSA-PSS signatures
108
109 @rtype: bool
110 @return: Whether the signature matches the passed-in data.
111 """
112 rsaScheme = rsaScheme.lower()
113 hAlg = hAlg.lower()
114
115 hashBytes = secureHash(bytearray(bytes), hAlg)
116 return self.verify(sigBytes, hashBytes, rsaScheme, hAlg, sLen)
117
118 - def MGF1(self, mgfSeed, maskLen, hAlg):
119 """Generate mask from passed-in seed.
120
121 This generates mask based on passed-in seed and output maskLen.
122
123 @type mgfSeed: L{bytearray}
124 @param mgfSeed: Seed from which mask will be generated.
125
126 @type maskLen: int
127 @param maskLen: Wished length of the mask, in octets
128
129 @rtype: L{bytearray}
130 @return: Mask
131 """
132 hashLen = getattr(hashlib, hAlg)().digest_size
133 if maskLen > (2 ** 32) * hashLen:
134 raise MaskTooLongError("Incorrect parameter maskLen")
135 T = bytearray()
136 end = divceil(maskLen, hashLen)
137 for x in range(0, end):
138 C = numberToByteArray(x, 4)
139 T += secureHash(mgfSeed + C, hAlg)
140 return T[:maskLen]
141
143 """Encode the passed in message
144
145 This encodes the message using selected hash algorithm
146
147 @type mHash: bytearray
148 @param mHash: Hash of message to be encoded
149
150 @type emBits: int
151 @param emBits: maximal length of returned EM
152
153 @type hAlg: str
154 @param hAlg: hash algorithm to be used
155
156 @type sLen: int
157 @param sLen: length of salt"""
158 hashLen = getattr(hashlib, hAlg)().digest_size
159 emLen = divceil(emBits, 8)
160 if emLen < hashLen + sLen + 2:
161 raise EncodingError("The ending limit too short for " +
162 "selected hash and salt length")
163 salt = getRandomBytes(sLen)
164 M2 = bytearray(8) + mHash + salt
165 H = secureHash(M2, hAlg)
166 PS = bytearray(emLen - sLen - hashLen - 2)
167 DB = PS + bytearray(b'\x01') + salt
168 dbMask = self.MGF1(H, emLen - hashLen - 1, hAlg)
169 maskedDB = bytearray(i ^ j for i, j in zip(DB, dbMask))
170 mLen = emLen*8 - emBits
171 mask = (1 << 8 - mLen) - 1
172 maskedDB[0] &= mask
173 EM = maskedDB + H + bytearray(b'\xbc')
174 return EM
175
177 """"Sign the passed in message
178
179 This signs the message using selected hash algorithm
180
181 @type mHash: bytearray
182 @param mHash: Hash of message to be signed
183
184 @type hAlg: str
185 @param hAlg: hash algorithm to be used
186
187 @type sLen: int
188 @param sLen: length of salt"""
189 EM = self.EMSA_PSS_encode(mHash, numBits(self.n) - 1, hAlg, sLen)
190 m = bytesToNumber(EM)
191 if m >= self.n:
192 raise MessageTooLongError("Encode output too long")
193 s = self._rawPrivateKeyOp(m)
194 S = numberToByteArray(s, numBytes(self.n))
195 return S
196
198 """Verify signature in passed in encoded message
199
200 This verifies the signature in encoded message
201
202 @type mHash: bytearray
203 @param mHash: Hash of the original not signed message
204
205 @type EM: bytearray
206 @param EM: Encoded message
207
208 @type emBits: int
209 @param emBits: Length of the encoded message in bits
210
211 @type hAlg: str
212 @param hAlg: hash algorithm to be used
213
214 @type sLen: int
215 @param sLen: Length of salt
216 """
217 hashLen = getattr(hashlib, hAlg)().digest_size
218 emLen = divceil(emBits, 8)
219 if emLen < hashLen + sLen + 2:
220 raise InvalidSignature("Invalid signature")
221 if EM[-1] != 0xbc:
222 raise InvalidSignature("Invalid signature")
223 maskedDB = EM[0:emLen - hashLen - 1]
224 H = EM[emLen - hashLen - 1:emLen - hashLen - 1 + hashLen]
225 DBHelpMask = 1 << 8 - (8*emLen - emBits)
226 DBHelpMask -= 1
227 DBHelpMask = (~DBHelpMask) & 0xff
228 if maskedDB[0] & DBHelpMask != 0:
229 raise InvalidSignature("Invalid signature")
230 dbMask = self.MGF1(H, emLen - hashLen - 1, hAlg)
231 DB = bytearray(i ^ j for i, j in zip(maskedDB, dbMask))
232 mLen = emLen*8 - emBits
233 mask = (1 << 8 - mLen) - 1
234 DB[0] &= mask
235 if any(x != 0 for x in DB[0:emLen - hashLen - sLen - 2]):
236 raise InvalidSignature("Invalid signature")
237 if DB[emLen - hashLen - sLen - 2] != 0x01:
238 raise InvalidSignature("Invalid signature")
239 if sLen != 0:
240 salt = DB[-sLen:]
241 else:
242 salt = bytearray()
243 newM = bytearray(8) + mHash + salt
244 newH = secureHash(newM, hAlg)
245 if H == newH:
246 return True
247 else:
248 raise InvalidSignature("Invalid signature")
249
251 """Verify the signature in passed in message
252
253 This verifies the signature in the signed message
254
255 @type mHash: bytearray
256 @param mHash: Hash of original message
257
258 @type S: bytearray
259 @param S: Signed message
260
261 @type hAlg: str
262 @param hAlg: Hash algorithm to be used
263
264 @type sLen: int
265 @param sLen: Length of salt
266 """
267 if len(bytearray(S)) != len(numberToByteArray(self.n)):
268 raise InvalidSignature
269 s = bytesToNumber(S)
270 m = self._rawPublicKeyOp(s)
271 EM = numberToByteArray(m, divceil(numBits(self.n) - 1, 8))
272 result = self.EMSA_PSS_verify(mHash, EM, numBits(self.n) - 1,
273 hAlg, sLen)
274 if result:
275 return True
276 else:
277 raise InvalidSignature("Invalid signature")
278
290
291 - def sign(self, bytes, padding='pkcs1', hashAlg=None, saltLen=None):
292 """Sign the passed-in bytes.
293
294 This requires the key to have a private component. It performs
295 a PKCS1 signature on the passed-in data.
296
297 @type bytes: L{bytearray} of unsigned bytes
298 @param bytes: The value which will be signed.
299
300 @type padding: str
301 @param padding: name of the rsa padding mode to use, supported:
302 "pkcs1" for RSASSA-PKCS1_1_5 and "pss" for RSASSA-PSS.
303
304 @type hashAlg: str
305 @param hashAlg: name of hash to be encoded using the PKCS#1 prefix
306 for "pkcs1" padding or the hash used for MGF1 in "pss". Parameter
307 is mandatory for "pss" padding.
308
309 @type saltLen: int
310 @param saltLen: length of salt used for the PSS padding. Default
311 is the length of the hash output used.
312
313 @rtype: L{bytearray} of unsigned bytes.
314 @return: A PKCS1 signature on the passed-in data.
315 """
316 padding = padding.lower()
317 if padding == 'pkcs1':
318 if hashAlg is not None:
319 bytes = self.addPKCS1Prefix(bytes, hashAlg)
320 sigBytes = self._raw_pkcs1_sign(bytes)
321 elif padding == "pss":
322 sigBytes = self.RSASSA_PSS_sign(bytes, hashAlg, saltLen)
323 else:
324 raise UnknownRSAType("Unknown RSA algorithm type")
325 return sigBytes
326
338
339 - def verify(self, sigBytes, bytes, padding='pkcs1', hashAlg=None,
340 saltLen=None):
341 """Verify the passed-in bytes with the signature.
342
343 This verifies a PKCS1 signature on the passed-in data.
344
345 @type sigBytes: L{bytearray} of unsigned bytes
346 @param sigBytes: A PKCS1 signature.
347
348 @type bytes: L{bytearray} of unsigned bytes
349 @param bytes: The value which will be verified.
350
351 @rtype: bool
352 @return: Whether the signature matches the passed-in data.
353 """
354 if padding == "pkcs1" and hashAlg == 'sha1':
355
356 prefixedHashBytes1 = self.addPKCS1SHA1Prefix(bytes, False)
357 prefixedHashBytes2 = self.addPKCS1SHA1Prefix(bytes, True)
358 result1 = self._raw_pkcs1_verify(sigBytes, prefixedHashBytes1)
359 result2 = self._raw_pkcs1_verify(sigBytes, prefixedHashBytes2)
360 return (result1 or result2)
361 elif padding == 'pkcs1':
362 if hashAlg is not None:
363 bytes = self.addPKCS1Prefix(bytes, hashAlg)
364 r = self._raw_pkcs1_verify(sigBytes, bytes)
365 return r
366 elif padding == "pss":
367 r = self.RSASSA_PSS_verify(bytes, sigBytes, hashAlg, saltLen)
368 return r
369 else:
370 raise UnknownRSAType("Unknown RSA algorithm type")
371
373 """Encrypt the passed-in bytes.
374
375 This performs PKCS1 encryption of the passed-in data.
376
377 @type bytes: L{bytearray} of unsigned bytes
378 @param bytes: The value which will be encrypted.
379
380 @rtype: L{bytearray} of unsigned bytes.
381 @return: A PKCS1 encryption of the passed-in data.
382 """
383 paddedBytes = self._addPKCS1Padding(bytes, 2)
384 m = bytesToNumber(paddedBytes)
385 if m >= self.n:
386 raise ValueError()
387 c = self._rawPublicKeyOp(m)
388 encBytes = numberToByteArray(c, numBytes(self.n))
389 return encBytes
390
392 """Decrypt the passed-in bytes.
393
394 This requires the key to have a private component. It performs
395 PKCS1 decryption of the passed-in data.
396
397 @type encBytes: L{bytearray} of unsigned bytes
398 @param encBytes: The value which will be decrypted.
399
400 @rtype: L{bytearray} of unsigned bytes or None.
401 @return: A PKCS1 decryption of the passed-in data or None if
402 the data is not properly formatted.
403 """
404 if not self.hasPrivateKey():
405 raise AssertionError()
406 if len(encBytes) != numBytes(self.n):
407 return None
408 c = bytesToNumber(encBytes)
409 if c >= self.n:
410 return None
411 m = self._rawPrivateKeyOp(c)
412 decBytes = numberToByteArray(m, numBytes(self.n))
413
414 if decBytes[0] != 0 or decBytes[1] != 2:
415 return None
416
417 for x in range(1, len(decBytes)-1):
418 if decBytes[x]== 0:
419 break
420 else:
421 return None
422 return decBytes[x+1:]
423
425 raise NotImplementedError()
426
428 raise NotImplementedError()
429
431 """Return True if the write() method accepts a password for use
432 in encrypting the private key.
433
434 @rtype: bool
435 """
436 raise NotImplementedError()
437
438 - def write(self, password=None):
439 """Return a string containing the key.
440
441 @rtype: str
442 @return: A string describing the key, in whichever format (PEM)
443 is native to the implementation.
444 """
445 raise NotImplementedError()
446
448 """Generate a new key with the specified bit length.
449
450 @rtype: L{tlslite.utils.RSAKey.RSAKey}
451 """
452 raise NotImplementedError()
453 generate = staticmethod(generate)
454
455
456
457
458
459
460 @classmethod
462 """Add PKCS#1 v1.5 algorithm identifier prefix to SHA1 hash bytes"""
463
464
465
466
467
468
469
470
471 if not withNULL:
472 prefixBytes = bytearray([0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b,
473 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14])
474 else:
475 prefixBytes = cls._pkcs1Prefixes['sha1']
476 prefixedBytes = prefixBytes + hashBytes
477 return prefixedBytes
478
479 _pkcs1Prefixes = {'md5' : bytearray([0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
480 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
481 0x02, 0x05, 0x05, 0x00, 0x04, 0x10]),
482 'sha1' : bytearray([0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
483 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
484 0x00, 0x04, 0x14]),
485 'sha224' : bytearray([0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
486 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
487 0x04, 0x02, 0x04, 0x05, 0x00, 0x04,
488 0x1c]),
489 'sha256' : bytearray([0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
490 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
491 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
492 0x20]),
493 'sha384' : bytearray([0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
494 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
495 0x04, 0x02, 0x02, 0x05, 0x00, 0x04,
496 0x30]),
497 'sha512' : bytearray([0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
498 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
499 0x04, 0x02, 0x03, 0x05, 0x00, 0x04,
500 0x40])}
501
502 @classmethod
504 """Add the PKCS#1 v1.5 algorithm identifier prefix to hash bytes"""
505 hashName = hashName.lower()
506 assert hashName in cls._pkcs1Prefixes
507 prefixBytes = cls._pkcs1Prefixes[hashName]
508 return prefixBytes + data
509
511 padLength = (numBytes(self.n) - (len(bytes)+3))
512 if blockType == 1:
513 pad = [0xFF] * padLength
514 elif blockType == 2:
515 pad = bytearray(0)
516 while len(pad) < padLength:
517 padBytes = getRandomBytes(padLength * 2)
518 pad = [b for b in padBytes if b != 0]
519 pad = pad[:padLength]
520 else:
521 raise AssertionError()
522
523 padding = bytearray([0,blockType] + pad + [0])
524 paddedBytes = padding + bytes
525 return paddedBytes
526