Esempio n. 1
0
    def test_memoryview(self):
        data = b"1" * 16
        data_mv = memoryview(bytearray(data))

        # Encrypt
        key_mv = memoryview(bytearray(self.key_128))
        iv_mv = memoryview(bytearray(self.iv_128))

        cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128)
        ref1 = cipher1.encrypt(data)

        cipher2 = AES.new(key_mv, self.aes_mode, iv_mv)
        key_mv[:3] = b'\xFF\xFF\xFF'
        iv_mv[:3] = b'\xFF\xFF\xFF'
        ref2 = cipher2.encrypt(data_mv)

        self.assertEqual(ref1, ref2)
        self.assertEqual(cipher1.iv, cipher2.iv)

        # Decrypt
        key_mv = memoryview(bytearray(self.key_128))
        iv_mv = memoryview(bytearray(self.iv_128))

        cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128)
        ref3 = cipher3.decrypt(data)

        cipher4 = AES.new(key_mv, self.aes_mode, iv_mv)
        key_mv[:3] = b'\xFF\xFF\xFF'
        iv_mv[:3] = b'\xFF\xFF\xFF'
        ref4 = cipher4.decrypt(data_mv)

        self.assertEqual(ref3, ref4)
Esempio n. 2
0
    def test_output_param(self):

        pt = b'5' * 16
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
        ct = cipher.encrypt(pt)
        tag = cipher.digest()

        output = bytearray(16)
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
        res = cipher.encrypt(pt, output=output)
        self.assertEqual(ct, output)
        self.assertEqual(res, None)
        
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
        res = cipher.decrypt(ct, output=output)
        self.assertEqual(pt, output)
        self.assertEqual(res, None)
        
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
        res, tag_out = cipher.encrypt_and_digest(pt, output=output)
        self.assertEqual(ct, output)
        self.assertEqual(res, None)
        self.assertEqual(tag, tag_out)
        
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
        res = cipher.decrypt_and_verify(ct, tag, output=output)
        self.assertEqual(pt, output)
        self.assertEqual(res, None)
Esempio n. 3
0
    def test_invalid_multiple_decrypt_and_verify(self):
        cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
        ct, tag = cipher.encrypt_and_digest(self.data_128)

        cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
        cipher.decrypt_and_verify(ct, tag)
        self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag)
    def test_shorter_assoc_data_than_expected(self):
        # With plaintext
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
                         assoc_len=17)
        cipher.update(self.data_128)
        self.assertRaises(ValueError, cipher.encrypt, self.data_128)

        # With empty plaintext
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
                         assoc_len=17)
        cipher.update(self.data_128)
        self.assertRaises(ValueError, cipher.digest)

        # With ciphertext
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
                         assoc_len=17)
        cipher.update(self.data_128)
        self.assertRaises(ValueError, cipher.decrypt, self.data_128)

        # With empty ciphertext
        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96)
        cipher.update(self.data_128)
        mac = cipher.digest()

        cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96,
                         assoc_len=17)
        cipher.update(self.data_128)
        self.assertRaises(ValueError, cipher.verify, mac)
    def test_data_must_be_bytes(self):
        cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
        self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')

        cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96)
        self.assertRaises(TypeError, cipher.decrypt_and_verify,
                          u'test1234567890-*', b("xxxx"))
Esempio n. 6
0
    def test_bytearray(self):
        data = b"1" * 16
        iv = b"\x00" * 6 + b"\xFF\xFF"

        # Encrypt
        cipher1 = AES.new(self.key_128, AES.MODE_CTR,
                          nonce=self.nonce_64,
                          initial_value=iv)
        ref1 = cipher1.encrypt(data)

        cipher2 = AES.new(self.key_128, AES.MODE_CTR,
                          nonce=bytearray(self.nonce_64),
                          initial_value=bytearray(iv))
        ref2 = cipher2.encrypt(bytearray(data))

        self.assertEqual(ref1, ref2)
        self.assertEqual(cipher1.nonce, cipher2.nonce)

        # Decrypt
        cipher3 = AES.new(self.key_128, AES.MODE_CTR,
                          nonce=self.nonce_64,
                          initial_value=iv)
        ref3 = cipher3.decrypt(data)

        cipher4 = AES.new(self.key_128, AES.MODE_CTR,
                          nonce=bytearray(self.nonce_64),
                          initial_value=bytearray(iv))
        ref4 = cipher4.decrypt(bytearray(data))

        self.assertEqual(ref3, ref4)
def _aes_CTR_cipher(key, nonce, block_index=0, little_endian=False):
    if little_endian:
        counter = Cryptodome.Util.Counter.new(
            nbits=64, prefix=nonce, initial_value=block_index, little_endian=True)
        return AES.new(key, AES.MODE_CTR, counter=counter)
    else:
        return AES.new(key, AES.MODE_CTR, nonce=nonce, initial_value=block_index)
    def test_aes_256(self):
        plaintext =     '6bc1bee22e409f96e93d7e117393172a' +\
                        'ae2d8a571e03ac9c9eb76fac45af8e51' +\
                        '30c81c46a35ce411e5fbc1191a0a52ef' +\
                        'f69f2445df4f9b17ad2b417be66c3710'
        ciphertext =    'dc7e84bfda79164b7ecd8486985d3860' +\
                        '4febdc6740d20b3ac88f6ad82a4fb08d' +\
                        '71ab47a086e86eedf39d1c5bba97c408' +\
                        '0126141d67f37be8538f5a8be740e484'
        key =           '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'
        iv =            '000102030405060708090a0b0c0d0e0f'

        key = unhexlify(key)
        iv = unhexlify(iv)
        plaintext = unhexlify(plaintext)
        ciphertext = unhexlify(ciphertext)

        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.encrypt(plaintext), ciphertext)
        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.decrypt(ciphertext), plaintext)

        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8])
        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
    def test_aes_192(self):
        plaintext =     '6bc1bee22e409f96e93d7e117393172a' +\
                        'ae2d8a571e03ac9c9eb76fac45af8e51' +\
                        '30c81c46a35ce411e5fbc1191a0a52ef' +\
                        'f69f2445df4f9b17ad2b417be66c3710'
        ciphertext =    'cdc80d6fddf18cab34c25909c99a4174' +\
                        'fcc28b8d4c63837c09e81700c1100401' +\
                        '8d9a9aeac0f6596f559c6d4daf59a5f2' +\
                        '6d9f200857ca6c3e9cac524bd9acc92a'
        key =           '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
        iv =            '000102030405060708090a0b0c0d0e0f'

        key = unhexlify(key)
        iv = unhexlify(iv)
        plaintext = unhexlify(plaintext)
        ciphertext = unhexlify(ciphertext)

        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.encrypt(plaintext), ciphertext)
        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.decrypt(ciphertext), plaintext)

        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8])
        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
Esempio n. 10
0
    def test_valid_init_verify(self):
        # Verify path INIT->VERIFY
        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        mac = cipher.digest()

        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        cipher.verify(mac)
Esempio n. 11
0
    def test_hex_mac(self):
        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        mac_hex = cipher.hexdigest()
        self.assertEqual(cipher.digest(), unhexlify(mac_hex))

        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        cipher.hexverify(mac_hex)
Esempio n. 12
0
    def test3(self):

        for keylen, taglen, result in self.tv3:

            key = bchr(0) * (keylen // 8 - 1) + bchr(taglen)
            C = b("")

            for i in range(128):
                S = bchr(0) * i

                N = long_to_bytes(3 * i + 1, 12)
                cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
                cipher.update(S)
                C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()

                N = long_to_bytes(3 * i + 2, 12)
                cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
                C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest()

                N = long_to_bytes(3 * i + 3, 12)
                cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
                cipher.update(S)
                C += cipher.encrypt() + cipher.digest()

            N = long_to_bytes(385, 12)
            cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8)
            cipher.update(C)
            result2 = cipher.encrypt() + cipher.digest()
            self.assertEquals(unhexlify(b(result)), result2)
Esempio n. 13
0
    def test_unaligned_data_128(self):
        plaintexts = [ b"7777777" ] * 100

        cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
        ciphertexts = [ cipher.encrypt(x) for x in plaintexts ]
        cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
        self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts)))
Esempio n. 14
0
    def test_IV_iv_attributes(self):
        cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
        eiv = cipher.encrypt(b"")
        self.assertEqual(cipher.iv, self.iv_128)

        cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv)
        self.assertEqual(cipher.iv, self.iv_128)
