Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Self encrypting files (convergent encryption plus obfuscation)
Crate | Documentation |
---|---|
MaidSafe website | SAFE Dev Forum | SAFE Network Forum |
---|
A version of convergent encryption with an additional obfuscation step. This pattern allows secured data that can also be de-duplicated. This library presents an API that takes a set of bytes and returns a secret key derived from those bytes, and a set of encrypted chunks.
Important Security Note: While this library provides very secure encryption of the data, the returned secret key requires the same secure handling as would be necessary for any secret key.
Add this to your Cargo.toml
:
[dependencies]
self_encryption = "0.30"
bytes = "1.0"
use self_encryption::{encrypt, decrypt_full_set};
use bytes::Bytes;
// Basic encryption/decryption
fn basic_example() -> Result<()> {
let data = Bytes::from("Hello, World!".repeat(1000)); // Must be at least 3072 bytes
// Encrypt data
let (data_map, encrypted_chunks) = encrypt(data.clone())?;
// Decrypt data
let decrypted = decrypt_full_set(&data_map, &encrypted_chunks)?;
assert_eq!(data, decrypted);
Ok(())
}
use self_encryption::{shrink_data_map, get_root_data_map, decrypt_from_storage};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
// Memory Storage Example
fn memory_storage_example() -> Result<()> {
let storage = Arc::new(Mutex::new(HashMap::new()));
// Store function
let store = |hash, data| {
storage.lock().unwrap().insert(hash, data);
Ok(())
};
// Retrieve function
let retrieve = |hash| {
storage.lock().unwrap()
.get(&hash)
.cloned()
.ok_or_else(|| Error::Generic("Chunk not found".into()))
};
// Use with data map operations
let shrunk_map = shrink_data_map(data_map, store)?;
let root_map = get_root_data_map(shrunk_map, retrieve)?;
Ok(())
}
// Disk Storage Example
fn disk_storage_example() -> Result<()> {
let chunk_dir = PathBuf::from("chunks");
// Store function
let store = |hash, data| {
let path = chunk_dir.join(hex::encode(hash));
std::fs::write(path, data)?;
Ok(())
};
// Retrieve function
let retrieve = |hash| {
let path = chunk_dir.join(hex::encode(hash));
Ok(Bytes::from(std::fs::read(path)?))
};
// Use with data map operations
let shrunk_map = shrink_data_map(data_map, store)?;
let root_map = get_root_data_map(shrunk_map, retrieve)?;
Ok(())
}
pip install self-encryption
from self_encryption import encrypt, decrypt
# Basic in-memory encryption/decryption
def basic_example():
# Create test data (must be at least 3072 bytes)
data = b"Hello, World!" * 1000
# Encrypt data - returns data map and encrypted chunks
data_map, chunks = encrypt(data)
print(f"Data encrypted into {len(chunks)} chunks")
print(f"Data map has child level: {data_map.child()}")
# Decrypt data
decrypted = decrypt(data_map, chunks)
assert data == decrypted
from pathlib import Path
from self_encryption import encrypt_from_file, decrypt_from_storage, streaming_encrypt_from_file
def file_example():
# Setup paths
input_path = Path("large_file.dat")
chunk_dir = Path("chunks")
output_path = Path("decrypted_file.dat")
# Ensure chunk directory exists
chunk_dir.mkdir(exist_ok=True)
# Regular file encryption - stores all chunks at once
data_map, chunk_names = encrypt_from_file(str(input_path), str(chunk_dir))
print(f"File encrypted into {len(chunk_names)} chunks")
# Streaming encryption - memory efficient for large files
def store_chunk(name_hex: str, content: bytes) -> None:
chunk_path = chunk_dir / name_hex
chunk_path.write_bytes(content)
data_map = streaming_encrypt_from_file(str(input_path), store_chunk)
print(f"File encrypted with streaming method")
# Create chunk retrieval function
def get_chunk(hash_hex: str) -> bytes:
chunk_path = chunk_dir / hash_hex
return chunk_path.read_bytes()
# Decrypt file
decrypt_from_storage(data_map, str(output_path), get_chunk)
from self_encryption import shrink_data_map, get_root_data_map
def advanced_example():
# Create custom storage backend
chunk_store = {}
def store_chunk(name_hex: str, content: bytes) -> None:
chunk_store[name_hex] = content
def get_chunk(name_hex: str) -> bytes:
return chunk_store[name_hex]
# Use streaming encryption with custom storage
data_map = streaming_encrypt_from_file("large_file.dat", store_chunk)
# Get root data map for hierarchical storage
root_map = get_root_data_map(data_map, get_chunk)
print(f"Root data map level: {root_map.child()}")
Each chunk's encryption uses keys derived from the content hashes of three chunks:
For chunk N:
- Uses hashes from chunks [N, N+1, N+2]
- Combined hash = hash(N) || hash(N+1) || hash(N+2)
- Split into:
- Pad (first X bytes)
- Key (next 16 bytes for AES-256)
- IV (final 16 bytes)
This creates a chain of dependencies where each chunk's encryption depends on its neighbors
Provides both convergent encryption and additional security through the interdependencies
Content Chunking:
Per-Chunk Processing:
// For each chunk:
1. Compress data using Brotli
2. Generate key materials:
- Combine three consecutive chunk hashes
- Extract pad, key, and IV
3. Encrypt compressed data using AES-256-CBC
4. XOR encrypted data with pad for obfuscation
DataMap Creation:
Chunk Retrieval:
Per-Chunk Processing:
// For each chunk:
1. Regenerate key materials using src_hashes from DataMap
2. Remove XOR obfuscation using pad
3. Decrypt using AES-256-CBC with key and IV
4. Decompress using Brotli
Chunk Reassembly:
Flexible backend support through trait-based design
Supports both memory and disk-based storage
Streaming operations for memory efficiency
Hierarchical data maps for large files:
// DataMap shrinking for large files
1. Serialize large DataMap
2. Encrypt serialized map using same process
3. Create new DataMap with fewer chunks
4. Repeat until manageable size reached
This implementation provides a balance of:
Licensed under the General Public License (GPL), version 3 (LICENSE http://www.gnu.org/licenses/gpl-3.0.en.html).
self_encryption is licensed under GPLv3 with linking exception. This means you can link to and use the library from any program, proprietary or open source; paid or gratis. However, if you modify self_encryption, you must distribute the source to your modified version under the terms of the GPLv3.
See the LICENSE file for more details.
Want to contribute? Great :tada:
There are many ways to give back to the project, whether it be writing new code, fixing bugs, or just reporting errors. All forms of contributions are encouraged!
For instructions on how to contribute, see our Guide to contributing.
FAQs
Self encrypting files (convergent encryption plus obfuscation)
We found that self-encryption demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.