Vault
Transform sensitive data with Vault
Note
The Transform secrets engine requires a Vault Enterprise Advanced Data Protection (ADP) license or HCP Vault Dedicated Plus tier cluster.
Challenge
Vault's Transit secrets engine provides encryption service; however, the resulting ciphertext does not preserve the original data format or length.

Think of a scenario where an organization must cryptographically protect personally identifiable information (PII) while preserving the data format and length. For example, the database schema expects a certain character length and/or only allows alphanumeric characters.
The preservation of the original data format or length may be driven by compliance with certain industry standards such as HIPAA or PCI.
Solution
Vault Enterprise 1.4 with Advanced Data Protection module introduced the Transform secrets engine to handle secure data transformation and tokenization against provided secrets. Transformation methods encompass NIST vetted cryptographic standards such as format-preserving encryption (FPE) via FF3-1 to encode your secrets while maintaining the data format and length. In addition, it can also perform pseudonymous transformations of the data through other means, such as masking.

This prevents the need for change in your existing database schemas.
Prerequisites
To perform the tasks described in this tutorial, you need to have:
- Vault Enterprise with the Advanced Data Protection module or a HCP Vault Dedicated Plus tier cluster.
- jq installed
Policy requirements
For the purpose of this tutorial, you can use root token to work
with Vault. The only recommended use for root tokens is for initial setup or in emergencies. As a best practice, use tokens with
appropriate set of policies based on your role in the organization.
To perform all tasks demonstrated in this tutorial, your policy must include the following permissions:
# Work with transform secrets engine
path "transform/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}
# Enable secrets engine
path "sys/mounts/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}
# List enabled secrets engine
path "sys/mounts" {
  capabilities = [ "read", "list" ]
}
If you are not familiar with policies, complete the policies tutorial.
Lab setup
Note
If you do not have access to an HCP Vault Dedicated cluster, visit the Create a Vault Cluster on HCP tutorial.
- Launch the HCP Portal and login. 
- Click Vault in the left navigation pane. 
- In the Vault clusters pane, click vault-cluster. 
- Under Cluster URLs, click Public Cluster URL.  
- In a terminal, set the - VAULT_ADDRenvironment variable to the copied address.- $ export VAULT_ADDR=<Public_Cluster_URL>
- Return to the Overview page and click Generate token.  - Within a few moments, a new token will be generated. 
- Copy the Admin Token.  
- Return to the terminal and set the - VAULT_TOKENenvironment variable.- $ export VAULT_TOKEN=<token>
- Set the - VAULT_NAMESPACEenvironment variable to- admin.- $ export VAULT_NAMESPACE=admin- The - adminnamespace is the top-level namespace automatically created by HCP Vault. All CLI operations default to use the namespace defined in this environment variable.
- Type - vault statusto verify your connectivity to the Vault cluster.- $ vault status Key Value --- ----- Recovery Seal Type shamir Initialized true Sealed false Total Recovery Shares 1 Threshold 1 Version 1.9.2+ent Storage Type raft ...snipped...
The Vault Dedicated server is ready, you are ready to proceed with the lab.
Transform secrets engine workflow
Transform secrets engine configuration workflow:
- Enable the transformsecrets engine
- Create a role containing the transformations that it can perform
- Create an alphabet defining a set of characters to use for format-preserving encryption (FPE) if not using the built-in alphabets.
- Create a template defining the rules for value matching if not using the built-in template
- Create a transformation to specify the nature of the data manipulation

