Introduction
The need may arise to manually decrypt data previously encrypted by Vault Transit. Another possibility is to have vault manage the encryption keys on our behalf while another program handles the actual encryption/decryption, which is useful for encrypting large files. We'll walk through both scenarios here.
Scenario 1 - Decrypt Data Previously Encrypted by Transit
Prerequisites
- To decrypt data encrypted by Vault (transit), the key-ring must be set 'exportable' beforehand. If this isn't set, it's impossible to retrieve the encryption key.
$ vault write transit/keys/demo exportable=true
Procedure
-
With the prerequisite met (key-chain set "exportable"), we can export the encryption key using the 'transit/export/encryption-key/<key-name>' path.
$ vault read transit/export/encryption-key/demo
Key Value
--- -----
keys map[1:9h5bCooSKBtOS0kLG4hYkV6ZF8dBur4OGuYxA7CTJRU=]
name demo
type aes256-gcm96
- From the above output, we can see the encryption key is
9h5bCooSKBtOS0kLG4hYkV6ZF8dBur4OGuYxA7CTJRU=
. Note, the key is base64-encoded so it can be represented in text format. When used to actually decrypt data, it will need to be decoded first. -
Armed with our encryption key, we can feed it into another program to manually decrypt any data previously encrypted by vault using said key.
-
Below is an simple program written in python that will perform the decryption for us.
import sys
import base64
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
if len(sys.argv) < 3:
print(f'usage: {sys.argv[0]} <data_to_decrypt_base64> <key_base64>')
sys.exit(1)
ciphertext = base64.b64decode(sys.argv[1])
key = base64.b64decode(sys.argv[2])
iv = ciphertext[:int(96/8)]
actual_ciphertext = ciphertext[int(96/8):]
aad = None
plaintext = AESGCM(key).decrypt(iv, actual_ciphertext, aad).decode('utf-8')
print(plaintext)
- Here's how it would look all put together.
$ vault write transit/keys/demo exportable=true
Success! Data written to: transit/keys/demo
$ vault write transit/encrypt/demo plaintext=$(base64 <<< "4111 1111 1111 1111")
Key Value
--- -----
ciphertext vault:v1:qKp7GDihfFbY/Vn1mnuZeBRKNvifu8T4w7jSKmJhNtG181TbXbo0OnpAtce0YEh3
key_version 1
$ vault read transit/export/encryption-key/demo
Key Value
--- -----
keys map[1:9h5bCooSKBtOS0kLG4hYkV6ZF8dBur4OGuYxA7CTJRU=]
name demo
type aes256-gcm96
$ python3 ./decrypt.py 'qKp7GDihfFbY/Vn1mnuZeBRKNvifu8T4w7jSKmJhNtG181TbXbo0OnpAtce0YEh3' '9h5bCooSKBtOS0kLG4hYkV6ZF8dBur4OGuYxA7CTJRU='
4111 1111 1111 1111
Scenario 2 - Using Another Program for Both Encryption/Decryption
This scenario is useful when you need to encrypt large files where you don't want send the whole file to vault for encryption. Utilizing the data-key
functionality enables you to have vault store the encryption key for later decryption.
Prerequisites
- None
Procedure
- First create a new key.
vault write -f transit/keys/demo2
- Next, we generate a data-key. You can see now, any existing key can be used to create a data-key for use by another program.
$ vault write -f transit/datakey/plaintext/demo2
Key Value
--- -----
ciphertext vault:v1:odkugO08FJMJlYvT4Keur4dj9X/agRqkEsNPJpYEAoTRFx9KVn75aqYAYIcjWiaTpTgl7vSfYgutMBTj
key_version 1
plaintext nnhIB7D838mp4lz4a0gd+YOulPbgAXGpJPrFn6mLahE=
- In the output above the 'plaintext' value is what we would use to encrypt our data. Note, this key is base64 encoded so it's more manageable. It's vital to decode it beforehand.
- Here's what it would look like all put together. Note, our "3rd party program" in this example is the openssl command line tool.
$ vault write -f transit/keys/demo2
Success! Data written to: transit/keys/demo2
$ vault write -f transit/datakey/plaintext/demo2
Key Value
--- -----
ciphertext vault:v1:odkugO08FJMJlYvT4Keur4dj9X/agRqkEsNPJpYEAoTRFx9KVn75aqYAYIcjWiaTpTgl7vSfYgutMBTj
key_version 1
plaintext nnhIB7D838mp4lz4a0gd+YOulPbgAXGpJPrFn6mLahE=
$ cat > test.txt <<EOF
4111 1111 1111 1111
EOF
$ openssl aes-256-cbc -a -e -pbkdf2 -k "$(echo nnhIB7D838mp4lz4a0gd+YOulPbgAXGpJPrFn6mLahE=| base64 -d)" -in test.txt -out test.txt.encrypted
# At this point, we can throw away the 'plaintext' version of the key and just store the cipher-text version. Later we can retrieve the plain-text version using vault like below.
# The other option is to store the plaintext version somewhere else (securely), but this negates the need of vault.
$ vault write transit/decrypt/demo2 ciphertext="vault:v1:odkugO08FJMJlYvT4Keur4dj9X/agRqkEsNPJpYEAoTRFx9KVn75aqYAYIcjWiaTpTgl7vSfYgutMBTj"
Key Value
--- -----
plaintext nnhIB7D838mp4lz4a0gd+YOulPbgAXGpJPrFn6mLahE=
$ openssl aes-256-cbc -a -d -pbkdf2 -k "$(echo nnhIB7D838mp4lz4a0gd+YOulPbgAXGpJPrFn6mLahE=| base64 -d)" -in test.txt.encrypted -out -
4111 1111 1111 1111