Implement RSASSA-PKCS1-v1_5 in dkim.crypto, and use that in verify() and sign(). Move str2int/int2str into dkim.crypto. Verification no longer does a constant-time string compare; there is no private key involved on which a timing attack could be performed.

This commit is contained in:
William Grant
2011-03-10 00:03:15 +11:00
parent 5898094fe1
commit c82703cea9
2 changed files with 57 additions and 46 deletions
+50
View File
@@ -21,6 +21,8 @@ __all__ = [
'EMSA_PKCS1_v1_5_encode',
'parse_private_key',
'parse_public_key',
'RSASSA_PKCS1_v1_5_sign',
'RSASSA_PKCS1_v1_5_verify',
]
from dkim.asn1 import (
@@ -108,3 +110,51 @@ def EMSA_PKCS1_v1_5_encode(digest, modlen, hashid):
raise Exception("Hash too large for modulus") # XXX: DKIMException
return "\x00\x01"+"\xff"*(modlen-len(dinfo)-3)+"\x00"+dinfo
def str2int(s):
"""Convert an octet string to an integer.
Octet string assumed to represent a positive integer.
"""
r = 0
for c in s:
r = (r << 8) | ord(c)
return r
def int2str(n, length = -1):
"""Convert an integer to an octet string. Number must be positive.
@param n: Number to convert.
@param length: Minimum length, or -1 to return the smallest number of
bytes that represent the integer.
"""
assert n >= 0
r = []
while length < 0 or len(r) < length:
r.append(chr(n & 0xff))
n >>= 8
if length < 0 and n == 0:
break
r.reverse()
assert length < 0 or len(r) == length
return ''.join(r)
def perform_rsa(input, exponent, modulus, modlen):
return int2str(pow(str2int(input), exponent, modulus), modlen)
def RSASSA_PKCS1_v1_5_sign(digest, hashid, private_exponent, modulus):
modlen = len(int2str(modulus))
encoded_digest = EMSA_PKCS1_v1_5_encode(digest, modlen, hashid)
return perform_rsa(encoded_digest, private_exponent, modulus, modlen)
def RSASSA_PKCS1_v1_5_verify(digest, hashid, signature, public_exponent,
modulus):
modlen = len(int2str(modulus))
encoded_digest = EMSA_PKCS1_v1_5_encode(digest, modlen, hashid)
signed_digest = perform_rsa(signature, public_exponent, modulus, modlen)
return encoded_digest == signed_digest