Alphabets define a set of valid input/output UTF-8 characters to be used when you perform FPE. In this step, you are going to leverage one of the built-in alphabets. Read the create custom alphabets section to learn how to define your own alphabets.
Data transformation templates are constructed of type (regex),
pattern (regular
expression) and allowed
alphabet used in the input value. Currently, regex is the only supported
type. The pattern defines the data format pattern. For example, the most credit
card numbers would have a pattern that can be expressed as
(\d{4})-(\d{4})-(\d{4})-(\d{4}) in regex.
In this step, the use of the builtin/creditcardnumber template is
demonstrated. Read the create custom templates
section to learn how to define your own templates.
Transformations define the transformation template, tweak source or the masking character to be used to transform the secrets.
Tweak source types:
| Source | Description | 
|---|---|
| supplied (default) | User provide the tweak source which must be a base64-encoded 7-digit string | 
| generated | Vault generates and returns the tweak source along with the encoded data. The user must securely store the tweak source which will be needed to decrypt the data | 
| internal | Vault generates a tweak source for the transformation and the same tweak source will be used for every request | 
Note
Tweak source is only applicable to the FPE transformation.
Create a new transformation
In this section, you are going to:
- Enable the transform secrets engine
- Create a payments role which includes card-number transformation
- Create a card-number transformation which performs format preserving encryption

- Enable the - transformsecrets engine at- transform/.- $ vault secrets enable transform Success! Enabled the transform secrets engine at: transform/
- Create a role named "payments" with "card-number" transformation attached which you will create next. - $ vault write transform/role/payments transformations=card-number Success! Data written to: transform/role/payments
- List the existing roles. - $ vault list transform/role Keys ---- payments
- Create a transformation named "card-number" which will be used to transform credit card numbers. This uses the built-in template - builtin/creditcardnumberto perform format-preserving encryption (FPE). The allowed role to use this transformation is- payments, which you just created.- $ vault write transform/transformations/fpe/card-number \ template="builtin/creditcardnumber" \ tweak_source=internal \ allowed_roles=payments- Example Output: - Success! Data written to: transform/transformations/fpe/card-number- Note - The - allowed_rolesparameter can be set to a wildcard (- *) instead of listing role names. Also, the role name can be expressed using globs at the end for pattern matching (e.g.- pay*).- You will learn how to define your own template in the Create custom templates section. 
- List the existing transformations. - $ vault list transform/transformations/fpe Keys ---- card-number
- View the details of the newly created - card-numbertransformation.- $ vault read transform/transformations/fpe/card-number Key Value --- ----- allowed_roles [payments] deletion_allowed false template builtin/creditcardnumber templates [builtin/creditcardnumber] tweak_source internal type fpe
Transform secrets
The Vault client applications must have the following in their policy to perform
data encoding and decoding using the Transform secrets engine enabled at
transform/.
# To request data encoding using any of the roles
# Specify the role name in the path to narrow down the scope
path "transform/encode/*" {
   capabilities = [ "update" ]
}
# To request data decoding using any of the roles
# Specify the role name in the path to narrow down the scope
path "transform/decode/*" {
   capabilities = [ "update" ]
}
- Encode a value with the - paymentsrole.- $ ENCODED_OUTPUT=$(vault write transform/encode/payments \ value=1111-2222-3333-4444 \ -format=json | jq -r '.data | .encoded_value') \ && echo encoded_value: $ENCODED_OUTPUT- Example output: - encoded_value: 9474-2096-7736-0783
- Decode the value encoded with - paymentsrole where the- valueis set to the returned- encoded_value.- $ vault write transform/decode/payments \ value=$ENCODED_OUTPUT- Example output: - Key Value --- ----- decoded_value 1111-2222-3333-4444
Create custom templates
Templates define the data format patterns that you wish to keep while transforming the secrets. In this section, you are going to create a transformation template which encodes British passport numbers.

The passport number on a British passport is a pattern consisting of a 9-digit numeric value which can be expressed
using regular expression as (\d{9}). The parentheses tell Vault to encode all values
grouped within; therefore, (\d{9}) will encode the entire passport number.
If you want to encode the last 7 digits leaving the first two numbers
unchanged, the expression should be \d{2}(\d{7}).