Esempio n. 15
0
    def test_bytearray(self):
        data = b"1" * 16
        data_ba = bytearray(data)

        # Encrypt
        key_ba = bytearray(self.key_128)
        iv_ba = bytearray(self.iv_128)

        cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128)
        ref1 = cipher1.encrypt(data)

        cipher2 = AES.new(key_ba, self.aes_mode, iv_ba)
        key_ba[:3] = b'\xFF\xFF\xFF'
        iv_ba[:3] = b'\xFF\xFF\xFF'
        ref2 = cipher2.encrypt(data_ba)

        self.assertEqual(ref1, ref2)
        self.assertEqual(cipher1.iv, cipher2.iv)

        # Decrypt
        key_ba = bytearray(self.key_128)
        iv_ba = bytearray(self.iv_128)

        cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128)
        ref3 = cipher3.decrypt(data)

        cipher4 = AES.new(key_ba, self.aes_mode, iv_ba)
        key_ba[:3] = b'\xFF\xFF\xFF'
        iv_ba[:3] = b'\xFF\xFF\xFF'
        ref4 = cipher4.decrypt(data_ba)

        self.assertEqual(ref3, ref4)
Esempio n. 16
0
    def test_aes_128(self):
        plaintext =     '6bc1bee22e409f96e93d7e117393172a' +\
                        'ae2d8a571e03ac9c9eb76fac45af8e51' +\
                        '30c81c46a35ce411e5fbc1191a0a52ef' +\
                        'f69f2445df4f9b17ad2b417be66c3710'
        ciphertext =    '3b3fd92eb72dad20333449f8e83cfb4a' +\
                        '7789508d16918f03f53c52dac54ed825' +\
                        '9740051e9c5fecf64344f7a82260edcc' +\
                        '304c6528f659c77866a510d9c1d6ae5e'
        key =           '2b7e151628aed2a6abf7158809cf4f3c'
        iv =            '000102030405060708090a0b0c0d0e0f'

        key = unhexlify(key)
        iv = unhexlify(iv)
        plaintext = unhexlify(plaintext)
        ciphertext = unhexlify(ciphertext)

        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.encrypt(plaintext), ciphertext)
        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.decrypt(ciphertext), plaintext)

        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8])
        cipher = AES.new(key, AES.MODE_OFB, iv)
        self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8])
Esempio n. 17
0
    def test_nonce_parameter(self):
        # Nonce parameter becomes nonce attribute
        cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64)
        self.assertEqual(cipher1.nonce, self.nonce_64)

        counter = Counter.new(64, prefix=self.nonce_64, initial_value=0)
        cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter)
        self.assertEqual(cipher1.nonce, cipher2.nonce)

        pt = get_tag_random("plaintext", 65536)
        self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt))

        # Nonce is implicitly created (for AES) when no parameters are passed
        nonce1 = AES.new(self.key_128, AES.MODE_CTR).nonce
        nonce2 = AES.new(self.key_128, AES.MODE_CTR).nonce
        self.assertNotEqual(nonce1, nonce2)
        self.assertEqual(len(nonce1), 8)

        # Nonce can be zero-length
        cipher = AES.new(self.key_128, AES.MODE_CTR, nonce=b"")
        self.assertEqual(b"", cipher.nonce)
        cipher.encrypt(b'0'*300)

        # Nonce and Counter are mutually exclusive
        self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR,
                          counter=self.ctr_128, nonce=self.nonce_64)
Esempio n. 18
0
 def test_unknown_parameters(self):
     self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode,
                       self.iv_128, 7)
     self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode,
                       iv=self.iv_128, unknown=7)
     # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module)
     AES.new(self.key_128, self.aes_mode, iv=self.iv_128, use_aesni=False)
Esempio n. 19
0
 def test_unknown_parameters(self):
     self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR,
                       7, counter=self.ctr_128)
     self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR,
                       counter=self.ctr_128, unknown=7)
     # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module)
     AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128, use_aesni=False)
Esempio n. 20
0
def decrypt(secretkey, params):
    iv = b64decode(params['iv'])
    salt = b64decode(params['salt'])
    #~ keylen = params.get('ks', 128) // 8 # FIXME use somewhere?
    taglen = params.get('ts', 64) // 8
    iterations = params.get('iter', 1000)
    data = b64decode(params['ct'])
    ciphertext = data[:-taglen]
    tag = data[-taglen:]

    if params.get('adata'):
        raise NotImplementedError('authenticated data support is not implemented')

    iv = trunc_iv(iv, ciphertext, taglen)

    hash_func = lambda k, s: HMAC.new(k, s, SHA256).digest()
    key = PBKDF2(secretkey, salt=salt, count=iterations, prf=hash_func)

    mode_str = params.get('mode', 'ccm')
    mode = dict(ccm=AES.MODE_CCM)[mode_str]
    if mode_str == 'ccm':
        cipher = AES.new(key, mode=AES.MODE_CCM, nonce=iv, mac_len=taglen)
    else:
        cipher = AES.new(key, mode=mode, iv=iv)
    decrypted = cipher.decrypt_and_verify(ciphertext, tag)
    return decrypted
Esempio n. 21
0
    def test_either_encrypt_or_decrypt(self):
        cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128)
        eiv = cipher.encrypt(b"")
        self.assertRaises(TypeError, cipher.decrypt, b"")

        cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv)
        cipher.decrypt(b"")
        self.assertRaises(TypeError, cipher.encrypt, b"")
Esempio n. 22
0
    def test_loopback_128(self):
        cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
        pt = get_tag_random("plaintext", 16 * 100)
        ct = cipher.encrypt(pt)

        cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
        pt2 = cipher.decrypt(ct)
        self.assertEqual(pt, pt2)
Esempio n. 23
0
    def test_loopback_128(self):
        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        pt = get_tag_random("plaintext", 16 * 100)
        ct, mac = cipher.encrypt_and_digest(pt)

        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        pt2 = cipher.decrypt_and_verify(ct, mac)
        self.assertEqual(pt, pt2)
Esempio n. 24
0
    def test_loopback_128(self):
        cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
        pt = get_tag_random("plaintext", 16 * 100)
        ct = cipher.encrypt(pt)

        cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
        pt2 = cipher.decrypt(ct)
        self.assertEqual(pt, pt2)
Esempio n. 25
0
    def test_either_encrypt_or_decrypt(self):
        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        cipher.encrypt(b("xyz"))
        self.assertRaises(TypeError, cipher.decrypt, b("xyz"))

        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        cipher.decrypt(b("xyz"))
        self.assertRaises(TypeError, cipher.encrypt, b("xyz"))
Esempio n. 26
0
    def test_either_encrypt_or_decrypt(self):
        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        cipher.encrypt(b(""))
        self.assertRaises(TypeError, cipher.decrypt, b(""))

        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        cipher.decrypt(b(""))
        self.assertRaises(TypeError, cipher.encrypt, b(""))
Esempio n. 27
0
 def initialize_cipher(self):
     """Creates the cipher-related objects needed for AES-CTR
     encryption and decryption.
     """
     self.ctr_e = Counter.new(self.AES_block_size, initial_value=self.iv)
     self.ctr_d = Counter.new(self.AES_block_size, initial_value=self.iv)
     self.encryptor = AES.new(self.key, AES.MODE_CTR, counter=self.ctr_e)
     self.decryptor = AES.new(self.key, AES.MODE_CTR, counter=self.ctr_d)
Esempio n. 28
0
    def test_loopback_128(self):
        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        pt = get_tag_random("plaintext", 16 * 100)
        ct = cipher.encrypt(pt)

        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        pt2 = cipher.decrypt(ct)
        self.assertEqual(pt, pt2)
Esempio n. 29
0
    def test_unaligned_data_128(self):
        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        for wrong_length in xrange(1,16):
            self.assertRaises(ValueError, cipher.encrypt, b("5") * wrong_length)

        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        for wrong_length in xrange(1,16):
            self.assertRaises(ValueError, cipher.decrypt, b("5") * wrong_length)
Esempio n. 30
0
    def test_either_encrypt_or_decrypt(self):
        cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
        cipher.encrypt(b"")
        self.assertRaises(TypeError, cipher.decrypt, b"")

        cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128)
        cipher.decrypt(b"")
        self.assertRaises(TypeError, cipher.encrypt, b"")
