Crate memsecurity

Source
Expand description

§MEMSECURITY

Rust crates.ioDocs

Securely hold secrets in memory and protect them against cross-protection-boundary readout via microarchitectural, via attacks on physical layout, and via coldboot attacks. mlock is also used to prevent the operating system from swapping these secrets to RAM which offers some level of protection aganist cold boot attacks.

This algorithm was invented by OpenSSH. The given type of encryption secures sensitive data, such as secret keys, by encrypting them in memory while they are not in use and decrypting them on demand. This method provides protection against various types of attacks, including cross-protection-boundary readout via microarchitectural flaws like Spectre or Meltdown, attacks on physical layout like Rowbleed, and coldboot attacks. The key insight is that these attacks are imperfect, meaning that the recovered data contains bitflips or the attack only provides a probability for any given bit. When applied to cryptographic keys, these kinds of imperfect attacks are enough to recover the actual key.

However, this implementation derives a sealing key from a large area of memory called the “pre-key” using a key derivation function. Any single bitflip in the readout of the pre-key will avalanche through all the bits in the sealing key, rendering it unusable with no indication of where the error occurred.

This crate has not received an audit. Use at your own risk!!!

§Features
  • symm_asymm - feature enables data types that can be used to securely zero out memory when they are dropped. They implement Zeroize trait from zeroize crate.
  • clonable_mem - Allows the cloning of data types enabled by the symm_asymm features.
  • encryption - This enables encrypted memory with mlock and munlock and encrypts using Ascon128a cipher.
  • random - This enables cryptographically secure random number generator which use rand_core and rand_chacha.
§Usage Examples
  1. §Generating random bytes
    Using the random byte generator (it is cryptographically secure based on the randomness provided by the OS you are using). The random feature must be enabled.
    use memsecurity::CsprngArray;
    
    // Generate a 32 byte array of random bytes
    let random_bytes = CsprngArray::<32>::gen();
    
    // Assert that the random bytes are not zeroes
    assert_ne!(random_bytes.expose_borrowed(), &[0u8; 32]);
    
    // Use a simplified version of the random bytes generator.
    use memsecurity::CsprngArraySimple;
    
    // Generate one random byte
    let random8_byte = CsprngArraySimple::gen_u8_byte();
    
    // Generate 8 random bytes
    let random8 = CsprngArraySimple::gen_u8_array();
    assert_eq!(random8.expose_borrowed().len(), 8);
    
    // Generate 16 random bytes
    let random16 = CsprngArraySimple::gen_u16_array();
    assert_eq!(random16.expose_borrowed().len(), 16);
    
    // Generate 24 random bytes
    let random24 = CsprngArraySimple::gen_u24_array();
    assert_eq!(random24.expose_borrowed().len(), 24);
    
    // Generate 32 random bytes
    let random32 = CsprngArraySimple::gen_u32_array();
    assert_eq!(random32.expose_borrowed().len(), 32);
    
    // Generate 64 random bytes
    let random64 = CsprngArraySimple::gen_u64_array();
    assert_eq!(random64.expose_borrowed().len(), 64);
  2. §Using the data types that are zeroed when dropped
    Sometimes sensitive data needs to be zeroed when it is dropped. This can be to protect secrets like encryption keys or passwords by ensuring they are not kept in memory when they are no longer needed. The symm_asymm feature must be enabled. The clonable_mem feature can be enabled if they you need to clone these secrets (Use these with care). Most of these have the .expose_borrowed() method which exposes the inner value if you want to use that value.
    use memsecurity::{ZeroizeArray, ZeroizeBytes};
    
    // Create an array of 4 bytes that will be zeroed out when dropped.
    let array_like = ZeroizeArray::<4>::new([4u8, 3,2,1]);
    
    // Use the value
    array_like.expose_borrowed();
    
    // Create a Vec like array using `BytesMut` from `bytes` crate that re-allocates when it's capacity is exceeded.
    let mut vector_like = ZeroizeBytes::new();
    
    // Insert a slice of bytes
    vector_like.set(&[4u8, 5,6,7]); // Must be a byte (u8) type
    
    // Use the value
    vector_like.expose_borrowed();
  3. §Encrypt a secret while in memory using Ascon128a encryption
    Whenever you want to encrypt secrets like passwords or encryption keys in memory, enable the encryption feature to use the EncryptedMem type. mlock and munlock are also implemented in this data. The encryption key is generated afresh on each app run
    use memsecurity::{EncryptedMem, CsprngArray};
    
    // Initialize the struct with a random nonce (Nonce for Ascon128a)
    let mut foo = EncryptedMem::new();
    
    // Here a some random bytes are generated to simulate
    // some secret you want to protect.
    // Here the value must implement `Zeroize` trait
    // and `impl From<AsRef<[u8]>>` trait so be accepted
    // by the `encrypt()` and `decrypt()` methods of `EncryptedMem`.
    let plaintext_bytes = CsprngArray::<32>::gen();
    
    // Encrypt the secret in memory using the randomly
    // generated encryption key that is `mlocked`
    foo.encrypt(&plaintext_bytes).unwrap();
    
    // Decrypt the secret using the `mlocked` key
    let decrypted = foo.decrypt().unwrap();
    
    assert_eq!(
        plaintext_bytes.expose_borrowed(),
        decrypted.expose_borrowed()
    );
