pub struct ConvergentEncryption;Expand description
Convergent encryption using AES-256-GCM with Blake3 key derivation and Brotli compression
This implementation provides convergent encryption where the encryption key is derived from the content itself using Blake3. This enables:
- Deterministic encryption: Same content always produces the same ciphertext
- Content-based deduplication: Identical files can be identified by their key
- No key management: No need to store or manage encryption keys separately
- Integrity verification: Can verify file integrity by re-deriving the key
- Optional compression: Brotli compression reduces storage requirements
§Security Model
- The 32-byte Blake3 hash serves as both the encryption key and nonce (first 12 bytes)
- AES-256-GCM provides authenticated encryption with integrity protection
- Compression is applied before encryption to maximize storage efficiency
- The same content will always produce the same ciphertext, enabling deduplication
§Limitations
- Identical content detection: Adversaries can determine when identical files are stored
- No forward secrecy: If the content is known, the encryption can be broken
This approach is ideal for scenarios where you control the content and want to benefit from deduplication and integrity verification.
Implementations§
Source§impl ConvergentEncryption
impl ConvergentEncryption
Sourcepub(crate) fn derive_key(content: &[u8]) -> ConvergentEncryptionKey
pub(crate) fn derive_key(content: &[u8]) -> ConvergentEncryptionKey
Derive encryption key from source content using Blake3
This function calculates a 32-byte encryption key from the content using Blake3. The same content will always produce the same key, enabling convergent encryption.
The derived key is used as both the encryption key and nonce for AES-256-GCM.
§Arguments
content- The source content to derive the key from
§Returns
A 32-byte encryption key derived from the content
Sourcepub(crate) fn compress(
content: &[u8],
config: &CompressionConfig,
) -> Result<(Vec<u8>, bool), ConvergentEncryptionError>
pub(crate) fn compress( content: &[u8], config: &CompressionConfig, ) -> Result<(Vec<u8>, bool), ConvergentEncryptionError>
Compress content using Brotli if beneficial
Attempts to compress the content using Brotli. Only applies compression if:
- Compression is enabled in the config
- Content size is above the minimum threshold
- Compressed size is smaller than the original
§Arguments
content- The content to potentially compressconfig- Compression configuration settings
§Returns
A tuple containing the data to encrypt (compressed or original) and a flag indicating whether compression was applied.
Sourcepub(crate) fn decompress(
content: &[u8],
) -> Result<Vec<u8>, ConvergentEncryptionError>
pub(crate) fn decompress( content: &[u8], ) -> Result<Vec<u8>, ConvergentEncryptionError>
Sourcepub fn encrypt_with_compression_config(
plaintext: &[u8],
config: CompressionConfig,
) -> Result<(Vec<u8>, ConvergentEncryptionInfo), ConvergentEncryptionError>
pub fn encrypt_with_compression_config( plaintext: &[u8], config: CompressionConfig, ) -> Result<(Vec<u8>, ConvergentEncryptionInfo), ConvergentEncryptionError>
Encrypt plaintext using convergent encryption with custom compression settings
This function performs the complete encryption process:
- Derives the encryption key from the content using Blake3
- Compresses the content if beneficial (based on config)
- Encrypts the data using AES-256-GCM with the derived key
- Returns both the ciphertext and metadata for decryption
The same plaintext will always produce the same ciphertext, enabling convergent encryption and deduplication.
§Arguments
plaintext- The content to encryptconfig- Compression configuration settings
§Returns
A tuple containing the encrypted ciphertext and metadata needed for decryption
§Example
use zoe_encrypted_storage::{ConvergentEncryption, CompressionConfig};
let content = b"Hello, world!";
// Encrypt with custom compression
let config = CompressionConfig {
enabled: true,
quality: 8,
min_size: 128,
};
let (encrypted, info) = ConvergentEncryption::encrypt_with_compression_config(content, config).unwrap();Sourcepub fn decrypt(
ciphertext: &[u8],
config: &ConvergentEncryptionInfo,
) -> Result<Vec<u8>, ConvergentEncryptionError>
pub fn decrypt( ciphertext: &[u8], config: &ConvergentEncryptionInfo, ) -> Result<Vec<u8>, ConvergentEncryptionError>
Decrypt ciphertext using the provided metadata with automatic decompression
This function performs the complete decryption process:
- Decrypts the ciphertext using AES-256-GCM
- Decompresses the data if it was compressed during encryption
- Returns the original plaintext
§Arguments
ciphertext- The encrypted data to decryptconfig- Metadata containing the key and compression information
§Returns
The original plaintext content
§Example
use zoe_encrypted_storage::ConvergentEncryption;
let content = b"Hello, world!";
let (encrypted, info) = ConvergentEncryption::encrypt(content).unwrap();
let decrypted = ConvergentEncryption::decrypt(&encrypted, &info).unwrap();
assert_eq!(content, decrypted.as_slice());Sourcepub fn encrypt(
content: &[u8],
) -> Result<(Vec<u8>, ConvergentEncryptionInfo), ConvergentEncryptionError>
pub fn encrypt( content: &[u8], ) -> Result<(Vec<u8>, ConvergentEncryptionInfo), ConvergentEncryptionError>
Convenience function: encrypt content with default compression settings
This function combines key derivation, compression, and encryption in one step using the default compression configuration. It’s the simplest way to encrypt content with convergent encryption.
§Arguments
content- The content to encrypt
§Returns
A tuple containing the encrypted ciphertext and metadata needed for decryption
§Example
use zoe_encrypted_storage::ConvergentEncryption;
let content = b"Hello, world!";
let (encrypted, info) = ConvergentEncryption::encrypt(content).unwrap();
let decrypted = ConvergentEncryption::decrypt(&encrypted, &info).unwrap();
assert_eq!(content, decrypted.as_slice());