def test_validate_header_invalid(self): """Validate that the validate_header function behaves as expected for a valid header. """ self.mock_decrypt.side_effect = InvalidTag() with six.assertRaisesRegex(self, SerializationError, 'Header authorization failed'): aws_encryption_sdk.internal.formatting.deserialize.validate_header( header=VALUES['deserialized_header_block'], header_auth=VALUES['deserialized_header_auth_block'], raw_header=VALUES['header'], data_key=VALUES['data_key_obj'])
def test_validate_header_invalid(self): """Validate that the validate_header function behaves as expected for a valid header. """ self.mock_decrypt.side_effect = InvalidTag() with pytest.raises(SerializationError) as excinfo: aws_encryption_sdk.internal.formatting.deserialize.validate_header( header=VALUES["deserialized_header_block"], header_auth=VALUES["deserialized_header_auth_block"], raw_header=VALUES["header"], data_key=VALUES["data_key_obj"], ) excinfo.match("Header authorization failed")
def decrypt(self, ciphertext, aad, iv, tag, key): """Key Decryption with AES AES_CBC_HMAC_SHA2. :param ciphertext: ciphertext in bytes :param aad: additional authenticated data in bytes :param iv: initialization vector in bytes :param tag: authentication tag in bytes :param key: encrypted key in bytes :return: message """ self.check_iv(iv) hkey = key[:self.key_bytes_length] dkey = key[self.key_bytes_length:] _tag = self._hmac(ciphertext, aad, iv, hkey) if not hmac.compare_digest(_tag, tag): raise InvalidTag() cipher = Cipher(AES(dkey), CBC(iv), backend=default_backend()) d = cipher.decryptor() data = d.update(ciphertext) + d.finalize() unpad = PKCS7(AES.block_size).unpadder() return unpad.update(data) + unpad.finalize()
def locker(self, remove=True): """Provides file locking/unlocking mechanism This function either encrypts or decrypts the file - *file_path*. Encryption or decryption depends upon the file's extension. The user's encryption or decryption task is almost automated since *encryption* or *decryption* is determined by the file's extension. Usage ------- remove = If set to True, the the file that is being encrypted or decrypted will be removed. (Default: True). """ # The file is being decrypted try: if not self._flag: method = 'decrypt' new_file = os.path.splitext(self.file_path)[0] # Retrieve the nonce and remove it from the # encrypted file with open(self.file_path, 'rb+') as f: f.seek(-(self.NONCE_SIZE + self.SALT_LEN), 2) nonce, _ = unpack( '<{}s{}s'.format(self.NONCE_SIZE, self.SALT_LEN), f.read()) orig_size = os.path.getsize( self.file_path) - (self.NONCE_SIZE + self.SALT_LEN) os.truncate(self.file_path, orig_size) # The file is being encrypted else: method = 'encrypt' new_file = self.file_path + self.EXT nonce = os.urandom(self.NONCE_SIZE) # Create a cipher with the required method key = self.password_hash cipher = getattr(AESGCM(key), method) # Create a partial function with default values. crp = partial(cipher, nonce=nonce, associated_data=None) # Read from *file_path* and write to the *new_file* try: Locker._writer( self.file_path, new_file, crp, self._flag, nonce=nonce, salt=self._salt, ) except InvalidTag: os.remove(new_file) raise InvalidTag('Invalid Password or tampered data.') if remove: os.remove(self.file_path) return self except Exception as err: raise err
def locker(file_path, password, remove=True): """Provides file locking/unlocking mechanism This function either encrypts or decrypts the file - *file_path*. Encryption or decryption depends upon the file's extension. The user's encryption or decryption task is almost automated since *encryption* or *decryption* is determined by the file's extension. Usage ------- file_path = File to be written on. password = Key to be used for encryption/decryption. remove = If set to True, the the file that is being encrypted or decrypted will be removed. (Default: True). """ # The file is being decrypted try: if file_path.endswith(EXT): method = 'decrypt' flag = False new_file = os.path.splitext(file_path)[0] # Retrieve the nonce and remove it from the # encrypted file with open(file_path, 'rb+') as f: f.seek(-(NONCE_SIZE + SALT_LEN), 2) nonce, salt = unpack('<{}s{}s'.format(NONCE_SIZE, SALT_LEN), f.read()) orig_size = os.path.getsize(file_path) - (NONCE_SIZE + SALT_LEN) os.truncate(file_path, orig_size) # The file is being encrypted else: method = 'encrypt' flag = True new_file = file_path + EXT salt = os.urandom(SALT_LEN) nonce = os.urandom(NONCE_SIZE) # Create a cipher with the required method key = hashlib.pbkdf2_hmac('sha3-256', password, salt, 10000, 32) cipher = getattr(AESGCM(key), method) # Create a partial function with default values. crp = partial(cipher, nonce=nonce, associated_data=None) # Read from *file_path* and write to the *new_file* try: _writer( file_path, new_file, crp, flag, nonce=nonce, salt=salt, ) except InvalidTag as err: os.remove(new_file) raise InvalidTag('Invalid Password or tampered data.') if remove: os.remove(file_path) except Exception as err: raise err
def test_verify_finish(self, mock_chacha20_poly1305, mock_tlv_parser, mock_ed25519): config = Mock() config.get_pairing.return_value = None, 'test_ios_device_ltpk', None context = { 'session_key': 'test_session_key', 'accessory_curve25519_public_key': b'test_accessory_curve25519_public_key', 'ios_device_curve25519_public_key': b'test_ios_device_curve25519_public_key', 'shared_secret': b'shared_secret', } encrypted_input = b'test_encrypted_input' mock_tlv_parser.decode.return_value = [{ TlvCode.identifier: 'test_identifier', TlvCode.signature: b'test_signature', }] result = pair.verify_finish(config, context, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m4, }]) # handle 'verify_finished call before successful verify_start' context['session_key'] = None result = pair.verify_finish(config, context, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m4, TlvCode.error: TlvError.authentication, }]) context['session_key'] = 'test_session_key' # handle 'invalid auth tag during chacha decryption' mock_chacha20_poly1305().decrypt.side_effect = InvalidTag() result = pair.verify_finish(config, context, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m4, TlvCode.error: TlvError.authentication, }]) mock_chacha20_poly1305().decrypt.side_effect = None # handle 'unable to decode decrypted tlv data' mock_tlv_parser.decode.side_effect = ValueError() result = pair.verify_finish(config, context, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m4, TlvCode.error: TlvError.authentication, }]) mock_tlv_parser.decode.side_effect = None # handle 'unable to find requested ios device in config file' config.get_pairing.return_value = None, None, None result = pair.verify_finish(config, context, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m4, TlvCode.error: TlvError.authentication, }]) config.get_pairing.return_value = None, 'test_ios_device_ltpk', None # handle 'ios_device_info ed25519 signature verification is failed' mock_ed25519.BadSignatureError = BadSignatureError mock_ed25519.VerifyingKey().verify.side_effect = BadSignatureError() result = pair.verify_finish(config, context, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m4, TlvCode.error: TlvError.authentication, }]) mock_ed25519.VerifyingKey().verify.side_effect = None
def test_exchange(self, mock_chacha20_poly1305, mock_hkdf, mock_sha512, mocker_default_backend, mock_tlv_parser, mock_ed25519): config = Mock() config.get_pairing.return_value = None, None, None context = {'srp': Mock()} expected_tlv_state = TlvState.m5 encrypted_input = b'test_encrypted_input' encrypted_output = b'test_encrypted_output' mock_chacha20_poly1305().encrypt.return_value = encrypted_output mock_tlv_parser.decode.return_value = [{ TlvCode.identifier: 'test_identifier', TlvCode.public_key: b'test_public_key', TlvCode.signature: b'test_signature', }] result = pair.exchange(config, context, expected_tlv_state, encrypted_input) mock_hkdf.assert_called_with(algorithm=mock_sha512(), length=32, salt=b'Pair-Setup-Accessory-Sign-Salt', info=b'Pair-Setup-Accessory-Sign-Info', backend=mocker_default_backend()) mock_hkdf().derive.assert_called_with(context['srp'].session_key) mock_chacha20_poly1305.assert_called_with(mock_hkdf().derive()) mock_chacha20_poly1305().decrypt.assert_called_with(b'\x00\x00\x00\x00PS-Msg05', encrypted_input, None) mock_tlv_parser.decode.assert_called_with(mock_chacha20_poly1305().decrypt()) self.assertEqual(result, [{ TlvCode.state: TlvState.m6, TlvCode.encrypted_data: encrypted_output, }]) # handle 'Unexpected pair_setup state' expected_tlv_state = TlvState.m1 result = pair.exchange(config, context, expected_tlv_state, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m6, TlvCode.error: TlvError.unknown, }]) expected_tlv_state = TlvState.m5 # handle 'pair_setup M5: invalid auth tag during chacha decryption' mock_chacha20_poly1305().decrypt.side_effect = InvalidTag() result = pair.exchange(config, context, expected_tlv_state, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m6, TlvCode.error: TlvError.authentication, }]) mock_chacha20_poly1305().decrypt.side_effect = None # handle 'unable to decode decrypted tlv data' mock_tlv_parser.decode.side_effect = ValueError() result = pair.exchange(config, context, expected_tlv_state, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m6, TlvCode.error: TlvError.authentication, }]) mock_tlv_parser.decode.side_effect = None # handle 'ios_device_info ed25519 signature verification is failed' mock_ed25519.BadSignatureError = BadSignatureError mock_ed25519.VerifyingKey().verify.side_effect = BadSignatureError() result = pair.exchange(config, context, expected_tlv_state, encrypted_input) self.assertEqual(result, [{ TlvCode.state: TlvState.m6, TlvCode.error: TlvError.authentication, }]) mock_ed25519.VerifyingKey().verify.side_effect = None