.. _datakey: Method: Generate Data Key ------------------------- Description ~~~~~~~~~~~ This endpoint generates a new random key and the value of the new key is wrapped (encrypted) with the named key in the specified vault. Optionally return the plaintext of the key as well. Whether plaintext is returned depends on the type used (wrapped vs plaintext) and the users permission in the vault. .. note:: This endpoint requires at least :ref:`Read` permission in the affected vault. .. note:: Returning the plaintext requires :ref:`Write` permission in the affected vault. See the :ref:`overview` of how transparent encryption in StoredSafe can help solve key distribution problems. URL Syntax ~~~~~~~~~~ /api/{version}/transparent/:vaultid/datakey/:type/:name HTTP Method ~~~~~~~~~~~ POST Successful HTTP Response ~~~~~~~~~~~~~~~~~~~~~~~~ 200 Parameters ~~~~~~~~~~ .. _wrapped_or_plaintext: +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ | Parameter name | Description | Parameter type | Type | Default | Mandatory | Comment | +================+======================+================+=========+===========+===========+====================================================================================+ | X-Http-Token | StoredSafe token | HTTP Header | String | | :sup:`1)` | Preferred method | +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ | token | StoredSafe token | JSON-encoded | String | | :sup:`1)` | Legacy method | +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ | vaultid | Vault-ID | URL-encoded | String | | Yes | | +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ | type | Wrapped or plaintext | URL-encoded | String | plaintext | Yes | wrapped, plaintext (plaintext requires :ref:`Write` permission in the vault) | +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ | name | Key name | URL-encoded | String | | Yes | | +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ | key_version | Key version | JSON-encoded | String | | | Will use Latest version if unspecified | +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ | bits | Key size | JSON-encoded | Integer | 256 | | 128, 256 or 512 | +----------------+----------------------+----------------+---------+-----------+-----------+------------------------------------------------------------------------------------+ .. note:: :sup:`1)` One of the methods is required. Response Attributes ~~~~~~~~~~~~~~~~~~~ +----------------------+------------------------------------+---------+ | Attribute | Description | Type | +======================+====================================+=========+ | CALLINFO.errorcodes | Number of errors | Integer | +----------------------+------------------------------------+---------+ | CALLINFO.errors | Number of errors | Integer | +----------------------+------------------------------------+---------+ | CALLINFO.general | Information | Array | +----------------------+------------------------------------+---------+ | CALLINFO.handler | Handler used | String | +----------------------+------------------------------------+---------+ | CALLINFO.status | SUCCESS or FAIL | String | +----------------------+------------------------------------+---------+ | CALLINFO.token | Rotated StoredSafe token :sup:`1)` | String | +----------------------+------------------------------------+---------+ | CALLINFO.key_version | Latest key version | String | +----------------------+------------------------------------+---------+ | CALLINFO.ciphertext | Ciphertext (Base64 encoded) | String | +----------------------+------------------------------------+---------+ | CALLINFO.plaintext | Plaintext (Base64 encoded) | String | +----------------------+------------------------------------+---------+ | CALLINFO.objectid | Object-ID | String | +----------------------+------------------------------------+---------+ | DATA | Supplied data in prior API-call | String | +----------------------+------------------------------------+---------+ | HEADERS.(headers) | HTTP Headers | String | +----------------------+------------------------------------+---------+ | PARAMS | Route parameters (empty) | Array | +----------------------+------------------------------------+---------+ | ERRORCODES | Error code and text :sup:`2)` | Object | +----------------------+------------------------------------+---------+ | ERRORS | Error code and text :sup:`2)` | Array | +----------------------+------------------------------------+---------+ .. note:: | :sup:`1)` Token to be used in subsequent calls | :sup:`2`) Only present if errors Examples ~~~~~~~~ Obtain a randomized datakey using high entropy in both plaintext and chipertext, wrapped using the latest version (v2) of the key ``my-new-key`` in the vault (vaultid) 179. **Request** :: POST /api/1.0/transparent/179/datakey/plaintext/my-new-key x-http-token: your_storedsafe_token **Response** :: HTTP/2 200 Content-type: application/json; charset=UTF-8 { "CALLINFO": { "errorcodes": 0, "errors": 0, "general": [], "handler": "EncryptionHandler", "status": "SUCCESS", "token": "rotated_storedsafe_token", "name": "my-new-key", "ciphertext": "storedsafe:v2:rsUKcXUaeUqIlAihBB7c5NoX9xAUxcJt8L1xS1bDuIulobKIp1OAOQ==", "plaintext": "Z0VNRHZRcUIwVmhhNE5UZjdZSlU5Y091QTFlZTZRbVNEVTRJNnFVWQo=" }, "DATA": { "name": "my-new-key", "vaultid": "179", "token": "your_storedsafe_token" }, "HEADERS": { "Accept": "*/*", "Content-Length": "169", "Content-Type": "application/json", "Host": "safe.domain.cc", "User-Agent": "curl/7.64.1", "X-Http-Token": "your_storedsafe_token" }, "PARAMS": [] } .. _annotated_example_datakey: Annotated example ~~~~~~~~~~~~~~~~~ In this example, we will show how to encrypt a local file (``/data/large_file.blob``) using AES256-GCM and using StoredSafe to maintain and secure the key for the symmetric encryption. 1. Start by generating a datakey using the :ref:`/datakey` endpoint, requesting both a wrapped key and a copy in :ref:`cleartext` (``/plaintext/``). The ciphertext returned is wrapped (encrypted) with the named key ``my-new-key``, as specified in the REST call. :: $ curl --header "x-http-token: ..." --request GET https://safe.domain.cc/api/1.0/transparent/179/datakey/plaintext/my-new-key . . Content-type: application/json; charset=UTF-8 { "CALLINFO": { "ciphertext": "storedsafe:v2:rsUKcXUaeUqIlAihBB7c5NoX9xAUxcJt8L1xS1bDuIulobKIp1OAOQ==", "plaintext": "Z0VNRHZRcUIwVmhhNE5UZjdZSlU5Y091QTFlZTZRbVNEVTRJNnFVWQo=" 2. Next step is to base64 decode the plaintext key and save it to a file. :: $ base64 -d <</data/key.bin 3. And then use the plaintext key to encrypt a local file, after creating (and saving) a random 12-byte IV to a file. :: $ dd if=/dev/random bs=12 count=1 >/data/iv.file $ aesgcm enc -iv /data/iv.file -tag /data/tag.file -in /data/large_file.blob -out /data/large_file.blob.enc -key /data/key.bin 4. Finally, save the wrapped encryption key. Since it wrapped (e.g. encrypted by another key), it can safely be stored together with the encrypted file. :: $ echo "storedsafe:v2:rsUKcXUaeUqIlAihBB7c5NoX9xAUxcJt8L1xS1bDuIulobKIp1OAOQ==" > /data/key.wrapped 5. Securely delete the plaintext key. :: $ sterialize --passes 20 /data/key.bin .. note:: Now several days, weeks, months or years can pass. Members in vault 179 might have shifted over time, but as long as the current user has at least read permission in the vault at the time of decryption, decryption will work. 1. When the file needs to be decrypted, use the decrypt endpoint to unwrap the wrapped key. :: $ curl --header "x-http-token: ..." --request POST --data '{ "ciphertext": "storedsafe:v2:rsUKcXUaeUqIlAihBB7c5NoX9xAUxcJt8L1xS1bDuIulobKIp1OAOQ==" }' https://safe.domain.cc/api/1.0/transparent/decrypt/my-new-key . . Content-type: application/json; charset=UTF-8 { "CALLINFO": { "plaintext": "Z0VNRHZRcUIwVmhhNE5UZjdZSlU5Y091QTFlZTZRbVNEVTRJNnFVWQo=" $ base64 -d <<key.bin 2. And finally, use the unwrapped key to decrypt the locally stored data. :: $ aesgcm dec -iv /data/iv.file -tag /data/tag.file -in /data/large_file.blob.enc -out /data/large_file.blob -key /data/key.bin