Esempio n. 31
0
def decrypt_pairing_response(enc_pairing_response):

    """
    Parses and decrypts a pairing response into a named tuple PairingResponse
    consisting of

    * user_public_key - the user's public key
    * user_token_id   - an id for the client to uniquely identify the token.
                        this id is necessary, because the client could
                        communicate with more than one linotp, so serials
                        could overlap.
    * serial - the serial identifying the token in linotp
    * user_login - the user login name

    It is possible that either user_login or serial is None. Both
    being None is a valid response according to this function but
    will be considered an error in the calling method.

    The following parameters are needed:

    :param enc_pairing_response:
        The urlsafe-base64 encoded string received from the client

    The following exceptions can be raised:

    :raises ParameterError:
        If the pairing response has an invalid format

    :raises ValueError:
        If the pairing response has a different version
        than this implementation (currently hardcoded)

    :raises ValueError:
        If the pairing response indicates a different
        token type than QRToken (also hardcoded)

    :raises ValueError:
        If the pairing response field "partition" is not
        identical to the field "token_type"
        ("partition" is currently used for the token
        type id. It is reserved for multiple key usage
        in a future implementation.)

    :raises ValueError:
        If the MAC of the response didn't match

    :return:
        Parsed/decrypted PairingReponse
    """

    data = decode_base64_urlsafe(enc_pairing_response)

    # ---------------------------------------------------------------------- --

    #            ------------------------------------------- --
    #  fields   | version | partition | R  | ciphertext | MAC |
    #            ------------------------------------------- --
    #  size     |    1    |     4     | 32 |      ?     | 16  |
    #            ------------------------------------------- --

    if len(data) < 1 + 4 + 32 + 16:
        raise ParameterError('Malformed pairing response')

    # ---------------------------------------------------------------------- --

    # parse header

    header = data[0:5]
    version, partition = struct.unpack('<bI', header)

    if version != PAIR_RESPONSE_VERSION:
        raise ValueError('Unexpected pair-response version, '
                         'expected: %d, got: %d' %
                         (PAIR_RESPONSE_VERSION, version))

    # ---------------------------------------------------------------------- --

    R = data[5:32+5]
    ciphertext = data[32+5:-16]
    mac = data[-16:]

    # ---------------------------------------------------------------------- --

    # calculate the shared secret

    # - --

    secret_key = get_dh_secret_key(partition)
    ss = calc_dh(secret_key, R)

    # derive encryption key and nonce from the shared secret
    # zero the values from memory when they are not longer needed
    U = SHA256.new(ss).digest()
    zerome(ss)
    encryption_key = U[0:16]
    nonce = U[16:32]
    zerome(U)

    # decrypt response
    cipher = AES.new(encryption_key, AES.MODE_EAX, nonce)
    cipher.update(header)
    plaintext = cipher.decrypt_and_verify(ciphertext, mac)
    zerome(encryption_key)

    # ---------------------------------------------------------------------- --

    # check format boundaries for type peaking
    # (token type specific length boundaries are checked
    #  in the appropriate functions)

    plaintext_min_length = 1
    if len(data) < plaintext_min_length:
        raise ParameterError('Malformed pairing response')

    # ---------------------------------------------------------------------- --

    # get token type and parse decrypted response

    #            -------------------- --
    #  fields   | token type |   ...   |
    #            -------------------- --
    #  size     |     1      |    ?    |
    #            -------------------- --

    token_type = struct.unpack('<b', plaintext[0])[0]

    if token_type not in SUPPORTED_TOKEN_TYPES:
        raise ValueError('unsupported token type %d, supported types '
                         'are %s' % (token_type, SUPPORTED_TOKEN_TYPES))

    # ---------------------------------------------------------------------- --

    # delegate the data parsing of the plaintext
    # to the appropriate function and return the result

    data_parser = get_pairing_data_parser(token_type)
    pairing_data = data_parser(plaintext)
    zerome(plaintext)

    # get the appropriate high level type

    try:
        token_type_as_str = INV_TOKEN_TYPES[token_type]
    except KeyError:
        raise ProgrammingError('token_type %d is in SUPPORTED_TOKEN_TYPES',
                               'however an appropriate mapping entry in '
                               'TOKEN_TYPES is missing' % token_type)

    return PairingResponse(token_type_as_str, pairing_data)
Esempio n. 32
0
 def test_null_encryption_decryption(self):
     for func in "encrypt", "decrypt":
         cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
         result = getattr(cipher, func)(b(""))
         self.assertEqual(result, b(""))
Esempio n. 33
0
    def test_data_must_be_bytes(self):
        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')

        cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
        self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
Esempio n. 34
0
 def test_null_encryption_decryption(self):
     for func in "encrypt", "decrypt":
         cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
         result = getattr(cipher, func)(b(""))
         self.assertEqual(result, b(""))
Esempio n. 35
0
    def getDBfromFile(kInfoFile):
        names = [\
            b'kindle.account.tokens',\
            b'kindle.cookie.item',\
            b'eulaVersionAccepted',\
            b'login_date',\
            b'kindle.token.item',\
            b'login',\
            b'kindle.key.item',\
            b'kindle.name.info',\
            b'kindle.device.info',\
            b'MazamaRandomNumber',\
            b'max_date',\
            b'SIGVERIF',\
            b'build_version',\
            b'SerialNumber',\
            b'UsernameHash',\
            b'kindle.directedid.info',\
            b'DSN',\
            b'kindle.accounttype.info',\
            b'krx.flashcardsplugin.data.encryption_key',\
            b'krx.notebookexportplugin.data.encryption_key',\
            b'proxy.http.password',\
            b'proxy.http.username'
            ]
        with open(kInfoFile, 'rb') as infoReader:
            filedata = infoReader.read()

        data = filedata[:-1]
        items = data.split(b'/')
        IDStrings = GetIDStrings()
        print("trying username ", GetUserName(), " on file ", kInfoFile)
        for IDString in IDStrings:
            print("trying IDString:", IDString)
            try:
                DB = {}
                items = data.split(b'/')

                # the headerblob is the encrypted information needed to build the entropy string
                headerblob = items.pop(0)
                #print ("headerblob: ",headerblob)
                encryptedValue = decode(headerblob, charMap1)
                #print ("encryptedvalue: ",encryptedValue)
                cleartext = UnprotectHeaderData(encryptedValue)
                #print ("cleartext: ",cleartext)

                # now extract the pieces in the same way
                pattern = re.compile(
                    br'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''',
                    re.IGNORECASE)
                for m in re.finditer(pattern, cleartext):
                    version = int(m.group(1))
                    build = m.group(2)
                    guid = m.group(4)

                #print ("version",version)
                #print ("build",build)
                #print ("guid",guid,"\n")

                if version == 5:  # .kinf2011: identical to K4PC, except the build number gets multiplied
                    entropy = str(0x2df * int(build)).encode('utf-8') + guid
                    cud = CryptUnprotectData(entropy, IDString)
                    #print ("entropy",entropy)
                    #print ("cud",cud)

                elif version == 6:  # .kinf2018: identical to K4PC
                    salt = str(0x6d8 * int(build)).encode('utf-8') + guid
                    sp = GetUserName() + b'+@#$%+' + IDString
                    passwd = encode(SHA256(sp), charMap5)
                    key = PBKDF2(passwd, salt, count=10000, dkLen=0x400)[:32]

                    #print ("salt",salt)
                    #print ("sp",sp)
                    #print ("passwd",passwd)
                    #print ("key",key)

            # loop through the item records until all are processed
                while len(items) > 0:

                    # get the first item record
                    item = items.pop(0)

                    # the first 32 chars of the first record of a group
                    # is the MD5 hash of the key name encoded by charMap5
                    keyhash = item[0:32]
                    keyname = b'unknown'

                    # unlike K4PC the keyhash is not used in generating entropy
                    # entropy = SHA1(keyhash) + added_entropy
                    # entropy = added_entropy

                    # the remainder of the first record when decoded with charMap5
                    # has the ':' split char followed by the string representation
                    # of the number of records that follow
                    # and make up the contents
                    srcnt = decode(item[34:], charMap5)
                    rcnt = int(srcnt)

                    # read and store in rcnt records of data
                    # that make up the contents value
                    edlst = []
                    for i in range(rcnt):
                        item = items.pop(0)
                        edlst.append(item)

                    keyname = b'unknown'
                    for name in names:
                        if encodeHash(name, testMap8) == keyhash:
                            keyname = name
                            break
                    if keyname == b'unknown':
                        keyname = keyhash

                    # the testMap8 encoded contents data has had a length
                    # of chars (always odd) cut off of the front and moved
                    # to the end to prevent decoding using testMap8 from
                    # working properly, and thereby preventing the ensuing
                    # CryptUnprotectData call from succeeding.

                    # The offset into the testMap8 encoded contents seems to be:
                    # len(contents) - largest prime number less than or equal to int(len(content)/3)
                    # (in other words split 'about' 2/3rds of the way through)

                    # move first offsets chars to end to align for decode by testMap8
                    encdata = b''.join(edlst)
                    contlen = len(encdata)

                    # now properly split and recombine
                    # by moving noffset chars from the start of the
                    # string to the end of the string
                    noffset = contlen - primes(int(contlen / 3))[-1]
                    pfx = encdata[0:noffset]
                    encdata = encdata[noffset:]
                    encdata = encdata + pfx

                    if version == 5:
                        # decode using testMap8 to get the CryptProtect Data
                        encryptedValue = decode(encdata, testMap8)
                        cleartext = cud.decrypt(encryptedValue)

                    elif version == 6:
                        # decode using new testMap8 to get IV + ciphertext
                        iv_ciphertext = decode(encdata, testMap8)
                        # pad IV so that we can substitute AES-CTR for GCM
                        iv = iv_ciphertext[:12] + b'\x00\x00\x00\x02'
                        ciphertext = iv_ciphertext[12:]
                        # convert IV to int for use with pycrypto
                        iv_ints = unpack('>QQ', iv)
                        iv = iv_ints[0] << 64 | iv_ints[1]
                        # set up AES-CTR
                        ctr = Counter.new(128, initial_value=iv)
                        cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
                        # decrypt and decode
                        cleartext = decode(cipher.decrypt(ciphertext),
                                           charMap5)

                    # print keyname
                    # print cleartext
                    if len(cleartext) > 0:
                        DB[keyname] = cleartext

                if len(DB) > 6:
                    break

            except Exception:
                print(traceback.format_exc())
                pass
        if len(DB) > 6:
            # store values used in decryption
            print(
                "Decrypted key file using IDString '{0:s}' and UserName '{1:s}'"
                .format(IDString.decode('utf-8'),
                        GetUserName().decode('utf-8')))
            DB[b'IDString'] = IDString
            DB[b'UserName'] = GetUserName()
        else:
            print("Couldn't decrypt file.")
            DB = {}
        return DB
