Ubiq Security Rust Library
The Ubiq Security Rust library provides convenient interaction with the Ubiq Security Platform API from applications written in the Rust language. It includes a pre-defined set of types and builders that provide simple interfaces to encrypt and decrypt data.
Documentation
See the Ubiq API docs.
You can improve it by sending pull requests to this repository.
Requirements
- Rust 1.85 or later
- An async runtime — this library exposes
asyncAPIs. tokio is recommended but any runtime should work. - OpenSSL development libraries installed on your system (e.g.
libssl-devon Debian/Ubuntu,opensslvia Homebrew on macOS)
Installation
Add the dependency to your Cargo.toml:
[]
= "1.0.0"
Or use cargo add:
Ubiq Unstructured Encryption
The library needs to be configured with your account credentials which is
available in your Ubiq Dashboard credentials. The credentials can be
set using environment variables, loaded from an explicit file, or read from the
default location (~/.ubiq/credentials).
Read credentials from a specific file and use a specific profile
use ;
let enc = new
.with_cred_path
.with_profile
.build_encryption
.await?;
Configuration information can also be passed when building. See Configuration below.
Read credentials from ~/.ubiq/credentials and use the default profile
use ;
let enc = new
.build_encryption
.await?;
Use environment variables to set the credential values
The following environment variables are supported:
UBIQ_ACCESS_KEY_ID
UBIQ_SECRET_SIGNING_KEY
UBIQ_SECRET_CRYPTO_ACCESS_KEY
UBIQ_SERVER (optional, defaults to api.ubiqsecurity.com)
When no credentials file is found or a key is absent from the file, the library falls back to these environment variables automatically. No special builder call is required — simply ensure the variables are set and use the default builder:
use ;
let enc = new
.build_encryption
.await?;
Handling exceptions
All fallible operations return a Result<T, ubiq_rust::error::Error>. Use standard
Rust error handling to inspect and recover from failures.
use ;
match new.build_encryption.await
Encrypt a simple block of data
Pass data into the encrypt method on an Encryption object. The encrypted
data will be returned as a Vec<u8>. The plaintext input must be a &[u8]
slice.
use ;
let plaintext_data: & = b"plaintext data";
let mut enc = new
.build_encryption
.await?;
let encrypted_data: = enc.encrypt?;
Decrypt a simple block of data
Pass encrypted data into the decrypt method on a Decryption object. The
plaintext data will be returned as a Vec<u8>.
use ;
let mut dec = new
.build_decryption?;
// encrypted_data obtained from a previous encrypt call
let plaintext_data: = dec.decrypt.await?;
Encrypt a large data element where data is loaded in chunks
- Build an
Encryptionobject using the builder. - Call
beginto initialize the encryption and receive any header bytes. - Call
updaterepeatedly with each chunk of data until all data is processed. - Call
endto retrieve any remaining encrypted bytes and finalize.
use ;
// Process 1 MiB of plaintext data at a time
const BLOCK_SIZE: usize = 1024 * 1024;
// Rest of the program
// ....
let mut enc = new
.build_encryption
.await?;
// Write out the header information
let mut encrypted_data = enc.begin?;
// Loop until the end of the input is reached
for chunk in plaintext_data.chunks
// Retrieve any remaining encrypted data and finalize
encrypted_data.extend;
Decrypt a large data element where data is loaded in chunks
- Build a
Decryptionobject using the builder. - Call
beginto initialize the decryption and receive any header bytes. - Call
updaterepeatedly with each chunk of data until all data is processed. - Call
endto retrieve any remaining plaintext bytes and finalize.
use ;
// Process 1 MiB of encrypted data at a time
const BLOCK_SIZE: usize = 1024 * 1024;
// Rest of the program
// ....
let mut dec = new
.build_decryption?;
// Initialize the decryption state
let mut plaintext_data = dec.begin?;
// Loop until the end of the input is reached
// encrypted_data obtained from a previous encrypt call
for chunk in encrypted_data.chunks
// Retrieve any remaining plaintext data and finalize
plaintext_data.extend;
Encrypt and Decrypt with Reuse
To reuse encryption/decryption objects, build them once and call begin /
update / end in a loop. Encryption takes an extra parameter via
with_uses, specifying the number of separate encryptions to perform with
the same key. This number may be limited by the server. If with_uses is
not called, the default is 1 (a single use per key fetch).
use ;
let raw_data = ;
let mut enc = new
.with_uses
.build_encryption
.await?;
let mut dec = new
.build_decryption?;
let mut encrypted_data: = Vecnew;
for animal in &raw_data
for data in &encrypted_data
Ubiq Structured Encryption
This library incorporates Ubiq Structured Encryption.
Requirements
- Please follow the same requirements as described above for unstructured encryption/decryption.
Usage
You will need to obtain account credentials in the same way as described above
for conventional encryption/decryption. When you do this in your
Ubiq Dashboard credentials, you'll need to enable
access to structured datasets. The credentials can be set using environment
variables, loaded from an explicitly specified file, or read from the default
location (~/.ubiq/credentials).
Caching
When performing encryption/decryption, keys are retrieved from the Ubiq API.
To speed up performance and reduce the number of calls to the API, keys are
stored in a cache inside the structured::Encryption object. It is recommended
to reuse the object for multiple operations rather than rebuilding it each time.
Encrypt a social security text field — simple interface
Pass the dataset name and plaintext into the encrypt method. The encrypted
text will be returned as a String. A single Encryption object handles both
encrypt and decrypt operations.
use ;
let dataset_name = "SSN";
let plain_text = "123-45-6789";
let mut enc = new
.with_cred_path
.build?;
let ciphertext = enc.encrypt.await?;
println!;
Decrypt a social security text field — simple interface
Pass the dataset name and ciphertext into the decrypt method on the same
Encryption object. The decrypted text will be returned as a String.
use ;
let dataset_name = "SSN";
let cipher_text = "300-0E-274t";
let mut enc = new
.with_cred_path
.build?;
let plaintext = enc.decrypt.await?;
println!;
Additional information on how to use these models in your own applications is available by contacting Ubiq.
Configuration
A sample configuration file is shown below. The configuration is in JSON format
(example). Configuration can be set either as a
file read from a path, or as a pre-built Configuration object.
Reading from File
By default, configuration is read from ~/.ubiq/configuration. To use a
different file, pass its path to the builder with with_config_path:
use ;
let enc = new
.with_cred_path
.with_config_path
.build_encryption
.await?;
Pre-built Configuration Object
You can construct a Configuration value directly and supply it to the builder
with with_config. This is useful when you want to set configuration
programmatically rather than loading from a file:
use ;
use Configuration;
let mut config = default;
config.logging.verbose = true;
let enc = new
.with_config
.build_encryption
.await?;
Note: You cannot supply both with_config_path and with_config at the
same time; doing so will return a BuilderError at build time.
Disallowing Default Configuration
By default, if no configuration file is found at the default file location the library falls back to a
built-in Configuration::default(). To require that a configuration file be
present and return an error when it cannot be loaded, call
disallow_default_config:
use ;
let enc = new
.disallow_default_config
.build_encryption
.await?;
Event Reporting
The event_reporting section controls how often usage is reported to the
server.
wake_interval— number of seconds to sleep before waking to check whether there has been enough activity to report usageminimum_count— minimum number of usage records that must be queued before sendingflush_interval— seconds to sleep before all queued usage is flushed to the servertrap_exceptions— whether exceptions encountered while reporting usage are silently ignored (true) or propagated as errors (false)timestamp_granularity— how granular the timestamp will be when reporting events. Valid values are:"MICROS"— DEFAULT: values reported down to microsecond resolution"MILLIS"— values reported to the millisecond"SECONDS"— values reported to the second"MINUTES"— values reported to the minute"HOURS"— values reported to the hour"HALF_DAYS"— values reported to half day"DAYS"— values reported to the day
Key Caching
The key_caching section controls how and when keys are cached.
unstructured— whether keys are cached for unstructured decryption (default:true)structured— whether keys are cached for structured encryption/decryption (default:true)encrypt— whether cached keys are stored encrypted. Encrypted keys are harder to read from memory but require decryption on each use (default:false)ttl_seconds— how many seconds before a cache entry expires and the key is re-fetched (default:1800)
Logging
The logging section controls logging output.
verbose— enables or disables verbose logging such as event processing and caching activity
Example Configuration JSON
Zeroization
This library takes care to scrub sensitive cryptographic material from memory when it is no longer needed, reducing the risk of secrets leaking through memory dumps, core files, or swap.
How it works
- The
zeroizecrate and itsZeroizeOnDropderive macro are used throughout the library. - Credentials — API key/secret fields are zeroized when the
Credentialsstruct is dropped. - Unstructured encryption/decryption — key material, plaintext buffers, and cached private keys are zeroized on drop.
- Structured encryption —
KeyResolverand pipelineOpContextzeroize their key caches and plaintext values on drop. - Transient key material — decrypted key bytes are wrapped in
Zeroizing<Vec<u8>>so they are scrubbed as soon as the wrapper is dropped. - Cache — a custom
Zeroizeimplementation on the genericCache<T>type ensures all cached secrets are scrubbed when the cache is cleared or dropped. - AES/CBC ciphers — built with zeroize-enabled feature flags so internal cipher state is also cleared.
What this means for you
No action is required — zeroization is fully automatic. Sensitive material is
scrubbed when encryption and decryption objects go out of scope. To get the full
benefit, simply let these objects drop naturally and avoid using std::mem::forget,
which prevents destructors (and therefore zeroization) from running.
Ubiq API Error Reference
Occasionally, you may encounter issues when interacting with the Ubiq API.
| Status Code | Meaning | Solution |
|---|---|---|
| 400 | Bad Request | Check name of datasets and credentials are complete. |
| 401 | Authentication issue | Check you have the correct API keys, and it has access to the datasets you are using. Check dataset name. |
| 426 | Upgrade Required | You are using an out-of-date version of the library, or are trying to use newer features not supported by the library you are using. Update the library and try again. |
| 429 | Rate Limited | You are performing operations too quickly. Either slow down, or contact support@ubiqsecurity.com to increase your limits. |
| 500 | Internal Server Error | Something went wrong. Contact support if this persists. |
| 504 | Internal Error | Possible API key issue. Check credentials or contact support. |
Benchmarks
Currently benchmarks are contained in a single file, meant to be ran via CLI parameters - benches/load_test.rs. This file is meant to be fed a json file containing example data. Currently, these files are contained in the ubiq-test-data submodule. Credentials will be needed to run this as they are live dataset examples.
Example:
cargo bench --bench load_test -- -i ubiq-test-data/prod/1m-part-001.json -P "Max Benchmarks"