def test_calls_service_for_operations_unsupported_locally():
    """When an operation can't be performed locally, the client should request Key Vault perform it"""

    mock_client = mock.Mock()
    key = mock.Mock(spec=KeyVaultKey, id="https://localhost/fake/key/version")
    client = CryptographyClient(key, mock.Mock())
    client._client = mock_client

    supports_nothing = mock.Mock(supports=mock.Mock(return_value=False))
    with mock.patch(
            CryptographyClient.__module__ + ".get_local_cryptography_provider",
            lambda *_: supports_nothing):
        client.decrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.decrypt.call_count == 1
    assert supports_nothing.decrypt.call_count == 0

    client.encrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.encrypt.call_count == 1
    assert supports_nothing.encrypt.call_count == 0

    client.sign(SignatureAlgorithm.rs256, b"...")
    assert mock_client.sign.call_count == 1
    assert supports_nothing.sign.call_count == 0

    client.verify(SignatureAlgorithm.rs256, b"...", b"...")
    assert mock_client.verify.call_count == 1
    assert supports_nothing.verify.call_count == 0

    client.unwrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.unwrap_key.call_count == 1
    assert supports_nothing.unwrap_key.call_count == 0

    client.wrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.wrap_key.call_count == 1
    assert supports_nothing.wrap_key.call_count == 0
def test_decrypt_argument_validation():
    mock_client = mock.Mock()
    key = mock.Mock(
        spec=KeyVaultKey,
        id="https://localhost/fake/key/version",
        properties=mock.Mock(not_before=datetime(2000, 1, 1, tzinfo=_UTC),
                             expires_on=datetime(3000, 1, 1, tzinfo=_UTC)),
    )
    client = CryptographyClient(key, mock.Mock())
    client._client = mock_client

    with pytest.raises(ValueError) as ex:
        client.decrypt(EncryptionAlgorithm.rsa_oaep, b"...", iv=b"...")
    assert "iv" in str(ex.value)
    with pytest.raises(ValueError) as ex:
        client.decrypt(EncryptionAlgorithm.rsa_oaep,
                       b"...",
                       additional_authenticated_data=b"...")
    assert "additional_authenticated_data" in str(ex.value)
    with pytest.raises(ValueError) as ex:
        client.decrypt(EncryptionAlgorithm.rsa_oaep,
                       b"...",
                       authentication_tag=b"...")
    assert "authentication_tag" in str(ex.value)
    with pytest.raises(ValueError) as ex:
        client.decrypt(EncryptionAlgorithm.a128_gcm, b"...", iv=b"...")
    assert "authentication_tag" in str(ex.value) and "required" in str(
        ex.value)
    with pytest.raises(ValueError) as ex:
        client.decrypt(EncryptionAlgorithm.a192_cbcpad, b"...")
    assert "iv" in str(ex.value) and "required" in str(ex.value)
class DecryptTest(PerfStressTest):
    def __init__(self, arguments):
        super().__init__(arguments)

        # Auth configuration
        self.credential = DefaultAzureCredential()
        self.async_credential = AsyncDefaultAzureCredential()

        # Create clients
        vault_url = self.get_from_env("AZURE_KEYVAULT_URL")
        self.client = KeyClient(vault_url, self.credential,
                                **self._client_kwargs)
        self.async_client = AsyncKeyClient(vault_url, self.async_credential,
                                           **self._client_kwargs)
        self.key_name = "livekvtestdecryptperfkey"

    async def global_setup(self):
        """The global setup is run only once."""
        await super().global_setup()
        rsa_key = await self.async_client.create_rsa_key(self.key_name)
        self.crypto_client = CryptographyClient(rsa_key.id,
                                                self.credential,
                                                permissions=NO_GET,
                                                **self._client_kwargs)
        self.async_crypto_client = AsyncCryptographyClient(
            rsa_key.id,
            self.async_credential,
            permissions=NO_GET,
            **self._client_kwargs)

        self.test_algorithm = EncryptionAlgorithm.rsa_oaep_256
        plaintext = os.urandom(32)
        self.ciphertext = self.crypto_client.encrypt(self.test_algorithm,
                                                     plaintext).ciphertext

    async def global_cleanup(self):
        """The global cleanup is run only once."""
        await self.async_client.delete_key(self.key_name)
        await self.async_client.purge_deleted_key(self.key_name)
        await super().global_cleanup()

    async def close(self):
        """This is run after cleanup."""
        await self.async_client.close()
        await self.async_crypto_client.close()
        await self.async_credential.close()
        await super().close()

    def run_sync(self):
        """The synchronous perf test."""
        self.crypto_client.decrypt(self.test_algorithm, self.ciphertext)

    async def run_async(self):
        """The asynchronous perf test."""
        await self.async_crypto_client.decrypt(self.test_algorithm,
                                               self.ciphertext)