def generateCipher(AESkey, iv):
    return AES.new(AESkey, AES.MODE_GCM, iv)
Esempio n. 37
0
 def test_invalid_decrypt_after_final(self):
     cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
     cipher.update(self.data_128)
     cipher.decrypt(self.data_128)
     cipher.decrypt()
     self.assertRaises(TypeError, cipher.decrypt, self.data_128)
Esempio n. 38
0
    def parse_xiaomi(self, data, xiaomi_index, is_ext_packet):
        # parse BLE message in Xiaomi MiBeacon format
        firmware = "Xiaomi (MiBeacon)"

        # check for no BR/EDR + LE General discoverable mode flags
        advert_start = 29 if is_ext_packet else 14
        adv_index = data.find(b"\x02\x01\x06", advert_start, 3 + advert_start)
        adv_index2 = data.find(b"\x15\x16\x95", advert_start, 3 + advert_start)
        if adv_index == -1 and adv_index2 == -1:
            raise NoValidError("Invalid index")
        if adv_index2 != -1:
            adv_index = adv_index2

        # check for BTLE msg size
        msg_length = data[2] + 3
        if msg_length != len(data):
            raise NoValidError("Invalid msg size")

        # extract device type
        device_type = data[xiaomi_index + 5:xiaomi_index + 7]

        # extract frame control bits
        framectrl_data = data[xiaomi_index + 3:xiaomi_index + 5]
        framectrl, = struct.unpack('>H', framectrl_data)

        # flag advertisements without mac address in service data
        if device_type == b'\xF6\x07' and framectrl_data == b'\x48\x59':
            # MJYD02YL does not have a MAC address in the service data of some advertisements
            mac_in_service_data = False
        elif device_type == b'\xDD\x03' and framectrl_data == b'\x40\x30':
            # MUE4094RT does not have a MAC address in the service data
            mac_in_service_data = False
        else:
            mac_in_service_data = True

        # check for MAC presence in message and in service data
        mac_index = adv_index - 14 if is_ext_packet else adv_index
        if mac_in_service_data is True:
            xiaomi_mac_reversed = data[xiaomi_index + 8:xiaomi_index + 14]
            source_mac_reversed = data[mac_index - 7:mac_index - 1]
            if xiaomi_mac_reversed != source_mac_reversed:
                raise NoValidError("Invalid MAC address")
        else:
            # for sensors without mac in service data, use the first mac in advertisment
            xiaomi_mac_reversed = data[mac_index - 7:mac_index - 1]

        # check for MAC presence in whitelist, if needed
        if self.discovery is False and xiaomi_mac_reversed not in self.whitelist:
            return None, None, None
        packet_id = data[xiaomi_index + 7]
        try:
            prev_packet = self.lpacket_ids[xiaomi_mac_reversed]
        except KeyError:
            # start with empty first packet
            prev_packet = None, None, None
        if prev_packet == packet_id:
            # only process new messages
            return None, None, None
        self.lpacket_ids[xiaomi_mac_reversed] = packet_id

        # extract RSSI byte
        rssi_index = 18 if is_ext_packet else msg_length - 1
        (rssi,) = struct.unpack("<b", data[rssi_index:rssi_index + 1])

        # strange positive RSSI workaround
        if rssi > 0:
            rssi = -rssi
        try:
            sensor_type, binary_data = XIAOMI_TYPE_DICT[device_type]
        except KeyError:
            if self.report_unknown:
                _LOGGER.info(
                    "BLE ADV from UNKNOWN: RSSI: %s, MAC: %s, ADV: %s",
                    rssi,
                    ''.join('{:02X}'.format(x) for x in xiaomi_mac_reversed[::-1]),
                    data.hex()
                )
            raise NoValidError("Device unkown")

        # check data is present
        if not (framectrl & 0x4000):
            return {
                "rssi": rssi,
                "mac": ''.join('{:02X}'.format(x) for x in xiaomi_mac_reversed[::-1]),
                "type": sensor_type,
                "packet": packet_id,
                "firmware": firmware,
                "data": False,
            }, None, None
        xdata_length = 0
        xdata_point = 0

        # check capability byte present
        if framectrl & 0x2000:
            xdata_length = -1
            xdata_point = 1

        # check for messages without mac address in service data
        if mac_in_service_data is False:
            xdata_length = +6
            xdata_point = -6

        # parse_xiaomi data length = message length
        #     -all bytes before XiaomiUUID
        #     -3 bytes Xiaomi UUID + ADtype
        #     -1 byte rssi
        #     -3+1 bytes sensor type
        #     -1 byte packet_id
        #     -6 bytes MAC (if present)
        #     -capability byte offset
        xdata_length += msg_length - xiaomi_index - 15
        if xdata_length < 3:
            raise NoValidError("Xdata length invalid")

        xdata_point += xiaomi_index + 14

        # check if parse_xiaomi data start and length is valid
        if xdata_length != len(data[xdata_point:-1]):
            raise NoValidError("Invalid data length")

        # check encrypted data flags
        if framectrl & 0x0800:
            # try to find encryption key for current device
            try:
                key = self.aeskeys[xiaomi_mac_reversed]
            except KeyError:
                # no encryption key found
                raise NoValidError("No encryption key found")
            nonce = b"".join(
                [
                    xiaomi_mac_reversed,
                    device_type,
                    data[xiaomi_index + 7:xiaomi_index + 8]
                ]
            )
            endoffset = msg_length - int(not is_ext_packet)
            encrypted_payload = data[xdata_point:endoffset]
            aad = b"\x11"
            token = encrypted_payload[-4:]
            payload_counter = encrypted_payload[-7:-4]
            nonce = b"".join([nonce, payload_counter])
            cipherpayload = encrypted_payload[:-7]
            cipher = AES.new(key, AES.MODE_CCM, nonce=nonce, mac_len=4)
            cipher.update(aad)

            try:
                decrypted_payload = cipher.decrypt_and_verify(cipherpayload, token)
            except ValueError as error:
                _LOGGER.error("Decryption failed: %s", error)
                _LOGGER.error("token: %s", token.hex())
                _LOGGER.error("nonce: %s", nonce.hex())
                _LOGGER.error("encrypted_payload: %s", encrypted_payload.hex())
                _LOGGER.error("cipherpayload: %s", cipherpayload.hex())
                raise NoValidError("Error decrypting with arguments")
            if decrypted_payload is None:
                _LOGGER.error(
                    "Decryption failed for %s, decrypted payload is None",
                    "".join("{:02X}".format(x) for x in xiaomi_mac_reversed[::-1]),
                )
                raise NoValidError("Decryption failed")

            # replace cipher with decrypted data
            msg_length -= len(encrypted_payload)
            if is_ext_packet:
                data = b"".join((data[:xdata_point], decrypted_payload))
            else:
                data = b"".join((data[:xdata_point], decrypted_payload, data[-1:]))
            msg_length += len(decrypted_payload)

        result = {
            "rssi": rssi,
            "mac": ''.join('{:02X}'.format(x) for x in xiaomi_mac_reversed[::-1]),
            "type": sensor_type,
            "packet": packet_id,
            "firmware": firmware,
            "data": True,
        }
        binary = False
        measuring = False

        # loop through parse_xiaomi payload
        # assume that the data may have several values of different types,
        # although I did not notice this behavior with my LYWSDCGQ sensors
        while True:
            xvalue_typecode = data[xdata_point:xdata_point + 2]
            try:
                xvalue_length = data[xdata_point + 2]
            except ValueError as error:
                _LOGGER.error("xvalue_length conv. error: %s", error)
                _LOGGER.error("xdata_point: %s", xdata_point)
                _LOGGER.error("data: %s", data.hex())
                result = {}
                break
            except IndexError as error:
                _LOGGER.error("Wrong xdata_point: %s", error)
                _LOGGER.error("xdata_point: %s", xdata_point)
                _LOGGER.error("data: %s", data.hex())
                result = {}
                break

            xnext_point = xdata_point + 3 + xvalue_length
            xvalue = data[xdata_point + 3:xnext_point]
            resfunc, tbinary, tmeasuring = self._dataobject_dict.get(xvalue_typecode, (None, None, None))

            if resfunc:
                binary = binary or tbinary
                measuring = measuring or tmeasuring
                result.update(resfunc(xvalue))
            else:
                if self.report_unknown:
                    _LOGGER.info(
                        "UNKNOWN dataobject from DEVICE: %s, MAC: %s, ADV: %s",
                        sensor_type,
                        ''.join('{:02X}'.format(x) for x in xiaomi_mac_reversed[::-1]),
                        data.hex()
                    )

            if xnext_point > msg_length - 3:
                break
            xdata_point = xnext_point

        binary = binary and binary_data
        return result, binary, measuring
