URI: 
       tMerge pull request #3085 from SomberNight/aes_padding_pkcs7 - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 5cc71ef84bec9ca39c5e13e689e5a50b92955dc4
   DIR parent 42f9d1ee6375d467fc40ee845dc6bc1a4cc6d7fd
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Sun, 22 Oct 2017 08:34:29 +0200
       
       Merge pull request #3085 from SomberNight/aes_padding_pkcs7
       
       bitcoin.py AES: implement our own PKCS7 padding
       Diffstat:
         M lib/bitcoin.py                      |      52 +++++++++++++++++++++----------
         M lib/tests/test_bitcoin.py           |       4 ----
       
       2 files changed, 36 insertions(+), 20 deletions(-)
       ---
   DIR diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -111,36 +111,56 @@ try:
        except:
            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):
            assert_bytes(key, iv, data)
       +    data = append_PKCS7_padding(data)
            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)
       -        return e
            else:
                aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
       -        aes = pyaes.Encrypter(aes_cbc)
       -        e = aes.feed(data) + aes.feed()  # empty aes.feed() appends pkcs padding
       -        return e
       +        aes = pyaes.Encrypter(aes_cbc, padding=pyaes.PADDING_NONE)
       +        e = aes.feed(data) + aes.feed()  # empty aes.feed() flushes buffer
       +    return e
       +
        
        def aes_decrypt_with_iv(key, iv, data):
            assert_bytes(key, iv, data)
            if AES:
                cipher = AES.new(key, AES.MODE_CBC, iv)
                data = cipher.decrypt(data)
       -        padlen = data[-1]
       -        for i in data[-padlen:]:
       -            if i != padlen:
       -                raise InvalidPassword()
       -        return data[0:-padlen]
            else:
                aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
       -        aes = pyaes.Decrypter(aes_cbc)
       -        s = aes.feed(data) + aes.feed()  # empty aes.feed() strips pkcs padding
       -        return s
       +        aes = pyaes.Decrypter(aes_cbc, padding=pyaes.PADDING_NONE)
       +        data = aes.feed(data) + aes.feed()  # empty aes.feed() flushes buffer
       +    try:
       +        return strip_PKCS7_padding(data)
       +    except InvalidPadding:
       +        raise InvalidPassword()
       +
        
        def EncodeAES(secret, s):
            assert_bytes(s)
   DIR diff --git a/lib/tests/test_bitcoin.py b/lib/tests/test_bitcoin.py
       t@@ -113,10 +113,6 @@ class Test_bitcoin(unittest.TestCase):
                password = u"uber secret"
                wrong_password = u"not the 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)
        
            def test_hash(self):