{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric      #-}
{-# LANGUAGE OverloadedStrings  #-}
{-# LANGUAGE RecordWildCards    #-}
{-# LANGUAGE TypeFamilies       #-}

{-# OPTIONS_GHC -fno-warn-unused-imports #-}
{-# OPTIONS_GHC -fno-warn-unused-binds   #-}
{-# OPTIONS_GHC -fno-warn-unused-matches #-}

-- Derived from AWS service descriptions, licensed under Apache 2.0.

-- |
-- Module      : Network.AWS.KMS.GenerateDataKey
-- Copyright   : (c) 2013-2015 Brendan Hay
-- License     : Mozilla Public License, v. 2.0.
-- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>
-- Stability   : auto-generated
-- Portability : non-portable (GHC extensions)
--
-- Generates a data key that you can use in your application to locally
-- encrypt data. This call returns a plaintext version of the key in the
-- 'Plaintext' field of the response object and an encrypted copy of the
-- key in the 'CiphertextBlob' field. The key is encrypted by using the
-- master key specified by the 'KeyId' field. To decrypt the encrypted key,
-- pass it to the 'Decrypt' API.
--
-- We recommend that you use the following pattern to locally encrypt data:
-- call the 'GenerateDataKey' API, use the key returned in the 'Plaintext'
-- response field to locally encrypt data, and then erase the plaintext
-- data key from memory. Store the encrypted data key (contained in the
-- 'CiphertextBlob' field) alongside of the locally encrypted data.
--
-- You should not call the 'Encrypt' function to re-encrypt your data keys
-- within a region. 'GenerateDataKey' always returns the data key encrypted
-- and tied to the customer master key that will be used to decrypt it.
-- There is no need to decrypt it twice.
--
-- If you decide to use the optional 'EncryptionContext' parameter, you
-- must also store the context in full or at least store enough information
-- along with the encrypted data to be able to reconstruct the context when
-- submitting the ciphertext to the 'Decrypt' API. It is a good practice to
-- choose a context that you can reconstruct on the fly to better secure
-- the ciphertext. For more information about how this parameter is used,
-- see
-- <http://docs.aws.amazon.com/kms/latest/developerguide/encrypt-context.html Encryption Context>.
--
-- To decrypt data, pass the encrypted data key to the 'Decrypt' API.
-- 'Decrypt' uses the associated master key to decrypt the encrypted data
-- key and returns it as plaintext. Use the plaintext data key to locally
-- decrypt your data and then erase the key from memory. You must specify
-- the encryption context, if any, that you specified when you generated
-- the key. The encryption context is logged by CloudTrail, and you can use
-- this log to help track the use of particular data.
--
-- /See:/ <http://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html AWS API Reference> for GenerateDataKey.
module Network.AWS.KMS.GenerateDataKey
    (
    -- * Creating a Request
      generateDataKey
    , GenerateDataKey
    -- * Request Lenses
    , gdkKeySpec
    , gdkEncryptionContext
    , gdkNumberOfBytes
    , gdkGrantTokens
    , gdkKeyId

    -- * Destructuring the Response
    , generateDataKeyResponse
    , GenerateDataKeyResponse
    -- * Response Lenses
    , gdkrsResponseStatus
    , gdkrsKeyId
    , gdkrsPlaintext
    , gdkrsCiphertextBlob
    ) where

import           Network.AWS.KMS.Types
import           Network.AWS.KMS.Types.Product
import           Network.AWS.Prelude
import           Network.AWS.Request
import           Network.AWS.Response

-- | /See:/ 'generateDataKey' smart constructor.
data GenerateDataKey = GenerateDataKey'
    { _gdkKeySpec           :: !(Maybe DataKeySpec)
    , _gdkEncryptionContext :: !(Maybe (Map Text Text))
    , _gdkNumberOfBytes     :: !(Maybe Nat)
    , _gdkGrantTokens       :: !(Maybe [Text])
    , _gdkKeyId             :: !Text
    } deriving (Eq,Read,Show,Data,Typeable,Generic)

-- | Creates a value of 'GenerateDataKey' with the minimum fields required to make a request.
--
-- Use one of the following lenses to modify other fields as desired:
--
-- * 'gdkKeySpec'
--
-- * 'gdkEncryptionContext'
--
-- * 'gdkNumberOfBytes'
--
-- * 'gdkGrantTokens'
--
-- * 'gdkKeyId'
generateDataKey
    :: Text -- ^ 'gdkKeyId'
    -> GenerateDataKey
generateDataKey pKeyId_ =
    GenerateDataKey'
    { _gdkKeySpec = Nothing
    , _gdkEncryptionContext = Nothing
    , _gdkNumberOfBytes = Nothing
    , _gdkGrantTokens = Nothing
    , _gdkKeyId = pKeyId_
    }

-- | Value that identifies the encryption algorithm and key size to generate
-- a data key for. Currently this can be AES_128 or AES_256.
gdkKeySpec :: Lens' GenerateDataKey (Maybe DataKeySpec)
gdkKeySpec = lens _gdkKeySpec (\ s a -> s{_gdkKeySpec = a});

-- | Name\/value pair that contains additional data to be authenticated
-- during the encryption and decryption processes that use the key. This
-- value is logged by AWS CloudTrail to provide context around the data
-- encrypted by the key.
gdkEncryptionContext :: Lens' GenerateDataKey (HashMap Text Text)
gdkEncryptionContext = lens _gdkEncryptionContext (\ s a -> s{_gdkEncryptionContext = a}) . _Default . _Map;

-- | Integer that contains the number of bytes to generate. Common values are
-- 128, 256, 512, and 1024. 1024 is the current limit. We recommend that
-- you use the 'KeySpec' parameter instead.
gdkNumberOfBytes :: Lens' GenerateDataKey (Maybe Natural)
gdkNumberOfBytes = lens _gdkNumberOfBytes (\ s a -> s{_gdkNumberOfBytes = a}) . mapping _Nat;

-- | For more information, see
-- <http://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token Grant Tokens>.
gdkGrantTokens :: Lens' GenerateDataKey [Text]
gdkGrantTokens = lens _gdkGrantTokens (\ s a -> s{_gdkGrantTokens = a}) . _Default . _Coerce;

-- | A unique identifier for the customer master key. This value can be a
-- globally unique identifier, a fully specified ARN to either an alias or
-- a key, or an alias name prefixed by \"alias\/\".
--
-- -   Key ARN Example -
--     arn:aws:kms:us-east-1:123456789012:key\/12345678-1234-1234-1234-123456789012
-- -   Alias ARN Example -
--     arn:aws:kms:us-east-1:123456789012:alias\/MyAliasName
-- -   Globally Unique Key ID Example -
--     12345678-1234-1234-1234-123456789012
-- -   Alias Name Example - alias\/MyAliasName
gdkKeyId :: Lens' GenerateDataKey Text
gdkKeyId = lens _gdkKeyId (\ s a -> s{_gdkKeyId = a});

instance AWSRequest GenerateDataKey where
        type Rs GenerateDataKey = GenerateDataKeyResponse
        request = postJSON kMS
        response
          = receiveJSON
              (\ s h x ->
                 GenerateDataKeyResponse' <$>
                   (pure (fromEnum s)) <*> (x .:> "KeyId") <*>
                     (x .:> "Plaintext")
                     <*> (x .:> "CiphertextBlob"))

instance ToHeaders GenerateDataKey where
        toHeaders
          = const
              (mconcat
                 ["X-Amz-Target" =#
                    ("TrentService.GenerateDataKey" :: ByteString),
                  "Content-Type" =#
                    ("application/x-amz-json-1.1" :: ByteString)])

instance ToJSON GenerateDataKey where
        toJSON GenerateDataKey'{..}
          = object
              (catMaybes
                 [("KeySpec" .=) <$> _gdkKeySpec,
                  ("EncryptionContext" .=) <$> _gdkEncryptionContext,
                  ("NumberOfBytes" .=) <$> _gdkNumberOfBytes,
                  ("GrantTokens" .=) <$> _gdkGrantTokens,
                  Just ("KeyId" .= _gdkKeyId)])

instance ToPath GenerateDataKey where
        toPath = const "/"

instance ToQuery GenerateDataKey where
        toQuery = const mempty

-- | /See:/ 'generateDataKeyResponse' smart constructor.
data GenerateDataKeyResponse = GenerateDataKeyResponse'
    { _gdkrsResponseStatus :: !Int
    , _gdkrsKeyId          :: !Text
    , _gdkrsPlaintext      :: !(Sensitive Base64)
    , _gdkrsCiphertextBlob :: !Base64
    } deriving (Eq,Read,Show,Data,Typeable,Generic)

-- | Creates a value of 'GenerateDataKeyResponse' with the minimum fields required to make a request.
--
-- Use one of the following lenses to modify other fields as desired:
--
-- * 'gdkrsResponseStatus'
--
-- * 'gdkrsKeyId'
--
-- * 'gdkrsPlaintext'
--
-- * 'gdkrsCiphertextBlob'
generateDataKeyResponse
    :: Int -- ^ 'gdkrsResponseStatus'
    -> Text -- ^ 'gdkrsKeyId'
    -> ByteString -- ^ 'gdkrsPlaintext'
    -> ByteString -- ^ 'gdkrsCiphertextBlob'
    -> GenerateDataKeyResponse
generateDataKeyResponse pResponseStatus_ pKeyId_ pPlaintext_ pCiphertextBlob_ =
    GenerateDataKeyResponse'
    { _gdkrsResponseStatus = pResponseStatus_
    , _gdkrsKeyId = pKeyId_
    , _gdkrsPlaintext = _Sensitive . _Base64 # pPlaintext_
    , _gdkrsCiphertextBlob = _Base64 # pCiphertextBlob_
    }

-- | The response status code.
gdkrsResponseStatus :: Lens' GenerateDataKeyResponse Int
gdkrsResponseStatus = lens _gdkrsResponseStatus (\ s a -> s{_gdkrsResponseStatus = a});

-- | System generated unique identifier of the key to be used to decrypt the
-- encrypted copy of the data key.
gdkrsKeyId :: Lens' GenerateDataKeyResponse Text
gdkrsKeyId = lens _gdkrsKeyId (\ s a -> s{_gdkrsKeyId = a});

-- | Plaintext that contains the data key. Use this for encryption and
-- decryption and then remove it from memory as soon as possible.
--
-- /Note:/ This 'Lens' automatically encodes and decodes Base64 data,
-- despite what the AWS documentation might say.
-- The underlying isomorphism will encode to Base64 representation during
-- serialisation, and decode from Base64 representation during deserialisation.
-- This 'Lens' accepts and returns only raw unencoded data.
gdkrsPlaintext :: Lens' GenerateDataKeyResponse ByteString
gdkrsPlaintext = lens _gdkrsPlaintext (\ s a -> s{_gdkrsPlaintext = a}) . _Sensitive . _Base64;

-- | Ciphertext that contains the encrypted data key. You must store the blob
-- and enough information to reconstruct the encryption context so that the
-- data encrypted by using the key can later be decrypted. You must provide
-- both the ciphertext blob and the encryption context to the Decrypt API
-- to recover the plaintext data key and decrypt the object.
--
-- If you are using the CLI, the value is Base64 encoded. Otherwise, it is
-- not encoded.
--
-- /Note:/ This 'Lens' automatically encodes and decodes Base64 data,
-- despite what the AWS documentation might say.
-- The underlying isomorphism will encode to Base64 representation during
-- serialisation, and decode from Base64 representation during deserialisation.
-- This 'Lens' accepts and returns only raw unencoded data.
gdkrsCiphertextBlob :: Lens' GenerateDataKeyResponse ByteString
gdkrsCiphertextBlob = lens _gdkrsCiphertextBlob (\ s a -> s{_gdkrsCiphertextBlob = a}) . _Base64;