/gdata/tlslite/utils/RSAKey.py
Python | 264 lines | 249 code | 3 blank | 12 comment | 0 complexity | a283269588835f9b2756b0b2217875fe MD5 | raw file
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(sha1(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(sha1(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