Esempio n. 39
0
 def test_block_size_128(self):
     cipher = AES.new(self.key_128, self.aes_mode, self.iv_128)
     self.assertEqual(cipher.block_size, AES.block_size)
Esempio n. 40
0
 def test_block_size_128(self):
     cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96)
     self.assertEqual(cipher.block_size, AES.block_size)
Esempio n. 41
0
 def encrypt(self, message, key, key_size=256):
     message = self.pad(message)
     iv = Random.new().read(AES.block_size)
     cipher = AES.new(key, AES.MODE_CBC, iv)
     return iv + cipher.encrypt(message)
Esempio n. 42
0
 def decrypt(self, ciphertext, key):
     iv = ciphertext[:AES.block_size]
     cipher = AES.new(key, AES.MODE_CBC, iv)
     plaintext = cipher.decrypt(ciphertext[AES.block_size:])
     return plaintext.rstrip(b"\0")
Esempio n. 43
0
    def getDBfromFile(kInfoFile):
        names = [\
            b'kindle.account.tokens',\
            b'kindle.cookie.item',\
            b'eulaVersionAccepted',\
            b'login_date',\
            b'kindle.token.item',\
            b'login',\
            b'kindle.key.item',\
            b'kindle.name.info',\
            b'kindle.device.info',\
            b'MazamaRandomNumber',\
            b'max_date',\
            b'SIGVERIF',\
            b'build_version',\
            b'SerialNumber',\
            b'UsernameHash',\
            b'kindle.directedid.info',\
            b'DSN',\
            b'kindle.accounttype.info',\
            b'krx.flashcardsplugin.data.encryption_key',\
            b'krx.notebookexportplugin.data.encryption_key',\
            b'proxy.http.password',\
            b'proxy.http.username'
            ]
        namehashmap = {encodeHash(n, testMap8): n for n in names}
        # print(namehashmap)
        DB = {}
        with open(kInfoFile, 'rb') as infoReader:
            data = infoReader.read()
        # assume .kinf2011 or .kinf2018 style .kinf file
        # the .kinf file uses "/" to separate it into records
        # so remove the trailing "/" to make it easy to use split
        data = data[:-1]
        items = data.split(b'/')

        # starts with an encoded and encrypted header blob
        headerblob = items.pop(0)
        encryptedValue = decode(headerblob, testMap1)
        cleartext = UnprotectHeaderData(encryptedValue)
        #print "header  cleartext:",cleartext
        # now extract the pieces that form the added entropy
        pattern = re.compile(
            br'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''',
            re.IGNORECASE)
        for m in re.finditer(pattern, cleartext):
            version = int(m.group(1))
            build = m.group(2)
            guid = m.group(4)

        if version == 5:  # .kinf2011
            added_entropy = build + guid
        elif version == 6:  # .kinf2018
            salt = str(0x6d8 * int(build)).encode('utf-8') + guid
            sp = GetUserName() + b'+@#$%+' + GetIDString().encode('utf-8')
            passwd = encode(SHA256(sp), charMap5)
            key = PBKDF2(passwd, salt, count=10000,
                         dkLen=0x400)[:32]  # this is very slow

        # loop through the item records until all are processed
        while len(items) > 0:

            # get the first item record
            item = items.pop(0)

            # the first 32 chars of the first record of a group
            # is the MD5 hash of the key name encoded by charMap5
            keyhash = item[0:32]

            # the remainder of the first record when decoded with charMap5
            # has the ':' split char followed by the string representation
            # of the number of records that follow
            # and make up the contents
            srcnt = decode(item[34:], charMap5)
            rcnt = int(srcnt)

            # read and store in rcnt records of data
            # that make up the contents value
            edlst = []
            for i in range(rcnt):
                item = items.pop(0)
                edlst.append(item)

            # key names now use the new testMap8 encoding
            if keyhash in namehashmap:
                keyname = namehashmap[keyhash]
                #print "keyname found from hash:",keyname
            else:
                keyname = keyhash
                #print "keyname not found, hash is:",keyname

            # the testMap8 encoded contents data has had a length
            # of chars (always odd) cut off of the front and moved
            # to the end to prevent decoding using testMap8 from
            # working properly, and thereby preventing the ensuing
            # CryptUnprotectData call from succeeding.

            # The offset into the testMap8 encoded contents seems to be:
            # len(contents)-largest prime number <=  int(len(content)/3)
            # (in other words split "about" 2/3rds of the way through)

            # move first offsets chars to end to align for decode by testMap8
            # by moving noffset chars from the start of the
            # string to the end of the string
            encdata = b"".join(edlst)
            #print "encrypted data:",encdata
            contlen = len(encdata)
            noffset = contlen - primes(int(contlen / 3))[-1]
            pfx = encdata[0:noffset]
            encdata = encdata[noffset:]
            encdata = encdata + pfx
            #print "rearranged data:",encdata

            if version == 5:
                # decode using new testMap8 to get the original CryptProtect Data
                encryptedValue = decode(encdata, testMap8)
                #print "decoded data:",encryptedValue.encode('hex')
                entropy = SHA1(keyhash) + added_entropy
                cleartext = CryptUnprotectData(encryptedValue, entropy, 1)
            elif version == 6:
                # decode using new testMap8 to get IV + ciphertext
                iv_ciphertext = decode(encdata, testMap8)
                # pad IV so that we can substitute AES-CTR for GCM
                iv = iv_ciphertext[:12] + b'\x00\x00\x00\x02'
                ciphertext = iv_ciphertext[12:]
                # convert IV to int for use with pycrypto
                iv_ints = unpack('>QQ', iv)
                iv = iv_ints[0] << 64 | iv_ints[1]
                # set up AES-CTR
                ctr = Counter.new(128, initial_value=iv)
                cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
                # decrypt and decode
                cleartext = decode(cipher.decrypt(ciphertext), charMap5)

            if len(cleartext) > 0:
                #print "cleartext data:",cleartext,":end data"
                DB[keyname] = cleartext
            #print keyname, cleartext

        if len(DB) > 6:
            # store values used in decryption
            DB[b'IDString'] = GetIDString().encode('utf-8')
            DB[b'UserName'] = GetUserName()
            print(
                "Decrypted key file using IDString '{0:s}' and UserName '{1:s}'"
                .format(GetIDString(),
                        GetUserName().decode('utf-8')))
        else:
            print("Couldn't decrypt file.")
            DB = {}
        return DB
    def decrypt_file(metadata,
                     encryption_material,
                     in_filename,
                     chunk_size=block_size * 4 * 1024,
                     tmp_dir=None):
        """
        Decrypts a file and stores the output in the temporary directory
        :param metadata: metadata input
        :param encryption_material: encryption material
        :param in_filename: input file name
        :param chunk_size: read chunk size
        :param tmp_dir: temporary directory, optional
        :return: a decrypted file name
        """
        logger = getLogger(__name__)
        use_openssl_only = os.getenv('SF_USE_OPENSSL_ONLY', 'False') == 'True'
        key_base64 = metadata.key
        iv_base64 = metadata.iv
        decoded_key = base64.standard_b64decode(
            encryption_material.query_stage_master_key)
        key_bytes = base64.standard_b64decode(key_base64)
        iv_bytes = base64.standard_b64decode(iv_base64)

        if not use_openssl_only:
            key_cipher = AES.new(key=decoded_key, mode=AES.MODE_ECB)
            file_key = PKCS5_UNPAD(key_cipher.decrypt(key_bytes))
            data_cipher = AES.new(key=file_key, mode=AES.MODE_CBC, IV=iv_bytes)
        else:
            backend = default_backend()
            cipher = Cipher(algorithms.AES(decoded_key),
                            modes.ECB(),
                            backend=backend)
            decryptor = cipher.decryptor()
            file_key = PKCS5_UNPAD(
                decryptor.update(key_bytes) + decryptor.finalize())
            cipher = Cipher(algorithms.AES(file_key),
                            modes.CBC(iv_bytes),
                            backend=backend)
            decryptor = cipher.decryptor()

        temp_output_fd, temp_output_file = tempfile.mkstemp(
            text=False,
            dir=tmp_dir,
            prefix=os.path.basename(in_filename) + "#")
        total_file_size = 0
        prev_chunk = None
        logger.debug(u'encrypted file: %s, tmp file: %s', in_filename,
                     temp_output_file)
        with open(in_filename, u'rb') as infile:
            with os.fdopen(temp_output_fd, u'wb') as outfile:
                while True:
                    chunk = infile.read(chunk_size)
                    if len(chunk) == 0:
                        break
                    total_file_size += len(chunk)
                    if not use_openssl_only:
                        d = data_cipher.decrypt(chunk)
                    else:
                        d = decryptor.update(chunk)
                    outfile.write(d)
                    prev_chunk = d
                if prev_chunk is not None:
                    total_file_size -= PKCS5_OFFSET(prev_chunk)
                if use_openssl_only:
                    outfile.write(decryptor.finalize())
                outfile.truncate(total_file_size)
        return temp_output_file
