Index: third_party/tlslite/tlslite/utils/rsakey.py |
diff --git a/third_party/tlslite/tlslite/utils/rsakey.py b/third_party/tlslite/tlslite/utils/rsakey.py |
index 1b917428f595e316d6c68098f53bd8c4b0594740..3f2100ebc0d09b3d9d96b7be8b4fc9fc2925775a 100644 |
--- a/third_party/tlslite/tlslite/utils/rsakey.py |
+++ b/third_party/tlslite/tlslite/utils/rsakey.py |
@@ -1,15 +1,18 @@ |
+# Author: Trevor Perrin |
+# See the LICENSE file for legal information regarding use of this file. |
+ |
"""Abstract class for RSA.""" |
-from cryptomath import * |
+from .cryptomath import * |
-class RSAKey: |
+class RSAKey(object): |
"""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}, |
+ 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 |
@@ -44,36 +47,19 @@ class RSAKey: |
""" |
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 |
+ @type bytes: str or L{bytearray} of unsigned bytes |
@param bytes: The value which will be hashed and signed. |
- @rtype: L{array.array} of unsigned bytes. |
+ @rtype: L{bytearray} of unsigned bytes. |
@return: A PKCS1-SHA1 signature on the passed-in data. |
""" |
- if not isinstance(bytes, type("")): |
- bytes = bytesToString(bytes) |
- hashBytes = stringToBytes(sha.sha(bytes).digest()) |
+ hashBytes = SHA1(bytearray(bytes)) |
prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes) |
sigBytes = self.sign(prefixedHashBytes) |
return sigBytes |
@@ -83,20 +69,23 @@ class RSAKey: |
This verifies a PKCS1-SHA1 signature on the passed-in data. |
- @type sigBytes: L{array.array} of unsigned bytes |
+ @type sigBytes: L{bytearray} of unsigned bytes |
@param sigBytes: A PKCS1-SHA1 signature. |
- @type bytes: str or L{array.array} of unsigned bytes |
+ @type bytes: str or L{bytearray} 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(sha.sha(bytes).digest()) |
- prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes) |
- return self.verify(sigBytes, prefixedHashBytes) |
+ hashBytes = SHA1(bytearray(bytes)) |
+ |
+ # Try it with/without the embedded NULL |
+ prefixedHashBytes1 = self._addPKCS1SHA1Prefix(hashBytes, False) |
+ prefixedHashBytes2 = self._addPKCS1SHA1Prefix(hashBytes, True) |
+ result1 = self.verify(sigBytes, prefixedHashBytes1) |
+ result2 = self.verify(sigBytes, prefixedHashBytes2) |
+ return (result1 or result2) |
def sign(self, bytes): |
"""Sign the passed-in bytes. |
@@ -104,10 +93,10 @@ class RSAKey: |
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 |
+ @type bytes: L{bytearray} of unsigned bytes |
@param bytes: The value which will be signed. |
- @rtype: L{array.array} of unsigned bytes. |
+ @rtype: L{bytearray} of unsigned bytes. |
@return: A PKCS1 signature on the passed-in data. |
""" |
if not self.hasPrivateKey(): |
@@ -117,7 +106,7 @@ class RSAKey: |
if m >= self.n: |
raise ValueError() |
c = self._rawPrivateKeyOp(m) |
- sigBytes = numberToBytes(c, numBytes(self.n)) |
+ sigBytes = numberToByteArray(c, numBytes(self.n)) |
return sigBytes |
def verify(self, sigBytes, bytes): |
@@ -125,21 +114,23 @@ class RSAKey: |
This verifies a PKCS1 signature on the passed-in data. |
- @type sigBytes: L{array.array} of unsigned bytes |
+ @type sigBytes: L{bytearray} of unsigned bytes |
@param sigBytes: A PKCS1 signature. |
- @type bytes: L{array.array} of unsigned bytes |
+ @type bytes: L{bytearray} of unsigned bytes |
@param bytes: The value which will be verified. |
@rtype: bool |
@return: Whether the signature matches the passed-in data. |
""" |
+ if len(sigBytes) != numBytes(self.n): |
+ return False |
paddedBytes = self._addPKCS1Padding(bytes, 1) |
c = bytesToNumber(sigBytes) |
if c >= self.n: |
return False |
m = self._rawPublicKeyOp(c) |
- checkBytes = numberToBytes(m) |
+ checkBytes = numberToByteArray(m, numBytes(self.n)) |
return checkBytes == paddedBytes |
def encrypt(self, bytes): |
@@ -147,10 +138,10 @@ class RSAKey: |
This performs PKCS1 encryption of the passed-in data. |
- @type bytes: L{array.array} of unsigned bytes |
+ @type bytes: L{bytearray} of unsigned bytes |
@param bytes: The value which will be encrypted. |
- @rtype: L{array.array} of unsigned bytes. |
+ @rtype: L{bytearray} of unsigned bytes. |
@return: A PKCS1 encryption of the passed-in data. |
""" |
paddedBytes = self._addPKCS1Padding(bytes, 2) |
@@ -158,7 +149,7 @@ class RSAKey: |
if m >= self.n: |
raise ValueError() |
c = self._rawPublicKeyOp(m) |
- encBytes = numberToBytes(c) |
+ encBytes = numberToByteArray(c, numBytes(self.n)) |
return encBytes |
def decrypt(self, encBytes): |
@@ -167,25 +158,27 @@ class RSAKey: |
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 |
+ @type encBytes: L{bytearray} of unsigned bytes |
@param encBytes: The value which will be decrypted. |
- @rtype: L{array.array} of unsigned bytes or None. |
+ @rtype: L{bytearray} 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() |
+ if len(encBytes) != numBytes(self.n): |
+ return None |
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 |
+ decBytes = numberToByteArray(m, numBytes(self.n)) |
+ #Check first two bytes |
+ if decBytes[0] != 0 or decBytes[1] != 2: |
return None |
- if decBytes[0] != 2: #Check second byte |
- return None |
- for x in range(len(decBytes)-1): #Scan through for zero separator |
+ #Scan through for zero separator |
+ for x in range(1, len(decBytes)-1): |
if decBytes[x]== 0: |
break |
else: |
@@ -210,19 +203,11 @@ class RSAKey: |
"""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. |
+ @return: A string describing the key, in whichever format (PEM) |
+ 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. |
@@ -236,9 +221,22 @@ class RSAKey: |
# 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]) |
+ def _addPKCS1SHA1Prefix(self, bytes, withNULL=True): |
+ # There is a long history of confusion over whether the SHA1 |
+ # algorithmIdentifier should be encoded with a NULL parameter or |
+ # with the parameter omitted. While the original intention was |
+ # apparently to omit it, many toolkits went the other way. TLS 1.2 |
+ # specifies the NULL should be included, and this behavior is also |
+ # mandated in recent versions of PKCS #1, and is what tlslite has |
+ # always implemented. Anyways, verification code should probably |
+ # accept both. However, nothing uses this code yet, so this is |
+ # all fairly moot. |
+ if not withNULL: |
+ prefixBytes = bytearray(\ |
+ [0x30,0x1f,0x30,0x07,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x04,0x14]) |
+ else: |
+ prefixBytes = bytearray(\ |
+ [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14]) |
prefixedBytes = prefixBytes + bytes |
return prefixedBytes |
@@ -247,7 +245,7 @@ class RSAKey: |
if blockType == 1: #Signature padding |
pad = [0xFF] * padLength |
elif blockType == 2: #Encryption padding |
- pad = createByteArraySequence([]) |
+ pad = bytearray(0) |
while len(pad) < padLength: |
padBytes = getRandomBytes(padLength * 2) |
pad = [b for b in padBytes if b != 0] |
@@ -255,10 +253,6 @@ class RSAKey: |
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]) |
+ padding = bytearray([0,blockType] + pad + [0]) |
paddedBytes = padding + bytes |
return paddedBytes |