.. _encrypt: Method: Encrypt Data -------------------- Description ~~~~~~~~~~~ This endpoint encrypts the provided plaintext using the named key in the specified vault. The returned ciphertext starts with storedsafe:v1:. The storedsafe prefix indicates that it has been wrapped by StoredSafe. The :v1: indicates which version of the key (if rotated) was used to encrypt the plaintext. The rest is a base64 encoded string of the initialization vector (IV) and the ciphertext and possible an appended tag. The IV is generated by StoredSafe using the randombytes API from Sodium. And if the selected encryption algorithm is of AEAD type, the corresponding tag is appended to string. AES-GCM returned ciphertext consists of base64(IV + ciphertext + tag), and the resulting ciphertext would be base64(IV + ciphertext) if a non-AEAD algorithm (like AES-OFB) was used. - If the User has :ref:`Write` permission in the affected vault and the key does not exist, it will be created. - If the user only has :ref:`Read` permissions, and the key does not exist, an error will be returned. .. note:: This endpoint requires at least :ref:`Read` permission in the affected vault. .. note:: All plaintext data must be base64-encoded. URL Syntax ~~~~~~~~~~ /api/{version}/transparent/:vaultid/encrypt/:name HTTP Method ~~~~~~~~~~~ POST Successful HTTP Response ~~~~~~~~~~~~~~~~~~~~~~~~ 200 Parameters ~~~~~~~~~~ +----------------+------------------+----------------+--------+--------------+--------------+---------------------------------------------------+ | 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 | | +----------------+------------------+----------------+--------+--------------+--------------+---------------------------------------------------+ | name | Key name | URL-encoded | String | | Yes | | +----------------+------------------+----------------+--------+--------------+--------------+---------------------------------------------------+ | key_version | Key version | JSON-encoded | String | | | Will use latest version if unspecified | +----------------+------------------+----------------+--------+--------------+--------------+---------------------------------------------------+ | type | Type of key | JSON-encoded | String | aes128-gcm96 | No :sup:`2)` | See :ref:`table` for supported types | +----------------+------------------+----------------+--------+--------------+--------------+---------------------------------------------------+ | plaintext | Plaintext | JSON-encoded | String | | Yes | Base64 encoded | +----------------+------------------+----------------+--------+--------------+--------------+---------------------------------------------------+ .. note:: | :sup:`1)` One of the methods is required. | :sup:`2)` Only required if the named key doesn't exist. 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 | Key version | String | +----------------------+---------------------------------------------------+---------+ | CALLINFO.ciphertext | IV + Ciphertext + (optional) Tag (Base64 encoded) | 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 ~~~~~~~~ Encrypt the supplied plaintext with the named encryption key in vault (vaultid) 179. **Request** :: $ base64 <<< "sensitive information" c2Vuc2l0aXZlIGluZm9ybWF0aW9uCg== POST /api/1.0/transparent/179/encrypt/my-new-key x-http-token: your_storedsafe_token { "key_version": "1", "plaintext": "c2Vuc2l0aXZlIGluZm9ybWF0aW9uCg==" } **Response** :: HTTP/2 201 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", "objectid": "8743", "type": "aes256-gcm96", "ciphertext": "storedsafe:v1:fCC+8a3plkkEaveSGaC23i9grdhAioNXgXtQW09Dkes=" }, "DATA": { "name": "my-new-key", "vaultid": "179", "plaintext": "c2Vuc2l0aXZlIGluZm9ybWF0aW9uCg==", "key_version": "1", "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_encrypt: Annotated example ~~~~~~~~~~~~~~~~~ In this example, we will show how to encrypt a local file (``/data/small_file.blob``) with AES256-GCM by using the :ref:`/encrypt` endpoint, using StoredSafe to maintain and secure the key for the symmetric encryption. 1. Start by generating an encryption key using the :ref:`/create key` endpoint. The created key is :ref:`protected` by StoredSafe and is unavailable to :ref:`Read` and :ref:`Write` users in the vault. .. note:: The key material (e.g. the plaintext version of the created encryption key) is only available to a user with :ref:`Admin` privileges in the affected vault, and only if the key has been marked as :ref:`exportable`. :: $ curl --header "x-http-token: ..." --data '{ "type": "aes256-gcm96", "info": "my new key" }' --request GET https://safe.domain.cc/api/1.0/transparent/179/keys/my-new-key . . Content-type: application/json; charset=UTF-8 { "CALLINFO": { "name": "my-new-key", "type": "aes256-gcm96", 2. Next step is to base64 encode the information to be encrypted. :: $ BASE64_ENCODED=$(base64 ` endpoint to have StoredSafe encrypt the file using AES256-GCM with the newly created key (``my-new-key``). :: $ curl --header "x-http-token: ..." --request POST --data '{ "key_version": "1", "plaintext": $BASE64_ENCODED }' https://safe.domain.cc/api/1.0/transparent/encrypt/my-new-key . . Content-type: application/json; charset=UTF-8 { "CALLINFO": { "ciphertext": "storedsafe:v1:fCC+8a3plkkEaveSGaC23i9grdhAioNXgXtQW09Dkes=", 4. Finally, save the encrypted file. :: $ echo "storedsafe:v1:fCC+8a3plkkEaveSGaC23i9grdhAioNXgXtQW09Dkes=" > /data/small_file.blob.enc 5. Securely delete the original, plaintext file. :: $ sterialize --passes 20 /data/small_file.blob 6. Now you have one file (``/data/small_file.blob.enc``), encrypted with AES256-GCM96 and the key is securely stored in StoredSafe. .. 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 :ref:`/decrypt` endpoint to decrypt the encrypted file. :: $ curl --header "x-http-token: ..." --request POST --data '{ "ciphertext": "storedsafe:v1:fCC+8a3plkkEaveSGaC23i9grdhAioNXgXtQW09Dkes=" }' https://safe.domain.cc/api/1.0/transparent/decrypt/my-new-key . . Content-type: application/json; charset=UTF-8 { "CALLINFO": { "plaintext": "Z0VNRHZRcUIwVmhhNE5UZjdZSlU5Y091QTFlZTZRbVNEVTRJNnFVWQo=" $ base64 -d <</data/small_file.blob 2. Now the file ``/data/small_file.blob`` contains the original plaintext content.