Esempio n. 45
0
 def __init__(self, km200_host, gateway_password, private_password):
     self.km200_host = km200_host
     self.cipher = AES.new(
         self.create_decryption_key(gateway_password, private_password),
         AES.MODE_ECB)
     self.pool_manager = urllib3.PoolManager()
Esempio n. 46
0
def decrypt_key(p_encrypted_key):
    cipher = AES.new(K_PRIM, AES.MODE_ECB)
    print(">>Key was decrypted")
    return cipher.decrypt(p_encrypted_key)
Esempio n. 47
0
def q3_break_cbc_mac():
    """Question 3: Break CBC-MAC if used as a hash function

        In this question, You will show that CBC-MAC will fail 
        catastrophically if used as a hash function rather than as a MAC. 
        To explain the underlying issue, I reproduce a quote from the blog of 
        Prof. Matt Green at Johns Hopkins:
            "Cryptographic hash functions are public functions (i.e., no secret key) 
            that have the property of collision-resistance (it's hard to find two messages with the same hash). 
            MACs are keyed functions that (typically) provide message unforgeability -- a very different property. 
            Moreover, they guarantee this only when the key is secret."

        Let's make a (broken) hash function using CBC-MAC with a hardcoded key 'very secret key!'
            K = 'very secret key!'     # key is fixed and public
            def hash_from_cbcmac(M):
                return cbcmac(K, M)    # run CBC-MAC using this key

    Your Task:
            To solve this question, you probably need to revisit your CBC-MAC implementation
            from the previous lab and modify it to use AES (ECB-mode) as the block cipher (instead of `TOY`).

            Then, show that the hash function is broken by finding two colliding messages.
            Hmm, wait, that's too easy, and this is the final question of the lab. 
            So, let me make the question harder in a couple of ways. 

            First, rather than letting you choose the two messages, I'm going to fix one of 
            them for you. Ergo, you'll break the **second preimage resistance** game rather 
            than the **collision resistance** game. 

            Specifically: I'm going to choose the following message: 
                `msg = 'print("CBC-MAC is a very strong hash function!")'`

            Second, I want you to produce a collision that actually has some semantic value. 
            Observe that the original message is a valid Python3 program that can be executed 
            via the command `exec(msg)`. I want your collision to do the same.
    Your output:
            A string `collision` that simultaneously satisfies the following 5 properties.
                1. The `collision` string is exactly 3 blocks (aka 48 bytes) long.
                2. Its hash equals the following: `hash_from_cbcmac(msg) == hash_from_cbcmac(collision)`.
                3. The `collision` string contains only printable ASCII characters (i.e., characters in `string.printable`).
                4. The `collision` string is valid Python3 syntax.
                5. When executed via the command `exec(collision)`, the following text is printed to the terminal: "CBC-MAC not a hash"

            If you cannot find a string that simultaneously satisfies all 5 properties, then simply go as far down the list 
            of properties as you can for partial credit. Because there are multiple valid answers to this question, 
            I cannot provide any test vectors to you.

            Note that you only need to find **one** valid answer.
    """
    key = b'very secret key!'
    message = 'print("CBC-MAC is a very strong hash function!")'
    blocksToEncrypt = [message[i:i + 16] for i in range(0, len(message), 16)]
    cipherTexts = []
    intermediate_states = []
    cobj = AES.new(key, AES.MODE_ECB)
    x = cobj.encrypt(blocksToEncrypt[0].encode())
    x = x.hex()
    cipherTexts.append(x)
    for byte in blocksToEncrypt[1:]:
        y = strxor(unhexlify(x), byte.encode('ascii')).hex()
        intermediate_states.append(y)
        x = cobj.encrypt(unhexlify(y))
        x = x.hex()
        cipherTexts.append(x)
    X = bytes.fromhex(intermediate_states[1])
    while (True):
        randomMessage = message_generator(4)
        collisionMessage = "print('CBC-MAC not a hash')#"
        collisionMessage += randomMessage
        collision_blocks = [
            collisionMessage[i:i + 16]
            for i in range(0, len(collisionMessage), 16)
        ]
        col_x = cobj.encrypt(collision_blocks[0].encode())
        col_y = strxor(col_x, collision_blocks[1].encode('ascii'))
        col_x = cobj.encrypt(col_y)
        Y = col_x
        message3 = strxor(X, Y)
        if isPrintable(message3):
            #print (randomMessage)
            #print (message3.decode('ascii'))
            message = collisionMessage + message3.decode('ascii')
            if is_valid_python(message):
                return message
Esempio n. 48
0
 def test_valid_init_digest(self):
     # Verify path INIT->DIGEST
     cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
     cipher.digest()
Esempio n. 49
0
def encrypt(k, s):
    """
    Implement an Enc function in the paper.

    k: the key list generated by key_gen
    s: the original texts
    return: ciphertext tuple (d, c, l)
    """
    # build a tree upon the string s
    tree = SuffixTree(s)
    kd = k[0]
    kc = k[1]
    kl = k[2]
    k1 = k[3]
    k2 = k[4]
    k3 = k[5]
    k4 = k[6]
    d = {}
    nodes = []
    tree.get_nodes(tree.root, nodes)
    nodes.sort(key=operator.attrgetter('edge_label'))
    for node in nodes:
        children = []
        g2 = []
        for child in node.children:
            children.append(child)
            h2 = hmac.new(key=k2, digestmod=hashlib.sha256)
            h2.update(child.get_initial_path().encode('utf-8'))
            g2.append(h2.digest())
        for i in range(len(children), 128):
            h = hmac.new(key=secrets.token_bytes(LAMBDA),
                         digestmod=hashlib.sha256)
            g2.append(h.digest())
        piu = [i for i in range(0, 128)]
        random.Random(
            hashlib.blake2b(key=secrets.token_bytes(LAMBDA),
                            digest_size=LAMBDA)).shuffle(piu)
        f2 = [i for i in range(0, 128)]
        for i in range(0, 128):
            f2[i] = g2[piu[i]]
        h1 = hmac.new(key=k1, digestmod=hashlib.sha256)
        h1.update(node.get_initial_path().encode('utf-8'))
        f1 = h1.digest()
        xu = str(
            node.get_ind()) + '$' + str(tree.get_leafpos(node)) + '$' + str(
                tree.get_num(node)) + '$' + str(
                    node.get_len()) + '$' + f1.hex()
        for i in range(0, 128):
            xu += '$' + f2[i].hex()
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(kd, AES.MODE_CFB, iv)
        wu = iv.hex() + '$' + cipher.encrypt(xu.encode("utf8")).hex()
        vu = ''
        for i in range(0, 128):
            vu += f2[i].hex() + '$'
        vu += wu
        d[f1] = vu
    for i in range(0, 2 * len(s) - len(nodes)):
        dummy_string = []
        for j in range(0, 129):
            h = hashlib.blake2b(key=secrets.token_bytes(LAMBDA),
                                digest_size=LAMBDA)
            dummy_string.append(h.digest())
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(kd, AES.MODE_CFB, iv)
        enc0 = iv.hex() + '$' + cipher.encrypt(str(0).encode("utf8")).hex()
        dummy = ''
        for i in range(0, 128):
            dummy += dummy_string[i].hex() + '$'
        dummy += enc0
        d[dummy_string[128]] = dummy
    c = [i for i in range(0, len(s))]
    p = [i for i in range(0, len(s))]
    random.seed(k3)
    random.shuffle(p)
    for i in range(0, len(s)):
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(kc, AES.MODE_CFB, iv)
        c[p[i]] = iv.hex() + '$' + cipher.encrypt(
            (s[i] + '$' + str(i)).encode("utf8")).hex()
    l = [i for i in range(0, len(s))]
    p = [i for i in range(0, len(s))]
    random.seed(k4)
    random.shuffle(p)
    for i in range(0, len(s)):
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(kl, AES.MODE_CFB, iv)
        l[p[i]] = iv.hex() + '$' + cipher.encrypt(
            (str(tree.leaves[i].get_ind()) + '$' +
             str(i)).encode("utf8")).hex()
    return (d, c, l)
