Viewing file: RSAKey.py (8.37 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
"""Abstract class for RSA."""
from cryptomath import *
class RSAKey: """This is an abstract base class for RSA keys.
Particular implementations of RSA keys, such as L{OpenSSL_RSAKey.OpenSSL_RSAKey}, L{Python_RSAKey.Python_RSAKey}, and L{PyCrypto_RSAKey.PyCrypto_RSAKey}, inherit from this.
To create or parse an RSA key, don't use one of these classes directly. Instead, use the factory functions in L{tlslite.utils.keyfactory}. """
def __init__(self, n=0, e=0): """Create a new RSA key.
If n and e are passed in, the new key will be initialized.
@type n: int @param n: RSA modulus.
@type e: int @param e: RSA public exponent. """ raise NotImplementedError()
def __len__(self): """Return the length of this key in bits.
@rtype: int """ return numBits(self.n)
def hasPrivateKey(self): """Return whether or not this key has a private component.
@rtype: bool """ raise NotImplementedError()
def hash(self): """Return the cryptoID <keyHash> value corresponding to this key.
@rtype: str """ raise NotImplementedError()
def getSigningAlgorithm(self): """Return the cryptoID sigAlgo value corresponding to this key.
@rtype: str """ return "pkcs1-sha1"
def hashAndSign(self, bytes): """Hash and sign the passed-in bytes.
This requires the key to have a private component. It performs a PKCS1-SHA1 signature on the passed-in data.
@type bytes: str or L{array.array} of unsigned bytes @param bytes: The value which will be hashed and signed.
@rtype: L{array.array} of unsigned bytes. @return: A PKCS1-SHA1 signature on the passed-in data. """ if not isinstance(bytes, type("")): bytes = bytesToString(bytes) hashBytes = stringToBytes(sha1(bytes).digest()) prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes) sigBytes = self.sign(prefixedHashBytes) return sigBytes
def hashAndVerify(self, sigBytes, bytes): """Hash and verify the passed-in bytes with the signature.
This verifies a PKCS1-SHA1 signature on the passed-in data.
@type sigBytes: L{array.array} of unsigned bytes @param sigBytes: A PKCS1-SHA1 signature.
@type bytes: str or L{array.array} of unsigned bytes @param bytes: The value which will be hashed and verified.
@rtype: bool @return: Whether the signature matches the passed-in data. """ if not isinstance(bytes, type("")): bytes = bytesToString(bytes) hashBytes = stringToBytes(sha1(bytes).digest()) prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes) return self.verify(sigBytes, prefixedHashBytes)
def sign(self, bytes): """Sign the passed-in bytes.
This requires the key to have a private component. It performs a PKCS1 signature on the passed-in data.
@type bytes: L{array.array} of unsigned bytes @param bytes: The value which will be signed.
@rtype: L{array.array} of unsigned bytes. @return: A PKCS1 signature on the passed-in data. """ if not self.hasPrivateKey(): raise AssertionError() paddedBytes = self._addPKCS1Padding(bytes, 1) m = bytesToNumber(paddedBytes) if m >= self.n: raise ValueError() c = self._rawPrivateKeyOp(m) sigBytes = numberToBytes(c) return sigBytes
def verify(self, sigBytes, bytes): """Verify the passed-in bytes with the signature.
This verifies a PKCS1 signature on the passed-in data.
@type sigBytes: L{array.array} of unsigned bytes @param sigBytes: A PKCS1 signature.
@type bytes: L{array.array} of unsigned bytes @param bytes: The value which will be verified.
@rtype: bool @return: Whether the signature matches the passed-in data. """ paddedBytes = self._addPKCS1Padding(bytes, 1) c = bytesToNumber(sigBytes) if c >= self.n: return False m = self._rawPublicKeyOp(c) checkBytes = numberToBytes(m) return checkBytes == paddedBytes
def encrypt(self, bytes): """Encrypt the passed-in bytes.
This performs PKCS1 encryption of the passed-in data.
@type bytes: L{array.array} of unsigned bytes @param bytes: The value which will be encrypted.
@rtype: L{array.array} of unsigned bytes. @return: A PKCS1 encryption of the passed-in data. """ paddedBytes = self._addPKCS1Padding(bytes, 2) m = bytesToNumber(paddedBytes) if m >= self.n: raise ValueError() c = self._rawPublicKeyOp(m) encBytes = numberToBytes(c) return encBytes
def decrypt(self, encBytes): """Decrypt the passed-in bytes.
This requires the key to have a private component. It performs PKCS1 decryption of the passed-in data.
@type encBytes: L{array.array} of unsigned bytes @param encBytes: The value which will be decrypted.
@rtype: L{array.array} of unsigned bytes or None. @return: A PKCS1 decryption of the passed-in data or None if the data is not properly formatted. """ if not self.hasPrivateKey(): raise AssertionError() c = bytesToNumber(encBytes) if c >= self.n: return None m = self._rawPrivateKeyOp(c) decBytes = numberToBytes(m) if (len(decBytes) != numBytes(self.n)-1): #Check first byte return None if decBytes[0] != 2: #Check second byte return None for x in range(len(decBytes)-1): #Scan through for zero separator if decBytes[x]== 0: break else: return None return decBytes[x+1:] #Return everything after the separator
def _rawPrivateKeyOp(self, m): raise NotImplementedError()
def _rawPublicKeyOp(self, c): raise NotImplementedError()
def acceptsPassword(self): """Return True if the write() method accepts a password for use in encrypting the private key.
@rtype: bool """ raise NotImplementedError()
def write(self, password=None): """Return a string containing the key.
@rtype: str @return: A string describing the key, in whichever format (PEM or XML) is native to the implementation. """ raise NotImplementedError()
def writeXMLPublicKey(self, indent=''): """Return a string containing the key.
@rtype: str @return: A string describing the public key, in XML format. """ return Python_RSAKey(self.n, self.e).write(indent)
def generate(bits): """Generate a new key with the specified bit length.
@rtype: L{tlslite.utils.RSAKey.RSAKey} """ raise NotImplementedError() generate = staticmethod(generate)
# ************************************************************************** # Helper Functions for RSA Keys # **************************************************************************
def _addPKCS1SHA1Prefix(self, bytes): prefixBytes = createByteArraySequence(\ [48,33,48,9,6,5,43,14,3,2,26,5,0,4,20]) prefixedBytes = prefixBytes + bytes return prefixedBytes
def _addPKCS1Padding(self, bytes, blockType): padLength = (numBytes(self.n) - (len(bytes)+3)) if blockType == 1: #Signature padding pad = [0xFF] * padLength elif blockType == 2: #Encryption padding pad = createByteArraySequence([]) while len(pad) < padLength: padBytes = getRandomBytes(padLength * 2) pad = [b for b in padBytes if b != 0] pad = pad[:padLength] else: raise AssertionError()
#NOTE: To be proper, we should add [0,blockType]. However, #the zero is lost when the returned padding is converted #to a number, so we don't even bother with it. Also, #adding it would cause a misalignment in verify() padding = createByteArraySequence([blockType] + pad + [0]) paddedBytes = padding + bytes return paddedBytes
|