Skip to content

Instantly share code, notes, and snippets.

@cptpiepmatz
Last active January 17, 2025 17:30
Show Gist options
  • Save cptpiepmatz/54d6a90cbaa3bb2386622d1375fd123f to your computer and use it in GitHub Desktop.
Save cptpiepmatz/54d6a90cbaa3bb2386622d1375fd123f to your computer and use it in GitHub Desktop.
encryt static toml data experiment

Secure Secrets Example

This example demonstrates how to securely handle sensitive (see Security Note) data, such as API keys and passwords, in a Rust application. The setup ensures that sensitive strings are not included in the binary in plaintext and uses encryption to protect secrets during the build process.

How It Works

  1. Encryption during Build: The build.rs script encrypts the secrets.toml file using a predefined key (key) and saves the result as secrets.toml.encrypted.
  2. Decryption at Runtime: The main program decrypts the secrets.toml.encrypted file at runtime, parses the TOML content, and verifies the data structure.
  3. Static Parsing: The static_toml crate provides compile-time validation of the TOML structure. In this experiment, since the same TOML file (though encrypted) is used to build the data structure, deserialization after decryption should not fail unless there is an unexpected issue.

Running the Example

  1. Place your secrets.toml and key files in the same directory as main.rs and build.rs.
  2. Build the project:
    cargo build --release
  3. Run the application:
    target/release/example
    You should see:
    Nice secrets you got there 😎
    

Verifying Secrets Are Not in the Binary

To confirm that sensitive strings are not embedded in the binary as plaintext, you can search for them:

strings target/release/example | rg your_api_key_here

This command should return no results, demonstrating that the original secret string is not stored in the binary.

Security Note

Disclaimer: I am not a security expert, and this experiment is limited in scope. It only checks that the original strings are not visible as plaintext in the binary. This approach does not ensure full security of sensitive data.

Keep in mind:

  • A key is still required for encryption and decryption. Managing this securely is crucial.
  • Even with obfuscation, a shipped binary can be thoroughly inspected and reverse-engineered.
  • It is better to avoid shipping secrets in the binary altogether instead of relying solely on obfuscation.

If you need robust security, consider using secure key management solutions or dedicated libraries designed for handling sensitive data in production environments.

/target
/secrets.toml.encrypted
/Cargo.lock
use std::fs;
use simple_crypt::encrypt;
const SECRETS: &[u8] = include_bytes!("./secrets.toml");
const KEY: &[u8] = include_bytes!("./key");
fn main() {
let encrypted = encrypt(SECRETS, KEY).unwrap();
fs::write("./secrets.toml.encrypted", encrypted).unwrap();
}
[package]
name = "encrypt-static-toml-experiment"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "example"
path = "./main.rs"
[dependencies]
serde = { version = "1.0.217", features = ["derive"] }
simple_crypt = "0.2.3"
static-toml = "1.3.0"
toml = "0.8.19"
[build-dependencies]
simple_crypt = "0.2.3"
an example very very secret key!
use simple_crypt::decrypt;
use static_toml::static_toml;
static_toml! {
#[derive(serde::Deserialize)]
#[static_toml(cow)]
const _SECRETS = include_toml!("secrets.toml");
}
const KEY: &[u8] = include_bytes!("./key");
const SECRETS: &[u8] = include_bytes!("./secrets.toml.encrypted");
fn main() {
let decrypted = decrypt(SECRETS, KEY).unwrap();
let secrets = String::from_utf8(decrypted).unwrap();
let secrets: secrets::Secrets = toml::from_str(&secrets).unwrap();
assert_eq!(secrets.database.password, "super_secret_password");
assert_eq!(secrets.api.secret, "your_api_secret_here");
assert_eq!(secrets.aws.secret_access_key, "your_aws_secret_access_key");
println!("Nice secrets you got there 😎");
}
[database]
host = "localhost"
port = 5432
username = "db_user"
password = "super_secret_password"
[api]
key = "your_api_key_here"
secret = "your_api_secret_here"
[aws]
access_key_id = "your_aws_access_key_id"
secret_access_key = "your_aws_secret_access_key"
region = "us-west-2"
[encryption]
private_key = """
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD...
...rest_of_private_key...
-----END PRIVATE KEY-----
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment