#内存保护 #加密密钥 #攻击 #安全 #数据 #字节 #内存中

memsecurity

在内存中安全地存储秘密,并通过微架构、物理布局攻击和冷启动攻击防止跨保护边界读取

24 个稳定版本 (3 个主要版本)

3.5.2 2024年1月5日
3.5.1 2023年12月15日
3.4.0 2023年10月9日
2.2.1 2023年8月9日
0.2.0-alpha12023年5月19日

#278 in 加密学

Download history 9/week @ 2024-05-18 7/week @ 2024-05-25 111/week @ 2024-06-01 77/week @ 2024-06-08 99/week @ 2024-06-15 98/week @ 2024-06-22 91/week @ 2024-06-29 193/week @ 2024-07-06 165/week @ 2024-07-13 69/week @ 2024-07-20 253/week @ 2024-07-27 45/week @ 2024-08-03

每月548次下载

Apache-2.0 OR MIT

58KB
1K SLoC

MEMSECURITY

Rust crates.ioDocs

在内存中安全地存储秘密,并通过微架构、物理布局攻击和冷启动攻击防止跨保护边界读取。同时使用 mlock 防止操作系统将这些秘密交换到 RAM,从而在一定程度上防止冷启动攻击。

此算法由 OpenSSH 发明。这种加密方式通过在内存中加密不使用时的敏感数据(如密钥),并在需要时解密,来保护敏感数据。这种方法可以防止各种类型的攻击,包括通过微架构漏洞(如 Spectre 或 Meltdown)进行的跨保护边界读取、物理布局攻击(如 Rowbleed)和冷启动攻击。关键洞察是这些攻击是不完美的,意味着恢复的数据包含位翻转,或者攻击只提供任何给定位的概率。当应用于加密密钥时,这些类型的攻击就足以恢复实际密钥。

然而,此实现使用密钥派生函数从一个称为“预密钥”的大内存区域派生密封密钥。预密钥读取中的任何单个位翻转都会通过密封密钥的所有位级联,使其无法使用,而没有任何错误发生位置的指示。

此 crate 尚未接受审计。使用风险自负!!!

特性

  • symm_asymm - 特性启用可用于在丢弃时安全地将内存清零的数据类型。它们实现了来自 zeroize crate 的 Zeroize 特性。
  • clonable_mem - 允许使用 symm_asymm 特性启用的数据类型进行克隆。
  • encryption - 此特性启用使用 mlockmunlock 加密的加密内存,并使用 Ascon128a 密文。
  • random - 这启用基于 rand_corerand_chacha 的加密安全随机数生成器。

用法示例

  1. 生成随机字节
    使用随机字节生成器(它基于您使用的操作系统提供的随机性进行加密安全)。必须启用 random 功能。
    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. 使用丢弃时为零的数据类型
    有时在数据类型被丢弃时需要将其清零。这可以通过确保在不再需要时不在内存中保留加密密钥或密码等秘密来实现。必须启用 symm_asymm 功能。如果需要克隆这些秘密,则可以启用 clonable_mem 功能(请谨慎使用)。大多数这些都有 .expose_borrowed() 方法,如果您想使用该值,则会暴露内部值。
    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. 使用 Ascon128a 加密在内存中加密秘密
    每次您想在内存中加密密码或加密密钥时,请启用 encryption 功能以使用 EncryptedMem 类型。此数据中实现了 mlockmunlock。加密密钥在每个应用程序运行时都会重新生成。
    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()
    );
    

许可

此包受 Apache 许可证许可,所有贡献和重新分配都必须具有相同的许可证。

行为准则

所有对话和贡献都必须遵守 Rust 行为准则 https://rust-lang.net.cn/policies/code-of-conduct

依赖关系

~1.7–4MB
~80K SLoC