- Display all the exiting templates. - $ vault list transform/template Keys ---- builtin/creditcardnumber builtin/socialsecuritynumber
- Create a template named - uk-passport-tmpl.- $ vault write transform/template/uk-passport-tmpl \ type=regex \ pattern="(\d{9})" \ alphabet=builtin/numeric- Example output: - Success! Data written to: transform/template/uk-passport-tmpl- This template uses the built-in alphabet, - builtin/numeric.
- Create a transformation named - uk-passportwith the- uk-passport-tmpltemplate.- $ vault write transform/transformations/fpe/uk-passport \ template=uk-passport-tmpl \ tweak_source=internal \ allowed_roles='*'- Example output: - Success! Data written to: transform/transformations/fpe/uk-passport
- Update the - paymentsrole to include the- uk-passporttransformation.- $ vault write transform/role/payments transformations=card-number,uk-passport Success! Data written to: transform/role/payments- The payments role has two transformations. Future requests to encode/decode require that the specific transformation is provided. 
- Encode a value with the - paymentsrole with the- uk-passport.- $ ENCODED_OUTPUT=$(vault write transform/encode/payments value="123456789" \ transformation=uk-passport -format=json | jq -r '.data | .encoded_value') \ && echo encoded_value: $ENCODED_OUTPUT- Example output: - encoded_value: 128151714
Note
Remember that you must specify which transformation to use when you send an encode request since the payments role has two transformations associated with it.
Advanced handling
This section walks you through the new template features introduced in Vault Enterprise v1.9:
Encoding customization
In this section, you are going to create a transformation template which encodes Social Security numbers that may have an optional SSN: or ssn: prefix, and which are optionally separated by dashes or spaces.
A United States Social Security number is a 9-digit number, commonly written
using a 3-2-4 digit pattern which can be expressed using the regular expression
(\d{3})[- ]?(\d{2})[- ]?(\d{4}). The optional prefix can be expressed using
the regular expression (?:SSN[: ]?|ssn[: ]?)?. The use of non-capturing groups
tells Vault not to encode the prefix if it is present.
You will use the new encode_format field to specify what the encoded output
should look like. In the value for encode_format, variables representing the
capture groups of pattern are used to lay out the result. The variables are in
the form of $1, $2, etc…, one for each of the capture groups in pattern; and
in the form of ${name} or $name for the named capture groups. For more
detailed information see the Go regexp.Expand
documentation.
When a template has a value for encode_format, it will always be used. Make
sure that the resulting encoded output can be matched by pattern, otherwise
decoding will not be possible.
- Create a template named - us-ssn-tmpl.- $ vault write transform/template/us-ssn-tmpl \ type=regex \ pattern='(?:SSN[: ]?|ssn[: ]?)?(\d{3})[- ]?(\d{2})[- ]?(\d{4})' \ encode_format='$1-$2-$3' \ alphabet=builtin/numeric- Example output: - Success! Data written to: transform/template/us-ssn-tmpl
- Create a transformation named - us-ssnwith the- us-ssn-tmpltemplate.- $ vault write transform/transformations/fpe/us-ssn \ template=us-ssn-tmpl \ tweak_source=internal \ allowed_roles='*'- Example output: - Success! Data written to: transform/transformations/fpe/us-ssn
- Update the - paymentsrole to include the- us-ssntransformation.- $ vault write transform/role/payments transformations=card-number,uk-passport,us-ssn Success! Data written to: transform/role/payments
Validation
- Encode values with the - paymentsrole with the- us-ssntransformation.- $ ENCODED_OUTPUT=$(vault write transform/encode/payments value="123-45-6789" \ transformation=us-ssn \ -format=json | jq -r '.data | .encoded_value') \ && echo encoded_value: $ENCODED_OUTPUT- Example output: - encoded_value: 489-82-2140
- Try encoding value that starts with - SSN.- $ vault write transform/encode/payments value="SSN:$ENCODED_OUTPUT" \ transformation=us-ssn- Example output: - Key Value --- ----- encoded_value 766-52-7759
- Try encoding value that starts with - ssn.- $ vault write transform/encode/payments value="ssn:$ENCODED_OUTPUT" \ transformation=us-ssn- Example output: - Key Value --- ----- encoded_value 766-52-7759
- Decode the value encoded with the - paymentsrole with the- us-ssntransformation where the- valueis set to the- encoded_value.- $ vault write transform/decode/payments value="$ENCODED_OUTPUT" \ transformation=us-ssn- Example output: - Key Value --- ----- decoded_value 123-45-6789
Decoding customization
When running Vault Enterprise v1.9 or later, you can specify one or more
optional formats to use during decoding. In this section, you are going to
modify the template us-ssn-tmpl, created in the previous section, to add two
decoding formats: one to decode values separated by spaces, and the second to
decode only the last four digits.
Like encode_format, decode_formats have variables representing the capture
groups of pattern to lay out the decoded output. Specifying a decode format is
optional, and it is specified as part of the path when performing the decode
operation.
- Create a template named - us-ssn-tmpl.- $ vault write transform/template/us-ssn-tmpl \ type=regex \ pattern='(?:SSN[: ]?|ssn[: ]?)?(\d{3})[- ]?(\d{2})[- ]?(\d{4})' \ encode_format='$1-$2-$3' \ decode_formats=space-separated='$1 $2 $3' \ decode_formats=last-four='*** ** $3' \ alphabet=builtin/numeric- Example output: - Success! Data written to: transform/template/us-ssn-tmpl
- Create a transformation named - us-ssnwith the- us-ssn-tmpltemplate.- $ vault write transform/transformations/fpe/us-ssn \ template=us-ssn-tmpl \ tweak_source=internal \ allowed_roles='*'- Example output: - Success! Data written to: transform/transformations/fpe/us-ssn
- Update the - paymentsrole to include the- us-ssntransformation.- $ vault write transform/role/payments transformations=card-number,uk-passport,us-ssn Success! Data written to: transform/role/payments
- Encode values with the - paymentsrole with the- us-ssntransformation.- $ ENCODED_OUTPUT=$(vault write transform/encode/payments value="123-45-6789" \ transformation=us-ssn \ -format=json | jq -r '.data | .encoded_value') \ && echo encoded_value: $ENCODED_OUTPUT- Example output: - encoded_value: 489-82-2140
- Decode values with the - paymentsrole, the- us-ssntransformation and the- space-separateddecoding format.- $ vault write transform/decode/payments/space-separated value="$ENCODED_OUTPUT" \ transformation=us-ssn- Example output: - Key Value --- ----- decoded_value 123 45 6789
- Decode values with the - paymentsrole, the- us-ssntransformation and the- last-fourdecoding format.- $ vault write transform/decode/payments/last-four value="$ENCODED_OUTPUT" \ transformation=us-ssn- Example output: - Key Value --- ----- decoded_value *** ** 6789
Access control
As the decode format is part of the path of the write operation during decoding, Vault policies can be used to control access to them.
# Allow decoding using any of the decode formats
path "transform/decode/us-ssn/*"
{
    capabilities = ["update"]
}
# Allow decoding using only the last-four decode format
path "transform/decode/us-ssn/last-four"
{
    capabilities = ["update"]
}
# Allow decoding without specifying a decode format
path "transform/decode/us-ssn"
{
    capabilities = ["update"]
}
To demonstrate the functionality, create a token with a policy that will only
permit decoding using the last-four decode format.
- Define the policy in the file named - last-four.hcl.- $ tee last-four.hcl <<EOF # Allow decoding using only the last-four decode format path "transform/decode/payments/last-four" { capabilities = ["update"] } EOF
- Create the - last-fourwith the policy defined in- last-four.hcl.- $ vault policy write last-four last-four.hcl Success! Uploaded policy: us-ssn-last-four
- Create a token with the - last-fourpolicy attached and store the token in the variable- $LAST_FOUR_TOKEN.- $ LAST_FOUR_TOKEN=$(vault token create -format=json -policy="last-four" | jq -r ".auth.client_token")
- Using the token, decode values with the - paymentsrole, the- us-ssntransformation and the- last-fourdecoding format.- $ VAULT_TOKEN=$LAST_FOUR_TOKEN vault write transform/decode/payments/last-four \ value="766-52-7759" \ transformation=us-ssn- Example output: - Key Value --- ----- decoded_value *** ** 6789
- Trying to use the token to decode with the - paymentsrole with the- us-ssntransformation with the- space-separateddecode format, or without specifying a decode format will fail.- $ VAULT_TOKEN=$LAST_FOUR_TOKEN vault write transform/decode/payments \ value="766-52-7759" \ transformation=us-ssn- Example output: - Error writing data to transform/decode/payments: Error making API request. URL: PUT http://localhost:8200/v1/transform/decode/payments Code: 403. Errors: * 1 error occurred: * permission denied
Create custom alphabets
Alphabet defines a set of characters (UTF-8) that is used for FPE to determine the validity of plaintext and ciphertext values.
These are a number of built-in alphabets available to use.
| Alphabets | Description | 
|---|---|
| builtin/numeric | Numbers | 
| builtin/alphalower | Lower-case letters | 
| builtin/alphaupper | Upper-case letters | 
| builtin/alphanumericlower | Numbers and lower-case letters | 
| builtin/alphanumericupper | Numbers and upper-case letters | 
| builtin/alphanumeric | Numbers and letters | 
New alphabets can be created to satisfy the template requirements.
To learn the command, create a non-zero-numeric alphabet which contains
non-zero numbers.
Display existing alphabets.
$ vault list transform/alphabet
Keys
----
builtin/alphalower
builtin/alphanumeric
builtin/alphanumericlower
builtin/alphanumericupper
builtin/alphaupper
builtin/numeric
Create an alphabet named non-zero-numeric.
$ vault write transform/alphabet/non-zero-numeric alphabet="123456789"
Success! Data written to: transform/alphabet/non-zero-numeric
This new alphabet consists of only characters from the provided set 123456789.
Data masking
Data masking is used to hide sensitive data from those who do not have a clearance to view them. For example, this allows a contractor to test the database environment without having access to the actual sensitive customer information. Data masking has become increasingly important with the enforcement of General Data Protection Regulation (GDPR) introduced in 2018.
The following steps demonstrate the use of masking to obscure your customer's phone number since it is personally identifiable information (PII).
Note
Masking is a unidirectional operation; therefore, encode is the
only supported operation.
You will create a phone-number-tmpl template which masks phone numbers with its country code visible.

