Package tlslite :: Package utils :: Module rsakey
[hide private]
[frames] | no frames]

Source Code for Module tlslite.utils.rsakey

  1  # Author: Trevor Perrin 
  2  # See the LICENSE file for legal information regarding use of this file. 
  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 
10 11 12 -class RSAKey(object):
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
26 - def __init__(self, n=0, e=0):
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
39 - def __len__(self):
40 """Return the length of this key in bits. 41 42 @rtype: int 43 """ 44 return numBits(self.n)
45
46 - def hasPrivateKey(self):
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
142 - def EMSA_PSS_encode(self, mHash, emBits, hAlg, sLen=0):
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
176 - def RSASSA_PSS_sign(self, mHash, hAlg, sLen=0):
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
197 - def EMSA_PSS_verify(self, mHash, EM, emBits, hAlg, sLen=0):
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
250 - def RSASSA_PSS_verify(self, mHash, S, hAlg, sLen=0):
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("Invalid signature") 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
279 - def _raw_pkcs1_sign(self, bytes):
280 """Perform signature on raw data, add PKCS#1 padding.""" 281 if not self.hasPrivateKey(): 282 raise AssertionError() 283 paddedBytes = self._addPKCS1Padding(bytes, 1) 284 m = bytesToNumber(paddedBytes) 285 if m >= self.n: 286 raise ValueError() 287 c = self._rawPrivateKeyOp(m) 288 sigBytes = numberToByteArray(c, numBytes(self.n)) 289 return sigBytes
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
327 - def _raw_pkcs1_verify(self, sigBytes, bytes):
328 """Perform verification operation on raw PKCS#1 padded signature""" 329 if len(sigBytes) != numBytes(self.n): 330 return False 331 paddedBytes = self._addPKCS1Padding(bytes, 1) 332 c = bytesToNumber(sigBytes) 333 if c >= self.n: 334 return False 335 m = self._rawPublicKeyOp(c) 336 checkBytes = numberToByteArray(m, numBytes(self.n)) 337 return checkBytes == paddedBytes
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 # Try it with/without the embedded NULL 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 res = self._raw_pkcs1_verify(sigBytes, bytes) 365 return res 366 elif padding == "pss": 367 try: 368 res = self.RSASSA_PSS_verify(bytes, sigBytes, hashAlg, saltLen) 369 except InvalidSignature: 370 res = False 371 return res 372 else: 373 raise UnknownRSAType("Unknown RSA algorithm type")
374
375 - def encrypt(self, bytes):
376 """Encrypt the passed-in bytes. 377 378 This performs PKCS1 encryption of the passed-in data. 379 380 @type bytes: L{bytearray} of unsigned bytes 381 @param bytes: The value which will be encrypted. 382 383 @rtype: L{bytearray} of unsigned bytes. 384 @return: A PKCS1 encryption of the passed-in data. 385 """ 386 paddedBytes = self._addPKCS1Padding(bytes, 2) 387 m = bytesToNumber(paddedBytes) 388 if m >= self.n: 389 raise ValueError() 390 c = self._rawPublicKeyOp(m) 391 encBytes = numberToByteArray(c, numBytes(self.n)) 392 return encBytes
393
394 - def decrypt(self, encBytes):
395 """Decrypt the passed-in bytes. 396 397 This requires the key to have a private component. It performs 398 PKCS1 decryption of the passed-in data. 399 400 @type encBytes: L{bytearray} of unsigned bytes 401 @param encBytes: The value which will be decrypted. 402 403 @rtype: L{bytearray} of unsigned bytes or None. 404 @return: A PKCS1 decryption of the passed-in data or None if 405 the data is not properly formatted. 406 """ 407 if not self.hasPrivateKey(): 408 raise AssertionError() 409 if len(encBytes) != numBytes(self.n): 410 return None 411 c = bytesToNumber(encBytes) 412 if c >= self.n: 413 return None 414 m = self._rawPrivateKeyOp(c) 415 decBytes = numberToByteArray(m, numBytes(self.n)) 416 #Check first two bytes 417 if decBytes[0] != 0 or decBytes[1] != 2: 418 return None 419 #Scan through for zero separator 420 for x in range(1, len(decBytes)-1): 421 if decBytes[x]== 0: 422 break 423 else: 424 return None 425 return decBytes[x+1:] #Return everything after the separator
426
427 - def _rawPrivateKeyOp(self, m):
428 raise NotImplementedError()
429
430 - def _rawPublicKeyOp(self, c):
431 raise NotImplementedError()
432
433 - def acceptsPassword(self):
434 """Return True if the write() method accepts a password for use 435 in encrypting the private key. 436 437 @rtype: bool 438 """ 439 raise NotImplementedError()
440
441 - def write(self, password=None):
442 """Return a string containing the key. 443 444 @rtype: str 445 @return: A string describing the key, in whichever format (PEM) 446 is native to the implementation. 447 """ 448 raise NotImplementedError()
449
450 - def generate(bits):
451 """Generate a new key with the specified bit length. 452 453 @rtype: L{tlslite.utils.RSAKey.RSAKey} 454 """ 455 raise NotImplementedError()
456 generate = staticmethod(generate) 457 458 459 # ************************************************************************** 460 # Helper Functions for RSA Keys 461 # ************************************************************************** 462 463 @classmethod
464 - def addPKCS1SHA1Prefix(cls, hashBytes, withNULL=True):
465 """Add PKCS#1 v1.5 algorithm identifier prefix to SHA1 hash bytes""" 466 # There is a long history of confusion over whether the SHA1 467 # algorithmIdentifier should be encoded with a NULL parameter or 468 # with the parameter omitted. While the original intention was 469 # apparently to omit it, many toolkits went the other way. TLS 1.2 470 # specifies the NULL should be included, and this behavior is also 471 # mandated in recent versions of PKCS #1, and is what tlslite has 472 # always implemented. Anyways, verification code should probably 473 # accept both. 474 if not withNULL: 475 prefixBytes = bytearray([0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 476 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14]) 477 else: 478 prefixBytes = cls._pkcs1Prefixes['sha1'] 479 prefixedBytes = prefixBytes + hashBytes 480 return prefixedBytes
481 482 _pkcs1Prefixes = {'md5' : bytearray([0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 483 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 484 0x02, 0x05, 0x05, 0x00, 0x04, 0x10]), 485 'sha1' : bytearray([0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 486 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 487 0x00, 0x04, 0x14]), 488 'sha224' : bytearray([0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 489 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 490 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 491 0x1c]), 492 'sha256' : bytearray([0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 493 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 494 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 495 0x20]), 496 'sha384' : bytearray([0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 497 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 498 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 499 0x30]), 500 'sha512' : bytearray([0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 501 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 502 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 503 0x40])} 504 505 @classmethod
506 - def addPKCS1Prefix(cls, data, hashName):
507 """Add the PKCS#1 v1.5 algorithm identifier prefix to hash bytes""" 508 hashName = hashName.lower() 509 assert hashName in cls._pkcs1Prefixes 510 prefixBytes = cls._pkcs1Prefixes[hashName] 511 return prefixBytes + data
512
513 - def _addPKCS1Padding(self, bytes, blockType):
514 padLength = (numBytes(self.n) - (len(bytes)+3)) 515 if blockType == 1: #Signature padding 516 pad = [0xFF] * padLength 517 elif blockType == 2: #Encryption padding 518 pad = bytearray(0) 519 while len(pad) < padLength: 520 padBytes = getRandomBytes(padLength * 2) 521 pad = [b for b in padBytes if b != 0] 522 pad = pad[:padLength] 523 else: 524 raise AssertionError() 525 526 padding = bytearray([0,blockType] + pad + [0]) 527 paddedBytes = padding + bytes 528 return paddedBytes
529