You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This RFC is part of the refactoring of the runtime in Stronghold.
The goal is to simplify and improve the security of the memory usage.
We allow Stronghold to store memory in 3 different ways: in the RAM, in the disk or in a non contiguous data structure (RAM and disk).
These 3 types of memory are then gathered under a common trait BoxedMemory to abstract away the implementation details.
Motivation
In the current Stronghold only RAM memory is used to store secrets and keys.
While this is partially protected with libsodium this is still not enough in our opinion.
An idea to make sensitive data harder to discover is to vary places where they can found.
Following this idea we propose to store some data in disk memory or to split data into shards using non contiguous data structure.
Guide-level explanation
Types of memory
There are 3 possible ways to store data:
RamMemory
This is RAM memory enhanced with security measures.
It's inspired from the current GuardedVec but with additional security inspired from MemGuard.
Security measures used:
Guards
Canary
Systems flags to prevent memory dumps
Access control of the memory pages
Zeroing out the memory when used
(Potentially) constant time copying/comparison against timing attacks
FileMemory
Disk memory is usually easier to access for an attacker.
However we believe that diversifying the storage locations between disk and RAM gives better security.
Security measures used:
Data hidden among garbage data
File permissions
Zeroed out before removed it
NonContiguousMemory
Non contiguous memory split data and store into multiple pieces and only reconstruct the original value when it is required.
Here the different memory pieces used to store the data are RamMemory and FileMemory.
Hence the memory pieces benefit from the security of these two structures.
Security measures used:
Memory pieces have security of RamMemory and FileMemory
Possibility to refresh the pieces using Boojum scheme
Splitting and reconstructing the pieces are done using a XOR operation.
Trait BoxedMemory
To generalize the behavior of the three memory constructs presented above we force them to implement the trait BoxedMemory.
We abstract away the implementation details by presenting this memory as a box.
Data is securely stored as if it was in a "box".
If you want to access it you have to "unlock" it then you can work with the data.
When you are done using it you have to "lock" the data securely in the box.
Therefore the trait only possesses 4 functions:
alloc: creates and configure a boxed memory with data locked into it
lock: takes data, secures it, and stores into an existing BoxedMemory
unlock: retrieve/reconstruct the data locked in a BoxedMemory
dealloc: zeroes out all traces of the data in the box and clears the box
Important: there is a short window where the data is not secured, when unlocked from the BoxedMemory. To maximize security the data will be stored in a BufferMemory which is essentially RamMemory which does not requires to be unlocked to be used.
These BufferMemory stores data in clear so it has to be as short lived as possible
When to use which memory?
The current proposal of Stronghold has 3 types of sensitive data to store: records (user data), vault keys and a master key.
We explain how they will be stored in with this RFC:
Records: user data is stored as encrypted data in memory
Vault keys: used for encryption of records and stored encrypted in memory
1 master key: used for encryption of vault keys and stored in non-contiguous data structure (both disk and memory). Shards of the masker key are regularly refreshed using process described in RFC-0008
Note: those choices are temporary and final decision will be taken after running tests to find the best balance between security and performance
Reference-level explanation
// Different possible configuration for the memory // This is still in developmentpubenumMemoryConfiguration{Buffer,// short-lived ram memoryEncryptedRam,// Encrypted ram memoryEncryptedFile,// Encrypted file memoryNonContiguousInRamAndFile(usize)// Non contiguous memory in ram and disk argument is number of pieces}/// GuardedMemory is used when we want to store sensitive non encrypted data/// This shall always be short livedpubstructRamMemory<T:Zeroize + AsRef<Vec<u8>>>{data:Boxed<T>,// the boxed type of current GuardedVecconfig:MemoryConfiguration}/// File memorypubstructFileMemory{fname:String,config:MemoryConfiguration}// NONCONTIGUOUS MEMORY/// Shards of memory which composes a non contiguous memoryenumMemoryShard<T:Zeroize + AsRef<Vec<u8>>>{File(FileMemory),Ram(GuardedMemory<T>)}pubstructNonContiguousMemory<T:Zeroize + AsRef<Vec<u8>>>{index:Vec<MemoryShard<T>>,config:MemoryConfiguration}// ########## SECURE MEMORY// Secure memory is a trait which job is to provide "Secure memory"pubtraitSecureMemory:Zeroize +
Sized{/// Writes the payload into a GuardedMem then locks itfnalloc<T>(payload:T,config:MemoryConfiguration,key:Option<Vec<u8>>)
-> Result<Self,MemoryError>whereT:Zeroize + AsRef<Vec<u8>>;/// Locks the memory and possibly reallocatesfnlock<T>(self,payload:GuardedMemory<T>,key:Option<Vec<u8>>)
-> Result<Self,MemoryError>whereT:Zeroize + AsRef<Vec<u8>>;/// Unlocks the memoryfnunlock<T>(&self,key:Option<Vec<u8>>)
-> Result<GuardedMemory<T>,MemoryError>whereT:Zeroize + AsRef<Vec<u8>>;/// Cleans up any trace of the memory used/// Shall be called in drop()fndealloc(&mutself) -> Result<(),MemoryError>{self.zeroize();Ok(())}}
Example
/// We want to insert a record into a vaultfnexample_calls(){let key_store = KeyStore::new(b"some_user_provided_key".to_vec());letmut database = Database::default();let vault_id = VaultId::random();// vault is inserted and present at vault_idletmut vault = database.get_vault(&vault_id);// insert a record into vaultletmut record_id = Record::random_id();// Get a key from the vaultlet encrypted_vault_key = key_store.get(&vault_id);let locked_master_key = key_store.master_key;// Unlock the master key in a GuardedMemorylet guarded_master_key = locked_master_key.unlock(None);// Unlock/decrypt the vault key with the master key in a GuardedMemorylet guarded_vault_key = encrypted_vault_key.unlock(Some(guarded_master_key));// Insert data into the vaultlet value = b"payload";let record = NonContiguousMemory::alloc(value,MemoryConfiguration{len: value.len(),encrypted:true,with_guards:true}, decrypted_vault_key);
vault.insert(record_id, record);// Lock the keys again after usage
guarded_vault_key.lock(Some(guarded_master_key));
guarded_master_key.lock(None);}
Drawbacks
Using disk memory and non-contiguous memory may be costly in terms of performance
Forcing the memory types to behaves following the BoxedMemory removes some flexibility when using them
Rationale and alternatives
We allow multiple types of memory to be used which improves security of Stronghold if used wisely
Utilization of these memory types is unified behind the BoxedMemory trait.
This gives more leeway in the future to improve/add the memory constructs we use without breaking the code
Unresolved questions
Do tests to find the best balance between security and performance when using BoxedMemory for records, vault keys and master key
Shall we keep the memory configuration field in the FileMemory and NonContiguousMemory since there is a single type of MemoryConfiguration for these structures right now
For the moment I'd like to keep them to have more flexibility in the future tests when looking for a security balance between security and performance
Future possibilities
Adding security measures against timing attacks such as constant time
Investigate how to add support for hardware secure modules
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
MemoryManagement
)Summary
This RFC is part of the refactoring of the runtime in Stronghold.
The goal is to simplify and improve the security of the memory usage.
We allow Stronghold to store memory in 3 different ways: in the RAM, in the disk or in a non contiguous data structure (RAM and disk).
These 3 types of memory are then gathered under a common trait
BoxedMemory
to abstract away the implementation details.Motivation
In the current Stronghold only RAM memory is used to store secrets and keys.
While this is partially protected with libsodium this is still not enough in our opinion.
An idea to make sensitive data harder to discover is to vary places where they can found.
Following this idea we propose to store some data in disk memory or to split data into shards using non contiguous data structure.
Guide-level explanation
Types of memory
There are 3 possible ways to store data:
RamMemory
This is RAM memory enhanced with security measures.
It's inspired from the current
GuardedVec
but with additional security inspired fromMemGuard.
Security measures used:
FileMemory
Disk memory is usually easier to access for an attacker.
However we believe that diversifying the storage locations between disk and RAM gives better security.
Security measures used:
NonContiguousMemory
Non contiguous memory split data and store into multiple pieces and only reconstruct the original value when it is required.
Here the different memory pieces used to store the data are
RamMemory
andFileMemory
.Hence the memory pieces benefit from the security of these two structures.
Security measures used:
RamMemory
andFileMemory
Splitting and reconstructing the pieces are done using a XOR operation.
Trait
BoxedMemory
To generalize the behavior of the three memory constructs presented above we force them to implement the trait
BoxedMemory
.We abstract away the implementation details by presenting this memory as a box.
Data is securely stored as if it was in a "box".
If you want to access it you have to "unlock" it then you can work with the data.
When you are done using it you have to "lock" the data securely in the box.
Therefore the trait only possesses 4 functions:
alloc
: creates and configure a boxed memory with data locked into itlock
: takes data, secures it, and stores into an existingBoxedMemory
unlock
: retrieve/reconstruct the data locked in aBoxedMemory
dealloc
: zeroes out all traces of the data in the box and clears the boxImportant: there is a short window where the data is not secured, when unlocked from the
BoxedMemory
. To maximize security the data will be stored in aBufferMemory
which is essentiallyRamMemory
which does not requires to be unlocked to be used.These
BufferMemory
stores data in clear so it has to be as short lived as possibleWhen to use which memory?
The current proposal of Stronghold has 3 types of sensitive data to store: records (user data), vault keys and a master key.
We explain how they will be stored in with this RFC:
Note: those choices are temporary and final decision will be taken after running tests to find the best balance between security and performance
Reference-level explanation
Example
Drawbacks
BoxedMemory
removes some flexibility when using themRationale and alternatives
BoxedMemory
trait.This gives more leeway in the future to improve/add the memory constructs we use without breaking the code
Unresolved questions
FileMemory
andNonContiguousMemory
since there is a single type ofMemoryConfiguration
for these structures right nowFuture possibilities
Beta Was this translation helpful? Give feedback.
All reactions