Merge pull request #3085 from SomberNight/aes_padding_pkcs7
bitcoin.py AES: implement our own PKCS7 padding
This commit is contained in:
commit
5cc71ef84b
|
@ -111,36 +111,56 @@ try:
|
||||||
except:
|
except:
|
||||||
AES = None
|
AES = None
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidPadding(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def append_PKCS7_padding(data):
|
||||||
|
assert_bytes(data)
|
||||||
|
padlen = 16 - (len(data) % 16)
|
||||||
|
return data + bytes([padlen]) * padlen
|
||||||
|
|
||||||
|
|
||||||
|
def strip_PKCS7_padding(data):
|
||||||
|
assert_bytes(data)
|
||||||
|
if len(data) % 16 != 0 or len(data) == 0:
|
||||||
|
raise InvalidPadding("invalid length")
|
||||||
|
padlen = data[-1]
|
||||||
|
if padlen > 16:
|
||||||
|
raise InvalidPadding("invalid padding byte (large)")
|
||||||
|
for i in data[-padlen:]:
|
||||||
|
if i != padlen:
|
||||||
|
raise InvalidPadding("invalid padding byte (inconsistent)")
|
||||||
|
return data[0:-padlen]
|
||||||
|
|
||||||
|
|
||||||
def aes_encrypt_with_iv(key, iv, data):
|
def aes_encrypt_with_iv(key, iv, data):
|
||||||
assert_bytes(key, iv, data)
|
assert_bytes(key, iv, data)
|
||||||
|
data = append_PKCS7_padding(data)
|
||||||
if AES:
|
if AES:
|
||||||
padlen = 16 - (len(data) % 16)
|
|
||||||
if padlen == 0:
|
|
||||||
padlen = 16
|
|
||||||
data += bytes([padlen]) * padlen
|
|
||||||
e = AES.new(key, AES.MODE_CBC, iv).encrypt(data)
|
e = AES.new(key, AES.MODE_CBC, iv).encrypt(data)
|
||||||
return e
|
|
||||||
else:
|
else:
|
||||||
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
||||||
aes = pyaes.Encrypter(aes_cbc)
|
aes = pyaes.Encrypter(aes_cbc, padding=pyaes.PADDING_NONE)
|
||||||
e = aes.feed(data) + aes.feed() # empty aes.feed() appends pkcs padding
|
e = aes.feed(data) + aes.feed() # empty aes.feed() flushes buffer
|
||||||
return e
|
return e
|
||||||
|
|
||||||
|
|
||||||
def aes_decrypt_with_iv(key, iv, data):
|
def aes_decrypt_with_iv(key, iv, data):
|
||||||
assert_bytes(key, iv, data)
|
assert_bytes(key, iv, data)
|
||||||
if AES:
|
if AES:
|
||||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||||
data = cipher.decrypt(data)
|
data = cipher.decrypt(data)
|
||||||
padlen = data[-1]
|
|
||||||
for i in data[-padlen:]:
|
|
||||||
if i != padlen:
|
|
||||||
raise InvalidPassword()
|
|
||||||
return data[0:-padlen]
|
|
||||||
else:
|
else:
|
||||||
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
||||||
aes = pyaes.Decrypter(aes_cbc)
|
aes = pyaes.Decrypter(aes_cbc, padding=pyaes.PADDING_NONE)
|
||||||
s = aes.feed(data) + aes.feed() # empty aes.feed() strips pkcs padding
|
data = aes.feed(data) + aes.feed() # empty aes.feed() flushes buffer
|
||||||
return s
|
try:
|
||||||
|
return strip_PKCS7_padding(data)
|
||||||
|
except InvalidPadding:
|
||||||
|
raise InvalidPassword()
|
||||||
|
|
||||||
|
|
||||||
def EncodeAES(secret, s):
|
def EncodeAES(secret, s):
|
||||||
assert_bytes(s)
|
assert_bytes(s)
|
||||||
|
|
|
@ -113,10 +113,6 @@ class Test_bitcoin(unittest.TestCase):
|
||||||
password = u"uber secret"
|
password = u"uber secret"
|
||||||
wrong_password = u"not the password"
|
wrong_password = u"not the password"
|
||||||
enc = pw_encode(payload, password)
|
enc = pw_encode(payload, password)
|
||||||
# FIXME: pyaes does not check that padding is consistent
|
|
||||||
# before removing it, wich causes this test to randomly fail.
|
|
||||||
# Wallets are unaffected by this, because check_password
|
|
||||||
# includes a test of the decoded public key.
|
|
||||||
self.assertRaises(Exception, pw_decode, enc, wrong_password)
|
self.assertRaises(Exception, pw_decode, enc, wrong_password)
|
||||||
|
|
||||||
def test_hash(self):
|
def test_hash(self):
|
||||||
|
|
Loading…
Reference in New Issue