Expand description
§Configuration
First, you’ll need to create a configuration type by implementing the Config
trait.
If your configuration type implements the Default
trait, you can use the shorthand methods
of the EncryptedMessage
struct.
The first key provided is considered the primary key, & is always used to encrypt new payloads. The following keys are used in the order provided when the primary key can’t decrypt a payload. This allows you to rotate keys.
use encrypted_message::{
config::{Config, Secret, ExposeSecret as _},
strategy::Randomized,
};
#[derive(Debug, Default)]
struct EncryptionConfig;
impl Config for EncryptionConfig {
type Strategy = Randomized;
fn keys(&self) -> Vec<Secret<[u8; 32]>> {
std::env::var("ENCRYPTION_KEYS").unwrap()
.split(", ")
.map(|hex_key| {
let hex_key = Secret::new(hex_key.to_string());
let mut key = [0; 32];
hex::decode_to_slice(hex_key.expose_secret(), &mut key).unwrap();
key.into()
})
.collect()
}
}
You can generate secure 32-byte keys using the openssl
command-line tool:
openssl rand -hex 32
§Encryption strategies
Two encryption strategies are provided, Deterministic
& Randomized
.
Deterministic
encryption will always produce the same encrypted message for the same payload, allowing you to query encrypted data.Randomized
encryption will always produce a different encrypted message for the same payload. More secure thanDeterministic
, but impossible to query without decrypting all data.
It’s recommended to use different keys for each encryption strategy.
§Defining encrypted fields
You can now define your encrypted fields using the EncryptedMessage
struct.
The first type parameter is the payload type, & the second is the configuration type.
use encrypted_message::EncryptedMessage;
struct User {
diary: EncryptedMessage<String, EncryptionConfig>,
}
§Encrypting & decrypting payloads
If your Config
implements the Default
trait (like above), you can use the shorthand methods:
// Encrypt a user's diary.
let user = User {
diary: EncryptedMessage::encrypt("Very personal stuff".to_string()).unwrap(),
};
// Decrypt the user's diary.
let decrypted: String = user.diary.decrypt().unwrap();
If your Config
depends on external data:
use encrypted_message::{
EncryptedMessage,
config::{Config, Secret, ExposeSecret as _},
strategy::Randomized,
};
use pbkdf2::pbkdf2_hmac_array;
use sha2::Sha256;
#[derive(Debug)]
struct UserEncryptionConfig {
user_password: Secret<String>,
salt: Secret<String>,
}
impl Config for UserEncryptionConfig {
type Strategy = Randomized;
fn keys(&self) -> Vec<Secret<[u8; 32]>> {
let raw_key = self.user_password.expose_secret().as_bytes();
let salt = self.salt.expose_secret().as_bytes();
vec![pbkdf2_hmac_array::<Sha256, 32>(raw_key, salt, 2_u32.pow(16)).into()]
}
}
struct User {
diary: EncryptedMessage<String, UserEncryptionConfig>,
}
// Define the user's encryption configuration.
let config = UserEncryptionConfig {
user_password: "human-password-that-should-be-derived".to_string().into(),
salt: "unique-salt".to_string().into(),
};
// Encrypt a user's diary.
let user = User {
diary: EncryptedMessage::encrypt_with_config("Very personal stuff".to_string(), &config).unwrap(),
};
// Decrypt the user's diary.
let decrypted: String = user.diary.decrypt_with_config(&config).unwrap();
Re-exports§
pub use error::EncryptionError;
pub use error::DecryptionError;
Modules§
- config
- Contains the
Config
trait used to define the configuration for anEncryptedMessage
. - error
- Error types for the encryption & decryption operations.
- strategy
- All the encryption strategies that can be used with
EncryptedMessage
.
Structs§
- Encrypted
Message - Used to safely handle & transport encrypted data within your application. It contains an encrypted payload, along with a nonce & tag that are used in the encryption & decryption processes.