HashiCorp Vault — Encrypt & Decrypt
The core Transit operations: encrypt plaintext, decrypt ciphertext, and batch process multiple items.
Encrypt
Plaintext must be base64-encoded before sending to Vault:
# Encrypt a string
vault write transit/encrypt/my-app-key \
plaintext=$(echo -n "my secret data" | base64)
Expected output:
Key Value
--- -----
ciphertext vault:v1:UEhLNVF...encrypted...data
key_version 1
Ciphertext format: vault:v<KEY_VERSION>:<BASE64_ENCRYPTED_DATA>
vault:— Prefix identifying Vault-encrypted datav1— Key version used for encryption- The rest — Base64-encoded encrypted payload
Decrypt
vault write transit/decrypt/my-app-key \
ciphertext="vault:v1:UEhLNVF...encrypted...data"
Expected output:
Key Value
--- -----
plaintext bXkgc2VjcmV0IGRhdGE=
# Decode the base64 plaintext
echo "bXkgc2VjcmV0IGRhdGE=" | base64 --decode
# my secret data
One-Liner Patterns
# Encrypt and get just the ciphertext
CIPHERTEXT=$(vault write -field=ciphertext transit/encrypt/my-app-key \
plaintext=$(echo -n "credit-card-4242" | base64))
# Decrypt and decode in one step
vault write -field=plaintext transit/decrypt/my-app-key \
ciphertext="$CIPHERTEXT" | base64 --decode
API Usage
# Encrypt via API
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data "{\"plaintext\": \"$(echo -n 'my secret' | base64)\"}" \
"$VAULT_ADDR/v1/transit/encrypt/my-app-key" | jq
# Decrypt via API
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"ciphertext": "vault:v1:UEhLNVF..."}' \
"$VAULT_ADDR/v1/transit/decrypt/my-app-key" | jq
Batch Operations
Encrypt or decrypt multiple items in a single request:
# Batch encrypt via API
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{
"batch_input": [
{"plaintext": "'$(echo -n "secret1" | base64)'"},
{"plaintext": "'$(echo -n "secret2" | base64)'"},
{"plaintext": "'$(echo -n "secret3" | base64)'"}
]
}' \
"$VAULT_ADDR/v1/transit/encrypt/my-app-key" | jq
Response:
{
"data": {
"batch_results": [
{"ciphertext": "vault:v1:abc...", "key_version": 1},
{"ciphertext": "vault:v1:def...", "key_version": 1},
{"ciphertext": "vault:v1:ghi...", "key_version": 1}
]
}
}
Batch decryption works the same way with batch_input containing ciphertext fields.
Context and Associated Data
Add context for key derivation (useful with derived keys):
# Encrypt with context
vault write transit/encrypt/my-app-key \
plaintext=$(echo -n "my secret" | base64) \
context=$(echo -n "user-123" | base64)
# Must provide the same context to decrypt
vault write transit/decrypt/my-app-key \
ciphertext="vault:v1:..." \
context=$(echo -n "user-123" | base64)
Application Integration — Python
import hvac
import base64
client = hvac.Client(url='http://127.0.0.1:8200', token='my-token')
# Encrypt
plaintext = base64.b64encode(b"credit-card-4242-4242").decode()
result = client.secrets.transit.encrypt_data(
name='my-app-key',
plaintext=plaintext
)
ciphertext = result['data']['ciphertext']
print(f"Ciphertext: {ciphertext}")
# Store ciphertext in database...
# Decrypt
result = client.secrets.transit.decrypt_data(
name='my-app-key',
ciphertext=ciphertext
)
decoded = base64.b64decode(result['data']['plaintext']).decode()
print(f"Plaintext: {decoded}")
# credit-card-4242-4242
Quick Reference
| Command | Description |
|---|---|
vault write transit/encrypt/KEY plaintext=BASE64 |
Encrypt |
vault write transit/decrypt/KEY ciphertext=CIPHER |
Decrypt |
vault write -field=ciphertext transit/encrypt/KEY ... |
Get ciphertext only |
Batch via API batch_input |
Encrypt/decrypt multiple items |
Next: Key Rotation