Apply performance patch from bug#901591

This commit is contained in:
Stuart D. Gathman
2012-02-03 17:10:49 -05:00
parent e40148a7b3
commit 644916a653
4 changed files with 76 additions and 50 deletions
+3
View File
@@ -1,3 +1,6 @@
2012-02-03 Version 0.5.1
- Apply performance patch from <https://launchpad.net/bugs/901591>
2011-10-26 Version 0.5 2011-10-26 Version 0.5
- Add test case and fix for <https://launchpad.net/bugs/644046> - Add test case and fix for <https://launchpad.net/bugs/644046>
- Add test case and fix for <https://launchpad.net/bugs/737311> - Add test case and fix for <https://launchpad.net/bugs/737311>
+2 -4
View File
@@ -450,8 +450,7 @@ class DKIM(object):
self.logger.debug("sign headers: %r" % self.signed_headers) self.logger.debug("sign headers: %r" % self.signed_headers)
try: try:
sig2 = RSASSA_PKCS1_v1_5_sign( sig2 = RSASSA_PKCS1_v1_5_sign(h, pk)
h, pk['privateExponent'], pk['modulus'])
except DigestTooLargeError: except DigestTooLargeError:
raise ParameterError("digest too large for modulus") raise ParameterError("digest too large for modulus")
sig_value += base64.b64encode(bytes(sig2)) sig_value += base64.b64encode(bytes(sig2))
@@ -545,8 +544,7 @@ class DKIM(object):
try: try:
self.signature_fields = sig self.signature_fields = sig
signature = base64.b64decode(re.sub(br"\s+", b"", sig[b'b'])) signature = base64.b64decode(re.sub(br"\s+", b"", sig[b'b']))
return RSASSA_PKCS1_v1_5_verify( return RSASSA_PKCS1_v1_5_verify(h, signature, pk)
h, signature, pk['publicExponent'], pk['modulus'])
except (TypeError,DigestTooLargeError) as e: except (TypeError,DigestTooLargeError) as e:
raise KeyFormatError("digest too large for modulus: %s"%e) raise KeyFormatError("digest too large for modulus: %s"%e)
+34 -15
View File
@@ -213,41 +213,60 @@ def int2str(n, length=-1):
return r return r
def perform_rsa(message, exponent, modulus, mlen): def rsa_decrypt(message, pk, mlen):
"""Perform RSA signing or verification. """Perform RSA decryption/signing
@param message: byte string to operate on @param message: byte string to operate on
@param exponent: public or private key exponent @param pk: private key data
@param modulus: key modulus
@param mlen: desired output length @param mlen: desired output length
@return: byte string result of the operation @return: byte string result of the operation
""" """
return int2str(pow(str2int(message), exponent, modulus), mlen) c = str2int(message)
m1 = pow(c, pk['exponent1'], pk['prime1'])
m2 = pow(c, pk['exponent2'], pk['prime2'])
if m1 < m2:
h = pk['coefficient'] * (m1 + pk['prime1'] - m2) % pk['prime1']
else:
h = pk['coefficient'] * (m1 - m2) % pk['prime1']
return int2str(m2 + h * pk['prime2'], mlen)
def RSASSA_PKCS1_v1_5_sign(hash, private_exponent, modulus): def rsa_encrypt(message, pk, mlen):
"""Perform RSA encryption/verification
@param message: byte string to operate on
@param pk: public key data
@param mlen: desired output length
@return: byte string result of the operation
"""
m = str2int(message)
return int2str(pow(m, pk['publicExponent'], pk['modulus']), mlen)
def RSASSA_PKCS1_v1_5_sign(hash, private_key):
"""Sign a digest with RFC3447 RSASSA-PKCS1-v1_5. """Sign a digest with RFC3447 RSASSA-PKCS1-v1_5.
@param hash: hash object to sign @param hash: hash object to sign
@param private_exponent: private key exponent @param private_key: private key data
@param modulus: key modulus
@return: signed digest byte string @return: signed digest byte string
""" """
modlen = len(int2str(modulus)) modlen = len(int2str(private_key['modulus']))
encoded_digest = EMSA_PKCS1_v1_5_encode(hash, modlen) encoded_digest = EMSA_PKCS1_v1_5_encode(hash, modlen)
return perform_rsa(encoded_digest, private_exponent, modulus, modlen) return rsa_decrypt(encoded_digest, private_key, modlen)
def RSASSA_PKCS1_v1_5_verify(hash, signature, public_exponent, modulus): def RSASSA_PKCS1_v1_5_verify(hash, signature, public_key):
"""Verify a digest signed with RFC3447 RSASSA-PKCS1-v1_5. """Verify a digest signed with RFC3447 RSASSA-PKCS1-v1_5.
@param hash: hash object to check @param hash: hash object to check
@param signature: signed digest byte string @param signature: signed digest byte string
@param public_exponent: public key exponent @param public_key: public key data
@param modulus: key modulus
@return: True if the signature is valid, False otherwise @return: True if the signature is valid, False otherwise
""" """
modlen = len(int2str(modulus)) modlen = len(int2str(public_key['modulus']))
encoded_digest = EMSA_PKCS1_v1_5_encode(hash, modlen) encoded_digest = EMSA_PKCS1_v1_5_encode(hash, modlen)
signed_digest = perform_rsa(signature, public_exponent, modulus, modlen) signed_digest = rsa_encrypt(signature, public_key, modlen)
return encoded_digest == signed_digest return encoded_digest == signed_digest
+37 -31
View File
@@ -27,7 +27,6 @@ from dkim.crypto import (
int2str, int2str,
parse_pem_private_key, parse_pem_private_key,
parse_public_key, parse_public_key,
perform_rsa,
RSASSA_PKCS1_v1_5_sign, RSASSA_PKCS1_v1_5_sign,
RSASSA_PKCS1_v1_5_verify, RSASSA_PKCS1_v1_5_verify,
str2int, str2int,
@@ -50,6 +49,37 @@ TEST_KEY_PRIVATE_EXPONENT = int(
'489900956461640273471526152019568303807247290486052565153701534491987040' '489900956461640273471526152019568303807247290486052565153701534491987040'
'131529720476525111651818771481293273124837542067061293644354088836358900' '131529720476525111651818771481293273124837542067061293644354088836358900'
'29771161475005043329') '29771161475005043329')
TEST_KEY_PRIME1 = int(
'127343333492908149956322715568115237787784712176275919666517073343689103'
'280591709737233188193431204382936008602497360201661766158158969883295914'
'16266272177')
TEST_KEY_PRIME2 = int(
'125793967926229270607412639516115399484604596465353856808629588968254772'
'302339293254103556785310783521521266982500068526354237606773478050287350'
'33316975853')
TEST_KEY_EXPONENT1 = int(
'971401692373919639404678505179789291960987093676634885925231250693661495'
'080125935714710587508461815572290443270923375888685273287584323569222368'
'5450962737')
TEST_KEY_EXPONENT2 = int(
'405135004809332318340885085107137607293826268763328174261828392259785080'
'028911220030572618988900118679333717167345003034279703551607153395397272'
'3014807045')
TEST_KEY_COEFFICIENT = int(
'933140693852464192207530806898449261372116224159220632563973880414444021'
'989007318611849609226428922185905596238131661588470844906391982906126973'
'1282880267')
TEST_PK = {
'version': 0,
'modulus': TEST_KEY_MODULUS,
'publicExponent': TEST_KEY_PUBLIC_EXPONENT,
'privateExponent': TEST_KEY_PRIVATE_EXPONENT,
'prime1': TEST_KEY_PRIME1,
'prime2': TEST_KEY_PRIME2,
'exponent1': TEST_KEY_EXPONENT1,
'exponent2': TEST_KEY_EXPONENT2,
'coefficient': TEST_KEY_COEFFICIENT,
}
class TestStrIntConversion(unittest.TestCase): class TestStrIntConversion(unittest.TestCase):
@@ -71,9 +101,7 @@ class TestParseKeys(unittest.TestCase):
def test_parse_pem_private_key(self): def test_parse_pem_private_key(self):
key = parse_pem_private_key(read_test_data('test.private')) key = parse_pem_private_key(read_test_data('test.private'))
self.assertEqual(key['modulus'], TEST_KEY_MODULUS) self.assertEqual(key, TEST_PK)
self.assertEqual(key['publicExponent'], TEST_KEY_PUBLIC_EXPONENT)
self.assertEqual(key['privateExponent'], TEST_KEY_PRIVATE_EXPONENT)
def test_parse_public_key(self): def test_parse_public_key(self):
data = read_test_data('test.txt') data = read_test_data('test.txt')
@@ -109,27 +137,6 @@ class TestEMSA_PKCS1_v1_5(unittest.TestCase):
EMSA_PKCS1_v1_5_encode, hash, 45) EMSA_PKCS1_v1_5_encode, hash, 45)
class TestRSA(unittest.TestCase):
message = binascii.unhexlify(b'0004fb')
modulus = 186101
modlen = 3
public_exponent = 907
private_exponent = 2851
def test_perform(self):
signed = perform_rsa(
self.message, self.private_exponent, self.modulus, self.modlen)
self.assertEqual(binascii.unhexlify(b'01f140'), signed)
def test_sign_and_verify(self):
signed = perform_rsa(
self.message, self.private_exponent, self.modulus, self.modlen)
unsigned = perform_rsa(
signed, self.public_exponent, self.modulus, self.modlen)
self.assertEqual(self.message, unsigned)
class TestRSASSA(unittest.TestCase): class TestRSASSA(unittest.TestCase):
def setUp(self): def setUp(self):
@@ -144,19 +151,18 @@ class TestRSASSA(unittest.TestCase):
b'39d2d6ab8b215b19be0e69ef490885004a474eb26d747a219693e8c') b'39d2d6ab8b215b19be0e69ef490885004a474eb26d747a219693e8c')
def test_sign_and_verify(self): def test_sign_and_verify(self):
signature = RSASSA_PKCS1_v1_5_sign( signature = RSASSA_PKCS1_v1_5_sign(self.hash, TEST_PK)
self.hash, TEST_KEY_PRIVATE_EXPONENT, TEST_KEY_MODULUS)
self.assertEqual(self.test_signature, signature) self.assertEqual(self.test_signature, signature)
self.assertTrue( self.assertTrue(
RSASSA_PKCS1_v1_5_verify( RSASSA_PKCS1_v1_5_verify(
self.hash, signature, TEST_KEY_PUBLIC_EXPONENT, self.hash, signature, TEST_PK))
TEST_KEY_MODULUS))
def test_invalid_signature(self): def test_invalid_signature(self):
invalid_key = TEST_PK.copy()
invalid_key['modulus'] += 1
self.assertFalse( self.assertFalse(
RSASSA_PKCS1_v1_5_verify( RSASSA_PKCS1_v1_5_verify(
self.hash, self.test_signature, TEST_KEY_PUBLIC_EXPONENT, self.hash, self.test_signature, invalid_key))
TEST_KEY_MODULUS + 1))
def test_suite(): def test_suite():