def test_init(self): with self.assertRaises(AssertionError): S3EncryptionClient(key_provider='invalid_object') client = S3EncryptionClient(key_provider=self.kms_client) self.assertIs(client._key_provider, self.kms_client) self.assertRegexpMatches(str(client._client), "<botocore.client.S3 object at 0x.*?>")
def test_get_object(self): from botocore.exceptions import ClientError s3_key = 'dummy' encryption_client = S3EncryptionClient(key_provider=self.kms_client) encryption_client._client = mock.MagicMock() encryption_client._client.get_object = mock.Mock( side_effect=ClientError({'Error': { 'Code': 'Unknown Error' }}, 'S3')) with self.assertRaises(ConfigurationFileNotFoundError): encryption_client.get_object(bucket=self.s3_bucket, key=s3_key) encryption_client._client.get_object.assert_called_once_with( Bucket=self.s3_bucket, Key=s3_key) encryption_client = S3EncryptionClient(key_provider=self.kms_client) encryption_client._client = mock.MagicMock() encryption_client._client.get_object = mock.MagicMock( return_value={ 'Metadata': self.s3_metadata, 'Body': StringIO(base64.b64decode(self.base64_encrypted_data)) }) encryption_client._key_provider = mock.MagicMock() encryption_client._key_provider.decrypt = \ mock.MagicMock( return_value=base64.b64decode( self.base64_plaintext_envelope_key ) ) result = encryption_client.get_object(bucket=self.s3_bucket, key=s3_key) encryption_client._key_provider.decrypt.assert_called_once_with( encrypted_content=base64.b64decode( self.s3_metadata['x-amz-key-v2']), encryption_context=json.loads(self.s3_metadata['x-amz-matdesc'])) self.assertDictEqual(result, { 'Body': self.plaintext_data, 'Metadata': self.s3_metadata })
def test_encrypt(self): client = S3EncryptionClient(key_provider=self.kms_client) for chunk_size in (16, 32): encrypted_content = client.encrypt( content=self.plaintext_data, key=base64.b64decode(self.base64_plaintext_envelope_key), iv=base64.b64decode(self.s3_metadata['x-amz-iv']), chunk_size=chunk_size) base64_encrypted_content = base64.b64encode(encrypted_content) self.assertEqual(base64_encrypted_content, self.base64_encrypted_data)
def __init__(self, kms_alias, region=None, display=None, stream=None): stream = stream or sys.stderr logger = display or module_logger self._logger = logger # If no display is provided, the module_logger is configured and used. if isinstance(self._logger, logging.Logger): self._configure_logger(stream=stream) self._encryption_backend = S3EncryptionClient( key_provider=KMSClient(alias=kms_alias, region=region) )
def test_decrypt(self): client = S3EncryptionClient(key_provider=self.kms_client) for chunk_size in (16, 32, 48, 64): encrypted_content = StringIO( base64.b64decode(self.base64_encrypted_data)) decrypted = client.decrypt( content=encrypted_content, key=base64.b64decode(self.base64_plaintext_envelope_key), iv=base64.b64decode(self.s3_metadata['x-amz-iv']), unencrypted_length=int( self.s3_metadata['x-amz-unencrypted-content-length']), chunk_size=chunk_size) self.assertEqual(decrypted, self.plaintext_data)
def test_prepare_encryption_metadata(self): unencrypted_length = 10 metadata = dict(encrypted_envelope_key='test_envelope_key', iv='test_iv', encryption_context={'ctx': 'a'}, unencrypted_content_length=unencrypted_length) result = S3EncryptionClient._prepare_encryption_metadata(**metadata) self.assertDictEqual( result, { 'x-amz-key-v2': to_base64(metadata['encrypted_envelope_key']), 'x-amz-iv': to_base64(metadata['iv']), 'x-amz-cek-alg': 'AES/CBC/PKCS5Padding', 'x-amz-wrap-alg': 'kms', 'x-amz-matdesc': '{"ctx":"a"}', 'x-amz-unencrypted-content-length': str(unencrypted_length) })
def test_put_object(self): s3_key = 'dummy' encryption_client = S3EncryptionClient(key_provider=self.kms_client) encryption_client._key_provider = mock.MagicMock() encryption_client._key_provider.generate_envelope_key = \ mock.MagicMock( return_value={ 'Plaintext': base64.b64decode( self.base64_plaintext_envelope_key ), 'CiphertextBlob': base64.b64decode( self.s3_metadata['x-amz-key-v2'] ), 'EncryptionContext': json.loads( self.s3_metadata['x-amz-matdesc'] ) } ) encryption_client._client = mock.MagicMock() encryption_client._client.put_object = mock.MagicMock( return_value={'tested-operation': 's3_put_object'}) iv = base64.b64decode(self.s3_metadata['x-amz-iv']) crypto_random = StringIO(iv) mock_generate_envelope_key = \ encryption_client._key_provider.generate_envelope_key mock_put_object = encryption_client._client.put_object with mock.patch.object(Random, 'new', return_value=crypto_random): result = encryption_client.put_object(bucket=self.s3_bucket, key=s3_key, body=self.plaintext_data) mock_generate_envelope_key.assert_called_once_with() self.assertDictEqual(result, {'tested-operation': 's3_put_object'}) mock_put_object.assert_called_once_with( Body=base64.b64decode(self.base64_encrypted_data), Bucket=self.s3_bucket, Key=s3_key, Metadata=self.s3_metadata, ServerSideEncryption='AES256')
def test_get_object_update_alias_from_metadata(self): s3_key = 'dummy' kms_client = KMSClient(alias=None) encryption_client = S3EncryptionClient(key_provider=kms_client) original_set_alias = kms_client.set_alias self.assertIsNone(encryption_client._key_provider.alias) encryption_client._client = mock.MagicMock() encryption_client._client.get_object = mock.MagicMock( return_value={ 'Metadata': self.s3_metadata, 'Body': StringIO(base64.b64decode(self.base64_encrypted_data)) }) encryption_client._key_provider = mock.MagicMock() encryption_client._key_provider.decrypt = \ mock.MagicMock( return_value=base64.b64decode( self.base64_plaintext_envelope_key ) ) mock_get_key_alias = encryption_client._key_provider.get_key_alias = \ mock.MagicMock(return_value='test') encryption_client._key_provider.alias = None mock_set_alias = encryption_client._key_provider.set_alias = \ mock.MagicMock(side_effect=original_set_alias) encryption_client.get_object(bucket=self.s3_bucket, key=s3_key) mock_get_key_alias.assert_called_once_with( key_id=json.loads(self.s3_metadata['x-amz-matdesc'])['kms_cmk_id']) mock_set_alias.assert_called_once_with('test') self.assertEqual(kms_client._alias, 'alias/test')