faset over fra Z3950 til google books
This commit is contained in:
264
python/gdata/tlslite/utils/RSAKey.py
Normal file
264
python/gdata/tlslite/utils/RSAKey.py
Normal file
@@ -0,0 +1,264 @@
|
||||
"""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
|
Reference in New Issue
Block a user