Esempio n. 50
0
    def activation_finalyze(self, random_bytes=None):

        R = self.get_r()
        params = {
            "action": "ActionFinalize",
            "mode": self.mode,
            "id": self.data.iwid,
            "lastsync": self.data.iwTsync,
            "version": "Generator-1.0/0.2.11",
            "lang": "fr",
            "ack": "",
            "macid": self.macid
        }
        if self.mode == Otp.OTP_MODE:
            params.update({"keytype": '0', "sid": self.data.iwsecid})

        elif self.mode == Otp.ACTIVATE_MODE:
            kma_crypt = self.cipher.encrypt(
                bytes.fromhex(self.generate_kma(self.codepin))).hex()
            pin_crypt = self.cipher.encrypt(self.codepin.encode("utf-8")).hex()
            params.update({
                "serial": self.get_serial(),
                "code": self.smsCode,
                "Kma": kma_crypt,
                "pin": pin_crypt,
                "name": "Android SDK built for x86_64 / UNKNOWN",
            })

        params.update(R)
        xml = self.request(params)
        if xml["err"] != "OK":
            logger.error("Error during activation: %s", xml)
            return Otp.NOK
        self.data.synchro(xml, self.generate_kma(self.codepin))

        if self.mode == Otp.OTP_MODE:
            try:
                self.defi = str(xml["defi"])
            except KeyError:
                raise ConfigException
            if "J" in xml:
                logger.debug("Need another otp request")
                return Otp.OTP_TWICE
            return Otp.OK

        if "ms_n" not in xml or xml["ms_n"] == 0:
            logger.debug("no ms_n request needed")
            return Otp.OK

        if int(xml["ms_n"]) > 1:
            raise NotImplementedError
        ms_n = "0"

        self.challenge = xml["challenge"]
        self.action = "synchro"
        res = self.decode_oaep(xml["ms_key"], self.Kfact)
        temp_key = RSA.construct((int(res, 16), self.exponent))
        temp_cipher = oaep.new(temp_key, hash_algo=Hash.SHA256)
        if random_bytes is None:
            random_bytes = token_bytes(16)
        kpub_encode = temp_cipher.encrypt(random_bytes)

        aes_cipher = AES.new(bytes.fromhex(self.generate_kma(self.codepin)),
                             AES.MODE_ECB)
        encode_aes_from_hex = aes_cipher.encrypt(random_bytes).hex()
        self.data.iwsecval = encode_aes_from_hex
        self.data.iwsecid = xml["s_id"]
        self.data.iwsecn = 1

        req_param = {
            "action": "ActionFinalize",
            "mode": Otp.MS_MODE,
            "ms_id" + ms_n: xml["ms_id"],
            "ms_val" + ms_n: kpub_encode.hex(),
            "macid": self.macid
        }
        req_param.update({
            "id": self.data.iwid,
            "lastsync": self.data.iwTsync,
            "ms_n": 1
        })
        req_param.update(self.get_r())
        xml = self.request(req_param)
        self.data.synchro(xml, self.generate_kma(self.codepin))
        return Otp.OK
Esempio n. 51
0
# AES案例
from Cryptodome.Cipher import AES
# 16个字节的密码
key = b'1234567890123456'
# 创建加密对象
cipher = AES.new(key, mode=AES.MODE_EAX)
data = '我是心蓝'.encode()
# encrytion
msg = cipher.encrypt(data)

print(msg)
# 解密 过程
# 创建一个新的密码对象
cipher2 = AES.new(key, AES.MODE_EAX, nonce=cipher.nonce)
res = cipher2.decrypt(msg)
print(res.decode('utf-8'))
'''
文档参考:<https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html>

'''
Esempio n. 52
0
    def test_data_must_be_bytes(self):
        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*')

        cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96)
        self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*')
def create_decryptor(self, key, sequence):
    if key.method != "AES-128":
        raise StreamError("Unable to decrypt cipher {0}", key.method)

    if not key.uri:
        raise StreamError("Missing URI to decryption key")

    if self.key_uri != key.uri:
        zoom_key = self.reader.stream.session.options.get("zoom-key")
        zuom_key = self.reader.stream.session.options.get("zuom-key")
        livecam_key = self.reader.stream.session.options.get("livecam-key")
        saw_key = self.reader.stream.session.options.get("saw-key")
        your_key = self.reader.stream.session.options.get("your-key")
        mama_key = self.reader.stream.session.options.get("mama-key")
        custom_uri = self.reader.stream.session.options.get("custom-uri")

        if zoom_key:
            uri = 'http://www.zoomtv.me/k.php?q=' + base64.urlsafe_b64encode(
                zoom_key + base64.urlsafe_b64encode(key.uri))
        elif zuom_key:
            uri = 'http://www.zuom.xyz/k.php?q=' + base64.urlsafe_b64encode(
                zuom_key + base64.urlsafe_b64encode(key.uri))
        elif livecam_key:
            h = urlparse.urlparse(urllib.unquote(livecam_key)).netloc
            q = urlparse.urlparse(urllib.unquote(livecam_key)).query
            uri = 'http://%s/kaes?q=' % h + base64.urlsafe_b64encode(
                q + base64.b64encode(key.uri))
        elif saw_key:
            if 'foxsportsgo' in key.uri:
                _tmp = key.uri.split('/')
                uri = urljoin(saw_key,
                              '/m/fream?p=' + _tmp[-4] + '&k=' + _tmp[-1])
            elif 'nlsk.neulion' in key.uri:
                _tmp = key.uri.split('?')
                uri = urljoin(saw_key, '/m/stream?' + _tmp[-1])
            elif 'nlsk' in key.uri:
                _tmp = key.uri.split('?')
                uri = 'http://bile.level303.club/m/stream?' + _tmp[-1]
            elif 'nhl.com' in key.uri:
                _tmp = key.uri.split('/')
                uri = urljoin(saw_key,
                              '/m/streams?ci=' + _tmp[-3] + '&k=' + _tmp[-1])
            else:
                uri = key.uri
        elif mama_key:
            if 'nlsk' in key.uri:
                _tmp = key.uri.split('&url=')
                uri = 'http://mamahd.in/nba?url=' + _tmp[-1]
        elif your_key:
            if 'mlb.com' in key.uri:
                _tmp = key.uri.split('?')
                uri = urljoin(your_key, '/mlb/get_key/' + _tmp[-1])
            elif 'espn3/auth' in key.uri:
                _tmp = key.uri.split('?')
                uri = urljoin(your_key, '/ncaa/get_key/' + _tmp[-1])
            elif 'nhl.com' in key.uri:
                _tmp = key.uri.split('nhl.com/')
                uri = urljoin(your_key, '/nhl/get_key/' + _tmp[-1])
            else:
                uri = key.uri
        elif custom_uri:
            uri = custom_uri

        else:
            uri = key.uri

        #xbmc.log('[StreamLink_Proxy] using key uri %s'%str(uri))

        res = self.session.http.get(uri,
                                    exception=StreamError,
                                    retries=self.retries,
                                    **self.reader.request_params)

        self.key_data = res.content
        self.key_uri = key.uri

    iv = key.iv or num_to_iv(sequence)

    # Pad IV if needed
    iv = b"\x00" * (16 - len(iv)) + iv

    if _android_ssl:
        return enc(self.key_data, iv)
    elif _oscrypto:
        return AES(self.key_data, iv)
    else:
        return AES.new(self.key_data, AES.MODE_CBC, iv)
Esempio n. 54
0
import socket

from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad, unpad

key = '!!12345678900987654321!!12345678'
iv = '1234567890123456'
bufferSize = 1024

#TCP로 통신하도록 socket설정
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345))

while True:
    #새로운 thread 생성할 때마다 AES의 값을 초기화하는 작업 필요(안그러면 충돌발생하여 추가 thread생성 시 오류 발생)
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())
    decipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())

    #화면에 출력하여 안내하는 interface
    input_data = input("SEND( type :q! to Quit) :")

    print("send : ", input_data)

    ######################################################
    #암호화하여 전달(client -> server)
    #암호화1(pad처리)
    padded_data = pad(input_data.encode(), AES.block_size)

    #암호화2(pad된 데이터를 encrypt하여 암호화)
    encrypted_data = cipher.encrypt(padded_data)
Esempio n. 55
0
def ecb_encode(text, key):
    cipher = AES.new(key, AES.MODE_ECB)
    return (cipher.encrypt(text))
Esempio n. 56
0
def decrypt(enc, password):
    private_key = hashlib.sha256(password.encode("utf-8")).digest()
    enc = base64.b64decode(enc)
    iv = enc[:16]
    cipher = AES.new(private_key, AES.MODE_CBC, iv)
    return unpad(cipher.decrypt(enc[16:]))