- Create a template named "phone-number-tmpl" with country code. - $ vault write transform/template/phone-number-tmpl type=regex \ pattern="\+\d{1,2} (\d{3})-(\d{3})-(\d{4})" \ alphabet=builtin/numeric- Example output: - Success! Data written to: transform/template/phone-number-tmpl
- Create a transformation named "phone-number" with the - phone-number-tmpltemplate and allow all roles to use it.- $ vault write transform/transformations/masking/phone-number \ template=phone-number-tmpl \ masking_character=# \ allowed_roles='*'- Example output: - Success! Data written to: transform/transformations/masking/phone-number- The - typeis set to- maskingand specifies the- masking_charactervalue instead of- tweak_source. The default masking character is- *if you don't specify one.
- Test and verify the newly created - phone-numbermask transformation by adding the- phone-numbertransformation to the- paymentsrole.- $ vault write transform/role/payments \ transformations=card-number,uk-passport,phone-number- Example output: - Success! Data written to: transform/role/payments
- Encode a value with the - paymentsrole with the- phone-numbertransformation.- $ vault write transform/encode/payments value="+1 123-345-5678" \ transformation=phone-number- Example output: - Key Value --- ----- encoded_value +1 ###-###-####
Batch input processing
When you need to encode more than one secret value, you can send multiple secrets in a request payload as batch_input instead of invoking the API endpoint multiple times to encode secrets individually.
Example Scenario 1:
You received a credit card number, British passport number and a phone number
of a customer and wish to transform all these secrets using the payments role.
- Create an API request payload with multiple values, each with the desired transformation. - $ tee input-multiple.json <<EOF { "batch_input": [ { "value": "1111-1111-1111-1111", "transformation": "card-number" }, { "value": "123456789", "transformation": "uk-passport" }, { "value": "+1 123-345-5678", "transformation": "phone-number" } ] } EOF
- Encode all the values with the - paymentsrole.- $ curl --header "X-Vault-Token: $VAULT_TOKEN" \ --header "X-Vault-Namespace: $VAULT_NAMESPACE" \ --request POST \ --data @input-multiple.json \ $VAULT_ADDR/v1/transform/encode/payments | jq ".data"- Example output: - { "batch_results": [ { "encoded_value": "7998-7227-5261-3751" }, { "encoded_value": "908547441" }, { "encoded_value": "## ###-###-####" } ] }
Example Scenario 2:
An on-premises database stores corporate card numbers and your organization decided to migrate the data to another database. You wish to encode those card numbers before storing them in the new database.
- Create a request payload with multiple card numbers. - $ tee payload-batch.json <<EOF { "batch_input": [ { "value": "1111-1111-1111-1111", "transformation": "card-number" }, { "value": "2222-2222-2222-2222", "transformation": "card-number" }, { "value": "3333-3333-3333-3333", "transformation": "card-number" }, { "value": "4444-4444-4444-4444", "transformation": "card-number" } ] } EOF
- Encode all the values with the - paymentsrole.- $ BATCH_ENCODED=$(curl --header "X-Vault-Token: $VAULT_TOKEN" \ --header "X-Vault-Namespace: $VAULT_NAMESPACE" \ --request POST \ --data @payload-batch.json \ $VAULT_ADDR/v1/transform/encode/payments | jq ".data") \ && echo $BATCH_ENCODED- Example output: - { "batch_results": [ { "encoded_value": "7998-7227-5261-3751" }, { "encoded_value": "2026-7948-2166-0380" }, { "encoded_value": "3979-1805-7116-8137" }, { "encoded_value": "0196-8166-5765-0438" } ] }
Decode the values
- Create a request payload with the encoded card numbers. - $ tee payload-batch.json <<EOF { "batch_input": [ { "value": "$(echo $BATCH_ENCODED | jq -r '.batch_results[0].encoded_value')", "transformation": "card-number" }, { "value": "$(echo $BATCH_ENCODED | jq -r '.batch_results[1].encoded_value')", "transformation": "card-number" }, { "value": "$(echo $BATCH_ENCODED | jq -r '.batch_results[2].encoded_value')", "transformation": "card-number" }, { "value": "$(echo $BATCH_ENCODED | jq -r '.batch_results[3].encoded_value')", "transformation": "card-number" } ] } EOF
- Decode all the values with the - paymentsrole.- $ curl --header "X-Vault-Token: $VAULT_TOKEN" \ --header "X-Vault-Namespace: $VAULT_NAMESPACE" \ --request POST \ --data @payload-batch.json \ $VAULT_ADDR/v1/transform/decode/payments | jq ".data"- Example output: - { "batch_results": [ { "decoded_value": "1111-1111-1111-1111" }, { "decoded_value": "2222-2222-2222-2222" }, { "decoded_value": "3333-3333-3333-3333" }, { "decoded_value": "4444-4444-4444-4444" } ] }
Additional discussion
Bring your own key (BYOK)
Vault Enterprise users running version 1.12.0 or greater can use the BYOK functionality to import an existing encryption key generated outside of Vault, and use it with Transform secrets engine.
The target key for import can originate from an HSM or other external source, and must be prepared according to its origin before you can import it.
The example shown here will use a 256-bit AES key, referred to as the target key. To successfully import the target key, you must perform the following operations to prepare it.
- Generate an ephemeral 256-bit AES key. 
- Wrap the target key using the ephemeral AES key with AES-KWP. 
- Wrap the AES key under the Vault wrapping key using RSAES-OAEP with MGF1 and either SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512. 
- Delete the ephemeral AES key. 
- Append the wrapped target key to the wrapped AES key. 
- Base64 encode the result. 
A specific code example for preparing and wrapping the key for import is beyond the scope of this tutorial. For more details about wrapping the key for import including instructions for wrapping key from an HSM, refer to the key wrapping guide.
Before you can wrap the key for import, you must read the wrapping key from Vault so that it can be used to prepare your key.
$ vault read -field=public_key transform/wrapping_key
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0aBVXa1Z8X1n1z3smBjU
J+Vm16AznaIrDxWrMAEsQt8xqh33gNMdzsdhNGy0+UzF2mxs9lUbp3uXJxqSaJDB
B+yeSqB4svgcQneg5pZnpZ1Af1s8X6uHTjZZxlHpJ0wumA//zWwg+0TtDij16C5o
Qpep7+UqA9qEcVheCP4puyQXssGH6vwbV4nspNTd1E5RgXe9xpdUKW+ih0pJWbNN
wiW1L6YP8F6dQ4adr6Nm/UUoTpKnvdippT980SLFrkl7v6xh+UKC51bS5fxtQ4Xl
dFCZYWO+Z7HCu3dWEte0Q5vhvbDLCJYKQ/avsQ8EXJtBYzKS7rtvDOYZLOFAgGs4
yeUgVOaIEHXmp+r7CdXnMlo9/5qN02i16HavTgQvaBbPclgH2NWE2JP4sKNsFfyF
DIL9btnUjjgTl6/KaxlVBmZyx96A0V1UTEphziFgeUVw2Rc7PkyOX9lXdAu34A3i
0kgjZC1Y8x/TnGWJ4ofyFBM8RmSaoe4e9C2i2VjHFzJX3ya53Rewy/e+MdvG3tlI
tIEXoanXtTAPbpBJw9tY4FLO8WFsQuBiYg/ovO3ZcYzK5tZwdPnWLjgiXitFchUs
s0lEYFARLap6i/nXxmJnE8jJeAoZ6QSOpNf9ss4rIM9liFvHy+O5Fb3qRLg4zu9M
ERqkZVYfyxp4bChyZwOJD+ECAwEAAQ==
-----END PUBLIC KEY-----
The output is the (4096-bit RSA) wrapping key.
Use the wrapping key value at step 3 in the previously detailed preparation steps. Once you have prepared and base64 encoded the ciphertext, export the value to the environment variable IMPORT_CIPHERTEXT.
Example:
$ export IMPORT_CIPHERTEXT=XQiDLXkoN2nE3UXIUnNb4joUSUDyB0OsD/U0T3WpSGuatB2Rd89yj57v1eDb2RDq8tt904iCftDY1c4fJXBlNhvZtRgS45zV+hZZA806YZ2a2ha3rFFEEobRLxs0aCoyq+iqBsOxG4pHG5irtzqfPz5IJRtN0SXxcoOodRm0hGU69++iZO5GkJ8k6Y4513Y/Qwnm/4rBToE9E6toQSTf7exF3yp0wxe/GSfFKCr2aVvYnyK0j+UYNbDeK0M7JOSQ38JmC62oPEfYdI+onyzQxQJsXec/5GOZWsuNnhZtvDNeslnAoC20HiMxl2aMQn4PAvWO+HtlhleXKjaWgDuopgj+qjsSny72pKo2hSntGsamaPqVZQHDmYpIQP4aBsqQeq5bXtDc407cAEPl+MA5huzazdNgMeZqCYZNYFPlUVtZ2dJ6A9ogFE7B8RLAEf4t717kTvlQ0qsXwXOGtoFuw/AQGMTF1CNmCVEJWZBPkxH6GXT6N3QAgwRMYVP6r//IAZ4FKmZ8V4nwmp2uBN0H49XekH1yULa3lWGSXx3CGGy3hYuUHGi6B7mWEH7B0jQgk3EtU1JlgtpTk/jlnL7mpa8VRZefAZqFDX6DoEjioXtqbQAA1Vvkke/PDN3OL6a5aj9kr2UJvlRPfwYsSHw+l8oyazrLs8aKHiaVJAfsVD5y02ipMIGFwaUjswYeW1LxtXg4FVfINzUAoq7z9mvQDby1mvh0Mtr9
Create a new transformation role named physical-access to use for the proximity-card transformation that you will import the key into.
$ vault write transform/role/physical-access transformations=proximity-card
Success! Data written to: transit/role/physical-access
Create a new template named identifier to match a proximity card identifier string having the format shown in this example: 8A642EC3-3C8A-40C2-8AC0-A039ECC0FFEE.
$ vault write transform/template/identifier \
    type=regex \
    pattern="(\b[A-Z\d]{8}\b)[-/](\b[A-Z\d]{4}\b)[-/](\b[A-Z\d]{4}\b)[-/](\b[A-Z\d]{4}\b)[-/](\b[A-Z\d]{12}\b)" \
    alphabet=builtin/alphanumericupper
