--- layout: docs page_title: Key Wrapping for Transit Key Import - Transit - Secrets Engines description: |- Details about wrapping keys for import into the transit secrets engine. --- # Key Wrapping for Transit Key Import The "bring your own key" (BYOK) functionality for the transit secrets engine allows users to import keys that were generated outside of Vault into the transit secrets engine. This document describes the process for wrapping an externally-generated key (the target key) for import into Vault. It describes the processes for importing a software-stored key using Golang and for importing a key that is stored in an HSM. ### Mount the secrets engine ```shell-session $ vault secrets enable transit Success! Enabled the transit secrets engine at: transit/ ``` ### Retrieve the transit wrapping key ```shell-session $ vault read transit/wrapping_key ``` This returns a 4096-bit RSA key. The steps after this depend on whether the key is stored using a software solution or in an HSM. ### Software Example (Go) This example assumes that the key is stored in software using the variable name `key`. It demonstrates how to wrap the target key using Golang crypto libraries. Once you have the wrapping key, you can parse it using the `encoding/pem` and `crypto/x509` libraries (the example code below assumes that the wrapping key has been written to a variable called `wrappingKeyString`): ``` keyBlock, _ := pem.Decode([]byte(wrappingKeyString)) parsedKey, err := x509.ParsePKIXPublicKey(keyBlock.Bytes) if err != nil { return err } ``` Then generate an ephemeral AES key for wrapping the target key. This example uses Golang's `crypto/rand` library for generating the key: ``` ephemeralAESKey := make([]byte, 32) _, err := rand.Read(ephemeralAESKey) if err != nil { return err } ``` ~> **NOTE**: Be sure to securely delete the ephemeral AES key once it has been used! Google's [tink library](https://pkg.go.dev/github.com/google/tink/go@v1.6.1/kwp/subtle) provides a function for performing the key wrap operation: ``` wrapKWP, err := subtle.NewKWP(aesKey) if err != nil { return err } wrappedTargetKey, err := wrapKWP.Wrap(key) if err != nil { return err } ``` Then encrypt the ephemeral AES key using the transit wrapping key: ``` wrappedAESKey, err := rsa.EncryptOAEP( sha256.New(), rand.Reader, wrappingKey, ephemeralAESKey, []byte{}, ) if err != nil { return err } ``` Note that though this example uses SHA256, Vault also supports the use of SHA1, SHA384, or SHA512. The hash function that was used at this step will need to be provided as a parameter when importing the key. Finally, concatenate the wrapped keys into a single byte string. The leftmost 4096 bits of the string should be the wrapped AES key, and the remaining bits should be the wrapped target key. Then the resulting bytes should be base64-encoded. ``` combinedCiphertext := append(wrappedAESKey, wrappedTargetKey...) base64Ciphertext := base64.StdEncoding.EncodeToString(combinedCiphertext) ``` This is the ciphertext that should be provided to Vault when importing a key into the transit secrets engine. ```shell-session $ vault write transit/keys/test-key/import ciphertext=$CIPHERTEXT hash_function=SHA256 type=$KEY_TYPE ``` ### AWS CloudHSM Example This example demonstrates how to import a key into the transit secrets engine from an AWS CloudHSM cluster. The process and mechanisms used will apply to importing a key from an HSM in general, but the details will differ between HSMs. For information on creating and communicating with an AWS CloudHSM cluster, see the [Getting Started guide in the AWS CloudHSM documentation](https://docs.aws.amazon.com/cloudhsm/latest/userguide/getting-started.html). Communication with the HSM uses AWS's `key_mgmt_util` tool. For help setting that up, see the [Getting Started page for key_mgmt_util](https://docs.aws.amazon.com/cloudhsm/latest/userguide/key_mgmt_util-getting-started.html). The first step is writing the transit wrapping key to the HSM. This involves creating a new RSA public key object with the key returned by transit's `wrapping_key` endpoint. ```shell-session $ importPubKey -f wrapping_key.pem -l "vault-transit-wrapping-key" ``` This will create the public key in the HSM with all of the necessary permissions. If you're using a different tool, make sure that the usage for the wrapping key includes the attribute `CKA_WRAP`. The next step is wrapping the target key using the wrapping key. If the ID of the target key is `1` and the wrapping key is `2`, the command looks like this: ```shell-session $ wrapKey -noheader -k 1 -w 2 -t 3 -m 7 -out ciphertext.key ``` The `-m 7` flag specifies the mechanism to use for the key wrapping. For AWS CloudHSM, 7 corresponds to the PKCS11 mechanism `CKM_AES_RSA_KEY_WRAP` ([see the AWS documentation for details](https://docs.aws.amazon.com/cloudhsm/latest/userguide/key_mgmt_util-wrapKey.html)). The `-t 3` flag specifies `SHA256` as the hash function. The result is written to a file called `ciphertext.key`. The `noheader` flag ensures that the ciphertext does not include an AWS-specific header. The output from this is a binary file, which needs to be base64-encoded when it is provided to Vault. ```shell-session $ export CIPHERTEXT=$(base64 ciphertext.key) $ vault write transit/keys/test-key/import ciphertext=$CIPHERTEXT hash_function=SHA256 type=$KEY_TYPE ``` Once the key has been imported, it can be used like any other transit key.