Esempio n. 57
0
    def create_challenge_url(self,
                             transaction_id,
                             content_type,
                             message,
                             callback_url,
                             callback_sms_number,
                             use_compression=False,
                             reset_url=False):
        """
        creates a challenge url (looking like lseqr://chal/<base64string>)
        from a challenge dictionary as provided by Challanges.create_challenge
        in lib.challenge

        the version identifier of the challenge url is currently hardcoded
        to 1.
        """

        serial = self.getSerial()

        if content_type is None:
            content_type = CONTENT_TYPE_FREE

        # ------------------------------------------------------------------- --

        # sanity/format checks

        if content_type not in [
                CONTENT_TYPE_PAIRING, CONTENT_TYPE_AUTH, CONTENT_TYPE_FREE
        ]:
            raise InvalidFunctionParameter(
                'content_type', 'content_type must '
                'be CONTENT_TYPE_PAIRING, '
                'CONTENT_TYPE_AUTH or '
                'CONTENT_TYPE_FREE.')

        if content_type == CONTENT_TYPE_PAIRING and \
           message != serial:
            raise InvalidFunctionParameter(
                'message', 'message must be equal '
                'to serial in pairing mode')

        if content_type == CONTENT_TYPE_AUTH:
            if '@' not in message:
                raise InvalidFunctionParameter(
                    'message', 'For content type '
                    'auth, message must have format '
                    '<login>@<server>')

        # ------------------------------------------------------------------- --

        #  after the lseqr://chal/ prefix the following data is encoded
        #  in urlsafe base64:

        #            ---------------------------------------------------
        #  fields   | version | user token id |  R  | ciphertext | MAC |
        #            ---------------------------------------------------
        #           |          header         |     |    EAX enc data  |
        #            ---------------------------------------------------
        #  size     |    1    |       4       |  32 |      ?     | 16  |
        #            ---------------------------------------------------
        #

        r = urandom(32)
        R = calc_dh_base(r)

        user_token_id = self.getFromTokenInfo('user_token_id')
        data_header = struct.pack('<bI', QRTOKEN_VERSION, user_token_id)

        # the user public key is saved as base64 in
        # the token info since the byte format is
        # incompatible with the json backend.

        b64_user_public_key = self.getFromTokenInfo('user_public_key')
        user_public_key = b64decode(b64_user_public_key)

        ss = calc_dh(r, user_public_key)
        U1 = sha256(ss).digest()
        U2 = sha256(U1).digest()
        zerome(ss)

        skA = U1[0:16]
        skB = U2[0:16]
        nonce = U2[16:32]
        zerome(U1)
        zerome(U2)

        # ------------------------------------------------------------------- --

        # create plaintext section

        # ------------------------------------------------------------------- --

        # create the bitmap for flags

        flags = 0

        if use_compression:
            flags |= CHALLENGE_HAS_COMPRESSION

        # FIXME: sizecheck for message, callback url, sms number
        # wiki specs are utf-8 byte length (without \0)

        if callback_url is not None:
            flags |= CHALLENGE_HAS_URL

        if callback_sms_number is not None:
            flags |= CHALLENGE_HAS_SMS_NUMBER

        if (content_type == CONTENT_TYPE_PAIRING):
            flags |= CHALLENGE_HAS_SIGNATURE

        if reset_url:
            flags |= CHALLENGE_SHOULD_RESET_URL
            flags |= CHALLENGE_HAS_SIGNATURE

        # ------------------------------------------------------------------- --

        # generate plaintext header

        #            ----------------------------------------------
        #  fields   | content_type  | flags | transaction_id | ... |
        #            ----------------------------------------------
        #  size     |       1       |   1   |        8       |  ?  |
        #            ----------------------------------------------

        transaction_id = transaction_id_to_u64(transaction_id)
        pt_header = struct.pack('<bbQ', content_type, flags, transaction_id)
        plaintext = pt_header

        # ------------------------------------------------------------------- --

        # create data package

        #            -------------------------------
        #  fields   | header  | message | NUL | ... |
        #            -------------------------------
        #  size     |   10    |    ?    |  1  |  ?  |
        #            -------------------------------

        data_package = b''
        utf8_message = message.encode('utf8')

        # enforce max sizes specified by protocol

        if content_type == CONTENT_TYPE_FREE and len(utf8_message) > 511:
            raise ParameterError('message (encoded as utf8) can only be 511 '
                                 'characters long')

        elif content_type == CONTENT_TYPE_PAIRING and len(utf8_message) > 63:
            raise InvalidFunctionParameter(
                'message', 'max string length '
                '(encoded as utf8) is 511 for '
                'content type PAIRING')

        elif content_type == CONTENT_TYPE_AUTH and len(utf8_message) > 511:
            raise InvalidFunctionParameter(
                'message', 'max string length '
                '(encoded as utf8) is 511 for '
                'content type AUTH')

        data_package += utf8_message + b'\x00'

        # ------------------------------------------------------------------- --

        # depending on function parameters add callback url
        # and/or callback sms number

        #            -----------------------------------------------------
        #  fields   | ... | callback url | NUL | callback sms | NUL | ... |
        #            -----------------------------------------------------
        #  size     |  ?  |       ?      |  1  |       ?      |  1  |  ?  |
        #            -----------------------------------------------------

        # ------------------------------------------------------------------- --

        if callback_url is not None:

            utf8_callback_url = callback_url.encode('utf8')

            # enforce max url length as specified in protocol

            if len(utf8_callback_url) > 511:
                raise InvalidFunctionParameter(
                    'callback_url', 'max string '
                    'length (encoded as utf8) is '
                    '511')

            data_package += utf8_callback_url + b'\x00'

        # ------------------------------------------------------------------- --

        if callback_sms_number is not None:

            utf8_callback_sms_number = callback_sms_number.encode('utf8')

            if len(utf8_callback_sms_number) > 31:
                raise InvalidFunctionParameter(
                    'callback_sms_number', 'max string length (encoded '
                    'as utf8) is 31')

            data_package += utf8_callback_sms_number + b'\x00'

        # ------------------------------------------------------------------- --

        if use_compression:
            maybe_compressed_data_package = zlib.compress(data_package, 9)
        else:
            maybe_compressed_data_package = data_package

        # ------------------------------------------------------------------- --

        # when content type is pairing the protocol specifies that
        # the server must send a hmac based signature with the
        # response

        sig = ''
        sec_obj = self._get_secret_object()

        if flags & CHALLENGE_HAS_SIGNATURE:

            hmac_message = nonce + pt_header + maybe_compressed_data_package

            sig = sec_obj.hmac_digest(data_input=hmac_message,
                                      bkey=self.server_hmac_secret,
                                      hash_algo=sha256)

            plaintext += sig

        # ------------------------------------------------------------------- --

        plaintext += maybe_compressed_data_package

        # ------------------------------------------------------------------- --

        user_message = nonce + pt_header + sig + data_package

        user_sig = sec_obj.hmac_digest(data_input=user_message,
                                       bkey=skB,
                                       hash_algo=sha256)

        # the user sig will be given as urlsafe base64 in the
        # challenge response. for this reasons (and because we
        # need to serialize it into json) we convert the user_sig
        # into this format.

        user_sig = encode_base64_urlsafe(user_sig)

        # ------------------------------------------------------------------- --

        cipher = AES.new(skA, AES.MODE_EAX, nonce)
        cipher.update(data_header)
        ciphertext, tag = cipher.encrypt_and_digest(plaintext)

        raw_data = data_header + R + ciphertext + tag
        protocol_id = config.get('mobile_app_protocol_id', 'lseqr')
        url = protocol_id + '://chal/' + encode_base64_urlsafe(raw_data)

        return url, user_sig
Esempio n. 58
0
def encrypt(raw, password):
    private_key = hashlib.sha256(password.encode("utf-8")).digest()
    raw = pad(raw)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(private_key, AES.MODE_CBC, iv)
    return base64.b64encode(iv + cipher.encrypt(raw))
Esempio n. 59
0
def UnprotectHeaderData(encryptedData):
    passwdData = b'header_key_data'
    salt = b'HEADER.2011'
    key_iv = PBKDF2(passwdData, salt, dkLen=256, count=128)
    return AES.new(key_iv[0:32], AES.MODE_CBC,
                   key_iv[32:48]).decrypt(encryptedData)
Esempio n. 60
0
from Cryptodome.Cipher import AES
from Cryptodome.Random import get_random_bytes
"""
https://www.pycryptodome.org/en/latest/src/examples.html
"""
'''
Encrypt data with AES

The following code generates a new AES128 key and encrypts a piece of data into a file. 
We use the EAX mode because it allows the receiver to detect any unauthorized modification (similarly, 
we could have used other authenticated encryption modes like GCM, CCM or SIV).

'''
data = b"hello"
key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(data)
print(key, cipher, ciphertext)

file_out = open("encrypted.bin", "wb")
[file_out.write(x) for x in (cipher.nonce, tag, ciphertext)]
print(cipher.nonce, tag, ciphertext)
file_out.close()
'''
At the other end, the receiver can securely load the piece of data back (if they know the key!). 
Note that the code generates a ValueError exception when tampering is detected.

'''
file_in = open("encrypted.bin", "rb")
nonce, tag, ciphertext = [file_in.read(x) for x in (16, 16, -1)]