Beispiel #4
0
    def test_encrypt_decrypt(self, key_client, credential, **kwargs):
        key_name = self.get_resource_name("crypto-test-encrypt-key")
        key = key_client.create_rsa_key(key_name)
        client = CryptographyClient(key, credential)

        # [START encrypt]

        from azure.keyvault.keys.crypto import EncryptionAlgorithm

        # the result holds the ciphertext and identifies the encryption key and algorithm used
        result = client.encrypt(EncryptionAlgorithm.rsa_oaep, b"plaintext")
        ciphertext = result.ciphertext
        print(result.key_id)
        print(result.algorithm)

        # [END encrypt]

        # [START decrypt]

        from azure.keyvault.keys.crypto import EncryptionAlgorithm

        result = client.decrypt(EncryptionAlgorithm.rsa_oaep, ciphertext)
        print(result.plaintext)

        # [END decrypt]

        pass
Beispiel #5
0
    def test_encrypt_decrypt(self, key_client, **kwargs):
        credential = self.get_credential(CryptographyClient)
        key_name = self.get_resource_name("crypto-test-encrypt-key")
        key_client.create_rsa_key(key_name)

        # [START create_client]
        # create a CryptographyClient using a KeyVaultKey instance
        key = key_client.get_key(key_name)
        crypto_client = CryptographyClient(key, credential)

        # or a key's id, which must include a version
        key_id = "https://<your vault>.vault.azure.net/keys/<key name>/fe4fdcab688c479a9aa80f01ffeac26"
        crypto_client = CryptographyClient(key_id, credential)
        # [END create_client]

        client = CryptographyClient(key,
                                    credential,
                                    api_version=key_client.api_version)

        # [START encrypt]
        from azure.keyvault.keys.crypto import EncryptionAlgorithm

        # the result holds the ciphertext and identifies the encryption key and algorithm used
        result = client.encrypt(EncryptionAlgorithm.rsa_oaep, b"plaintext")
        ciphertext = result.ciphertext
        print(result.key_id)
        print(result.algorithm)
        # [END encrypt]

        # [START decrypt]
        from azure.keyvault.keys.crypto import EncryptionAlgorithm

        result = client.decrypt(EncryptionAlgorithm.rsa_oaep, ciphertext)
        print(result.plaintext)
    def decrypt_secret(self, cipher_text, vault_name, keyid, subscription_id,
                       region):
        logger.info("secret to decrypt: {0}".format(cipher_text))
        logger.info("keyid: {0}".format(keyid))
        logger.info("Azure subscription id: {0}".format(subscription_id))
        logger.info("Azure region: {0}".format(region))
        vault_url = "https://{0}.vault.azure.net/".format(vault_name)
        logger.info(vault_url)
        '''
        convert string to byte literal
        '''
        byte_literal_value = cipher_text.encode()
        '''
        You can use str.decode() with encoding as unicode-escape . 
        Then decode it back using the required encoding to get back your bytes array.
        '''
        byte_literal_value = byte_literal_value.decode(
            'unicode-escape').encode('ISO-8859-1')
        credential = DefaultAzureCredential()
        key_client = KeyClient(vault_url=vault_url, credential=credential)
        key = key_client.get_key(keyid)
        crypto_client = CryptographyClient(key, credential=credential)

        decrypted = crypto_client.decrypt(EncryptionAlgorithm.rsa_oaep,
                                          byte_literal_value)
        print("decrypted: ", decrypted.plaintext)
Beispiel #7
0
    def test_encrypt_local(self, key_client, credential, **kwargs):
        """Encrypt locally, decrypt with Key Vault"""

        key = key_client.create_rsa_key("encrypt-local", size=4096)
        crypto_client = CryptographyClient(key, credential)

        for encrypt_algorithm in EncryptionAlgorithm:
            result = crypto_client.encrypt(encrypt_algorithm, self.plaintext)
            self.assertEqual(result.key_id, key.id)

            result = crypto_client.decrypt(result.algorithm, result.ciphertext)
            self.assertEqual(result.plaintext, self.plaintext)