§LICENSE

This crate is licensed under Apache license and all contributions and redistributions must bear the same license.

§Code of Conduct

All conversations and contributions must obey the Rust Code of Conduct https://www.rust-lang.org/policies/code-of-conduct

Re-exports§

pub use arrayvec;
pub use ascon_aead;
pub use blake3;
pub use bytes;
pub use memsec;
pub use once_cell;
pub use rand_chacha;
pub use rand_core;
pub use borsh;
pub use zeroize;

Structs§

CsprngArray
Generate Cryptographically secure random bytes of different sizes based on generic usize N
CsprngArraySimple
Generate Cryptographically secure random bytes of array size 8, 16, 24, 32 or 64
EncryptedMem
A struct that holds the encrypted secret and performs encryption and decryption on the secret.
SealingKey
The struct used to hold the sealing key used for encrypt data while it’s loaded in memory.
ZeroizeArray
This is a array whose size is specified as a const generic N and can be zeroed out when dropped from memory. This array is useful when specifying fixed size bytes like passwords which need to be zeroed out from memory before being dropped.
ZeroizeArrayVec
This is an ArrayVec whose size is specified as a const generic N and can be zeroed out when dropped from memory. This array is useful when specifying fixed size bytes like passwords which need to be zeroed out from memory before being dropped.
ZeroizeArrayVecBytes
This is an ArrayVec of bytes whose size is specified as a const generic N and can be zeroed out when dropped from memory. This array is useful when specifying fixed size bytes like passwords which need to be zeroed out from memory before being dropped.
ZeroizeByte
This a byte that is zeroed out when dropped from memory.
ZeroizeBytes
Similar to ZeroizeBytesArray but this does not have a fixed size length. This is more similar to using a Vec than an array
ZeroizeBytesArray
This is an array of variable length bytes that can be zeroed out on drop.

Enums§

MemSecurityErr
Errors encountered in execution of the code in this crate

Constants§

ASCON128_NONCE_LEN
The nonce length of Ascon 128 cipher
DEFAULT_VAULT_PAGES
The number of pages used to accommodate one page of 4KiB in size.
DEFAULT_VAULT_PAGE_SIZE
A size in KiB of one page (a page is a fixed-size block of memory used by the operating system to manage memory)
SECRET_KEY_16BYTE
The length of a 16 byte secret key
SECRET_KEY_32BYTE
The length of a 32 byte secret key

Traits§

MinMaxNum
Define maximum number a generic T can hold. This is implemented for all integer and float primitive types
ToBlake3Hash
This trait ensures that a type can be converted into a Blake3 Hash. This can be useful especially for equality checks since blake3::Hash already implements constant time equality checks

Type Aliases§

Blake3Hash
The 32 bytes of a Blake3 Hash
Ed25519KeyPair
The 64 bytes of an ed25519 keypair
Ed25519PublicKey
The 32 bytes of an ed25519 keypair
Ed25519SecretKey
The 32 bytes of an ed25519 secret
Key32Byte
The 32 bytes secret key
MemSecurityResult
Wraps core::result::Result with the MemSecurityErr as the Err() value
Poly1305Tag
The 16 bytes of a Poly1305 AEAD tag
TaiTimestamp
The bytes of a Tai64N timestamp
VaultPagesLayout
The layout of the bytes used to create the key
X25519EphemeralSecretKey
The 32 bytes of an X25519 ephemeral secret key
X25519PublicKey
The 32 bytes of an X25519 public key
X25519ReusableSecretKey
The 32 bytes of an X25519 reusable secret key
X25519SharedSecretKey
The 32 bytes of an X25519 shared secret key from the outcome of a DH key exchange
X25519StaticKeyPair
The 64 bytes of an X25519 keypair
X25519StaticSecretKey
The 32 bytes of an X25519 static secret key