Example output:
Success! Data written to: transit/template/identifier
Import the key into the proximity-card transformation; add the allowed_roles parameter and specify the physical-access role.
$ vault write transform/transformations/fpe/proximity-card/import \
    ciphertext=$IMPORT_CIPHERTEXT \
    allowed_roles=physical-access \
    template=identifier \
    tweak_source=internal
Example output:
Success! Data written to: transform/transformations/fpe/proximity-card/import
Try using the newly imported key to encode a value.
$ vault write transform/encode/physical-access value="19742EC3-3C8A-B0C2-23C0-A039ECA9DD23" \
    transformation=proximity-card
Key              Value
---              -----
encoded_value    OGCIWU8A-RBW0-R7FJ-8IZZ-VZZRIWZQ3P5Z
The imported key is working, and the encoded value returned by the proximity-card transformation is using the imported key.
Note
The FPE transformation does not currently support versioning or rotating of its encryption keys.
Next steps
To actually integrate your application with Vault and leverage the transform secrets engine, there are a number of resources which must be configured.
Before the application can even request data transformation, it first needs to authenticate with Vault. Therefore, an auth method (e.g. AWS, Kubernetes, AppRole) must be enabled and configured for the application to use. In addition, an appropriate policy must be created and attached to the client token.

You can codify the Vault configuration using Terraform, and make the configuration repeatable. The Terraform Vault Provider supports the transform secrets engine. It can create policies, enable and configure auth methods and more.
Refer to the Codify Management of Vault Enterprise Using Terraform tutorial to learn how to leverage Terraform.
On the application side, you can run Vault Agent to authenticate with Vault and manage the lifecycle of the client token. Refer to the following tutorials to learn more about Vault Agent:
The Encrypting Data while Preserving Formatting with the Vault Enterprise Transform Secrets Engine blog post introduces some code examples to invoke the transform secrets engine using Vault API.
Clean up
- Unset the - VAULT_TOKENenvironment variable.- $ unset VAULT_TOKEN
- Unset the - VAULT_ADDRenvironment variable.- $ unset VAULT_ADDR
- Unset the - IMPORT_CIPHERTEXTenvironment variable.- $ unset IMPORT_CIPHERTEXT
- Remove the payload files. - $ rm -f input.json payload-batch.json payload.json input-multiple.json last-four.json payload-template.json
- You can stop the Vault dev server by pressing Ctrl+C where the server is running. Or, execute the following command. - $ pgrep -f vault | xargs kill- If you are using Vault Dedicated, you can delete the cluster from the HCP Portal. 
Summary
The Transform secrets engine performs secure data transformation and tokenization against the input data. Transformation methods may encompass NIST vetted cryptographic standards such as format-preserving encryption (FPE) via FF3-1, but can also be pseudonymous transformations of the data through other means, such as masking. This tutorial walked through the use of the Transform secrets engine step-by-step.
Limits:
The Transform secrets engine obeys the FF3-1 minimum and maximum sizes on the length of an input, which are a function of the alphabet size.
Help and reference
- Transform Secrets Engine (API)
- Transform Secrets Engine
- Encrypting Data while Preserving Formatting with the Vault Enterprise Transform Secrets Engine
Next steps
The Encrypting Data with Transform Secrets Engine tutorial introduces demo applications written in Go and Java to learn how to implement the Transform secrets engine API in your application.
If you are interested in data tokenization, refer to the Tokenize Data with Transform Secrets Engine tutorial.