def test_prefers_local_provider():
    """The client should complete operations locally whenever possible"""

    mock_client = mock.Mock()
    key = mock.Mock(
        spec=KeyVaultKey,
        id="https://localhost/fake/key/version",
        properties=mock.Mock(not_before=datetime(2000, 1, 1, tzinfo=_UTC),
                             expires_on=datetime(3000, 1, 1, tzinfo=_UTC)),
    )
    client = CryptographyClient(key, mock.Mock())
    client._client = mock_client

    supports_everything = mock.Mock(supports=mock.Mock(return_value=True))
    with mock.patch(
            CryptographyClient.__module__ + ".get_local_cryptography_provider",
            lambda *_: supports_everything):
        client.decrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.decrypt.call_count == 0
    assert supports_everything.decrypt.call_count == 1

    client.encrypt(EncryptionAlgorithm.rsa_oaep, b"...")
    assert mock_client.encrypt.call_count == 0
    assert supports_everything.encrypt.call_count == 1

    client.sign(SignatureAlgorithm.rs256, b"...")
    assert mock_client.sign.call_count == 0
    assert supports_everything.sign.call_count == 1

    client.verify(SignatureAlgorithm.rs256, b"...", b"...")
    assert mock_client.verify.call_count == 0
    assert supports_everything.verify.call_count == 1

    client.unwrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.unwrap_key.call_count == 0
    assert supports_everything.unwrap_key.call_count == 1

    client.wrap_key(KeyWrapAlgorithm.rsa_oaep, b"...")
    assert mock_client.wrap_key.call_count == 0
    assert supports_everything.wrap_key.call_count == 1
Beispiel #9
0
    def test_encrypt_and_decrypt(self, key_client, credential, **kwargs):
        key_name = self.get_resource_name("keycrypt")

        imported_key = self._import_test_key(key_client, key_name)
        crypto_client = CryptographyClient(imported_key.id, credential)

        result = crypto_client.encrypt(EncryptionAlgorithm.rsa_oaep,
                                       self.plaintext)
        self.assertEqual(result.key_id, imported_key.id)

        result = crypto_client.decrypt(result.algorithm, result.ciphertext)
        self.assertEqual(result.key_id, imported_key.id)
        self.assertEqual(EncryptionAlgorithm.rsa_oaep, result.algorithm)
        self.assertEqual(self.plaintext, result.plaintext)
Beispiel #10
0
def decrypt(request, json_key_attributes_dict, pin, version):
    """
    This method will be called by the application entry point
    for decrypting the payload.
    request.value has the plaintext payload
    request.alg contains the padding algorithm for encryption.
    """
    set_env(json_key_attributes_dict, pin)
    credential = DefaultAzureCredential()
    key_vault_key = get_akv_key(json_key_attributes_dict, credential)
    crypto_client = CryptographyClient(key_vault_key, credential=credential)
    decrypted_payload = crypto_client.decrypt(EncryptionAlgorithm.rsa_oaep,
                                              request.value)
    response = EncryptDecryptResponse(decrypted_payload.plaintext)
    return response
Beispiel #11
0
    def rotate_key(self,
                   envelope: EncryptionEnvelope,
                   version: Optional[str] = None) -> EncryptionEnvelope:
        old_key = self.key_client.get_key(self.key_encryption_key.name,
                                          version=envelope.version)
        old_crypto_client = CryptographyClient(old_key, self.cred)

        # decode from base64
        ciphertext = base64.b64decode(envelope.data)
        encrypted_data_key = base64.b64decode(envelope.key)
        nonce = base64.b64decode(envelope.iv)

        # decrypt the data key
        result = old_crypto_client.decrypt(ENCRYPTION_ALGORITHM,
                                           encrypted_data_key)
        data_key = result.plaintext

        # decrypt the data locally using the nonce and decrypted data key
        decrypted_data = self._data_decrypt(ciphertext, data_key, nonce)

        # now re-encrypt with the latest key encryption key
        return self.encrypt(decrypted_data)
