library(lockbox)
<- key_generate("private.key")
key key
Age key created at 2025-08-09 18:27:51
Public key: age1nd0hta5vernhcxzadqjz0ug28w00azkpevcknv9yww9eemzq44rqr0zus4
Simple file encryption and secret management for R using modern cryptographic tools. Provides functions to encrypt/decrypt files with ‘age’ and manage secrets in encrypted YAML files. Secrets can be easily exported as environment variables for use with APIs and services. Supports both file-based and in-memory key management workflows.
This package is designed for my (Vincent) personal use. I am not a security expert. This code might be unsafe. Use at your own risk.
lockbox
targets two main use cases:
To solve these problems, lockbox
provides Rust bindings to the age encryption tool for file encryption and implements a simple secrets management format. The default lockbox format is a simpler, more user-friendly version of SOPS, storing secrets in YAML files where keys remain in plain text but values are encrypted. For power users who need advanced features like key rotation and complex recipient management, full SOPS integration is also supported (see SOPS Integration section below).
age
: encryptionage is a simple and modern file encryption tool with small keys, no configuration options, and high security. It is designed to replace tools like GPG for most file encryption tasks.
There are two main encryption strategies with age
: passphrase or key pairs.
The first is simplest. A passphrase is assigned when encrypting the file. Then, whenever someone wishes to decrypt the file, they are prompted to supply that same password.
The second strategy relies on a pair of keys:
This situation illustrates the use of key pairs:
Anyone with your public key can encrypt files for you, but only you can decrypt them with your private key.
lockbox
: organize and export secretslockbox
implements a simple secrets management system for two main purposes:
The lockbox format creates YAML files that look like this:
API_KEY: "age1xyz789encrypted_value_here_abc123"
DATABASE_URL: "age1xyz789another_encrypted_value_def456"
lockbox_created: !expr "2024-01-15 10:30:00 UTC"
lockbox_version: "0.0.1"
lockbox_recipients:
- "age1abc123..."
As you can see, the secret keys (like API_KEY
) remain readable, but their values are encrypted using age. The file also includes metadata about when it was created, the package version, and which public keys can decrypt it.
You must never edit your lockbox.yaml
file manually. Always use the provided functions to ensure the file remains valid and encrypted.
The lockbox
package uses the age encryption format through a Rust implementation, so you need to install Rust to compile the package. The easiest way to install Rust is through rustup:
# Install Rust (all platforms)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Follow the installation prompts, then restart your terminal
Once Rust is installed, you can install the development version of lockbox
from Github:
Our first step is to create a private/public key pair using the key_generate()
function. The private key is saved to a file and should be kept secret. The public key can be shared and is used to encrypt data.
Age key created at 2025-08-09 18:27:51
Public key: age1nd0hta5vernhcxzadqjz0ug28w00azkpevcknv9yww9eemzq44rqr0zus4
This command created a local “identity file,” which holds both the public and private keys. The function returns the public key directly as a string.
Do not share the private.key
file. It should be kept secret and secure.
Security Note: The private key file is created with default system permissions, which may be readable by other users. After generating a key, set secure permissions:
lockbox
can encrypt and decrypt arbitrary files. To illustrate, let’s create a file with some text in it.
# write file
cat("Very sensitive data.\n", file = "sensitive.txt")
# make sure we can read it
readLines("sensitive.txt")
[1] "Very sensitive data."
Now, let’s use the public key and the file_encrypt()
function to encrypt the file. The .age
suffix is added automatically to the file name, and the content becomes gibberish.
[1] "age-encryption.org/v1"
[2] "-> X25519 2pKNkbTHMOPh19V4yH4PhDE4m/D1qINVPNFfYPo3ayE"
[3] "hM7CEcaWQ2Oy5D7S9Yxr6gdLUfsj/C9BsXohKMjXJcg"
[4] "-> jU$-grease 6obchv9B tPXI"
[5] "kba8dAo2Ks8gzqTMAw"
[6] "--- TOzduonqyTOQzn7wPPOmCibVjubsku0XVAro6GcZA+c"
[7] "U\xd30\xee\\\xa2\xee0\xf7|\022\xd8E\xfa\xbd\xb3\xe6\xaf'\xce{֦\x9e\xa0\006\x8f\x85+\x90\x9b\xb5\027\x8e\x83\xe6\xd9\xdfL%\017*\xa8\xdeG\x96\002.I\xd7\022\021\xc9"
Finally, we can decrypt the file using the private key file. The decrypted content is written to the specified output file.
lockbox
and exporting them as environment variablesSeveral packages and applications require users to export secrets as environment variables for easy access. For example, you may need to store a security key to access the API of an LLM provider; the location of your private database; or credentials to access AWS services.
Generally speaking, we do not want to store those secrets in plain text files. Instead, we can store them in an encrypted YAML file, and use a helper function to decrypt the file and export environment variables.
First, we define a named list with the values that we wish to store securely. Then, we call secrets_encrypt()
to encrypt those secrets into our lockbox file. Again, we use the public key for encryption.
lockbox
Now, we can retrieve all secrets using our private key file.
lockbox
To modify existing secrets or to add new ones, we can simply call secrets_encrypt()
again. In this case, however, we need to supply the private
key file because modifying requires us to read the existing secrets.
We see that the API_KEY
value has indeed been updated.
Finally, we can export all secrets from the lockbox file as environment variables. This is useful when running applications that rely on environment variables for configuration.
And we see that the secrets are indeed available in the environment.
For even more security, you can encrypt your private key file itself using a passphrase. This adds an extra layer of protection - even if someone gains access to your key file, they would need to know the passphrase to use it.
When you run this command, you’ll be prompted to enter a passphrase. Make sure you choose a strong, memorable passphrase as you’ll need it every time you use the encrypted key file.
Now you can use your password-protected key file with all the same functions. The lockbox package will automatically detect that it’s an encrypted key file and prompt you for the passphrase when needed.
Temporary File Handling
There are two cases where lockbox
creates temporary files with sensitive data:
private
key used in secrets_decrypt()
or file_decrypt()
is itself passphrase-encrypted.secrets_encrypt()
to modify an existing lockbox
file.In both cases, a file is written to disk at tempfile()
, and is automatically deleted using on.exit()
and unlink()
to ensure cleanup on function exit even if an error occurs.
While this approach follows R best practices for temporary file handling, users with heightened security requirements may prefer to run age
and sops
directly from the command line to maintain full control over key file handling.
For power users who need advanced secrets management features, lockbox
also supports SOPS (Secrets OPerationS), a mature secrets manager from Mozilla. SOPS provides additional features like:
To use SOPS features, install the SOPS command line tool:
When SOPS is installed, lockbox
will automatically detect it and use SOPS format for new lockbox files. You can also explicitly force SOPS mode:
# Force SOPS format (requires SOPS to be installed)
secrets_encrypt(
lockbox = "sops_lockbox.yaml",
secrets = list(API_KEY = "secret-value"),
public = key,
sops = TRUE
)
SOPS-managed files have a different format with additional metadata for key management, but the same secrets_decrypt()
and secrets_export()
functions work seamlessly with both formats.
If SOPS is not installed, lockbox
automatically falls back to its built-in format, ensuring that basic secrets management works out of the box without external dependencies.