Beispiel #12
0
class AzureEncryptionProvider(EncryptionProvider):
    """An EncryptionProvider implementation for Azure Key Vault.

    To authenticate, please provide Azure AD service principal info as 
    'tenant_id', 'client_id', and 'client_secret' kwargs, or as
    AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET environment
    variables.

    Attributes:
        tenant_id (str): The tenant ID of the Azure SP to connect with.
        client_id (str): The client ID of the Azure SP to connect with.
        client_secret (str): The client secret of the Azure SP to connect with.
        key_client (KeyClient): Azure Key Vault key client.
        crypto_client (CryptographyClient): Azure Key Vault crypto client.

    Args:
        vault_url (str): The URL of the key vault to connect to.
        key (str): The name of the key encryption key to use for envelope encryption.
        auth_via_cli (bool, kwarg): If we should auth via Azure CLI.
        **kwargs: Authentication information.

    Raises:
        TypeError: If authentication information is not provided correctly.
    """
    def __init__(self, vault_url: str, key: str, **kwargs) -> None:
        auth_via_cli = bool(kwargs.pop("auth_via_cli", False))
        if auth_via_cli:
            try:
                self.key_client = get_client_from_cli_profile(
                    KeyClient, vault_url=vault_url)
                self.key_encryption_key = self.key_client.get_key(key)
                self.crypto_client = get_client_from_cli_profile(
                    CryptographyClient, key=self.key_encryption_key)
            except CLIError:
                logging.error(
                    "ERROR: Unable to authenticate via Azure CLI, have you "
                    "logged in with 'az login'?")
                raise SystemExit(1)
        else:
            tenant_id = kwargs.pop("tenant_id", os.getenv(TENANT_ID_ENVVAR))
            client_id = kwargs.pop("client_id", os.getenv(CLIENT_ID_ENVVAR))
            client_secret = kwargs.pop("client_secret",
                                       os.getenv(CLIENT_SECRET_ENVVAR))
            if tenant_id is None or client_id is None or client_secret is None:
                raise TypeError(
                    "Please specify tenant_id, client_id, and client_secret "
                    "in config or in environment variables as in "
                    "https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity#service-principal-with-secret"
                )
            self.cred = ClientSecretCredential(tenant_id, client_id,
                                               client_secret)
            self.key_client = KeyClient(vault_url,
                                        credential=self.cred,
                                        logger=None)
            self.key_encryption_key = self.key_client.get_key(key)
            self.crypto_client = CryptographyClient(self.key_encryption_key,
                                                    self.cred)

    # overrides EncryptionProvider.encrypt()
    def encrypt(self, data: bytes) -> EncryptionEnvelope:
        # encrypt the data locally, generating a data key and a nonce
        ciphertext, data_key, nonce = self._data_encrypt(data)

        # encrypt the data key using the key from the vault
        result = self.crypto_client.encrypt(ENCRYPTION_ALGORITHM, data_key)
        del data_key  # we don't wanna keep this around after we've encrypted it
        encrypted_data_key = result.ciphertext

        # encode to base64 for storage/transmission
        b64_ciphertext = base64.b64encode(ciphertext).decode("utf-8")
        b64_encrypted_data_key = base64.b64encode(encrypted_data_key).decode(
            "utf-8")
        b64_nonce = base64.b64encode(nonce).decode("utf-8")

        return EncryptionEnvelope(b64_ciphertext, b64_encrypted_data_key,
                                  b64_nonce,
                                  self.key_encryption_key.properties.version)

    # overrides EncryptionProvider.decrypt()
    def decrypt(self, envelope: EncryptionEnvelope) -> Union[bytes, None]:
        if envelope.version != self.key_encryption_key.properties.version:
            logging.error(
                "Encryption key version %s is out of "
                "date, please re-encrypt with 'victoria encrypt rotate'",
                envelope.version)
            return None

        # decode from base64
        ciphertext = base64.b64decode(envelope.data)
        encrypted_data_key = base64.b64decode(envelope.key)
        nonce = base64.b64decode(envelope.iv)

        # decrypt the data key
        result = self.crypto_client.decrypt(ENCRYPTION_ALGORITHM,
                                            encrypted_data_key)
        data_key = result.plaintext

        # decrypt the data locally using the nonce and decrypted data key
        return self._data_decrypt(ciphertext, data_key, nonce)

    # overrides EncryptionProvider.rotate_key()
    def rotate_key(self,
                   envelope: EncryptionEnvelope,
                   version: Optional[str] = None) -> EncryptionEnvelope:
        old_key = self.key_client.get_key(self.key_encryption_key.name,
                                          version=envelope.version)
        old_crypto_client = CryptographyClient(old_key, self.cred)

        # decode from base64
        ciphertext = base64.b64decode(envelope.data)
        encrypted_data_key = base64.b64decode(envelope.key)
        nonce = base64.b64decode(envelope.iv)

        # decrypt the data key
        result = old_crypto_client.decrypt(ENCRYPTION_ALGORITHM,
                                           encrypted_data_key)
        data_key = result.plaintext

        # decrypt the data locally using the nonce and decrypted data key
        decrypted_data = self._data_decrypt(ciphertext, data_key, nonce)

        # now re-encrypt with the latest key encryption key
        return self.encrypt(decrypted_data)
Beispiel #13
0
 def decrypt(self, ciphertext, key_name):
     key = self.key_client.get_key(key_name)
     crypto_client = CryptographyClient(key, credential=self.credential)
     text = crypto_client.decrypt(EncryptionAlgorithm.rsa_oaep, ciphertext)
     return text.plaintext.decode()