#secret #secret-management #security #meta-programming #unsigned-integer #exposure-control #non-linear-types

无需 std sosecrets-rs

一个简单的 Secret 包装类型,最多在编译时保证 MEC: typenum::Unsigned 次揭示秘密

8 个版本

0.2.6 2024 年 7 月 18 日
0.2.5 2024 年 7 月 17 日
0.2.4 2024 年 4 月 25 日
0.2.0 2024 年 3 月 16 日
0.1.0 2024 年 1 月 27 日

266Rust 模式

Download history 21/week @ 2024-04-27 186/week @ 2024-07-13 25/week @ 2024-07-20 53/week @ 2024-07-27 1/week @ 2024-08-03

每月 111 次下载

自定义许可证

65KB
722

Secrets Management crate with

  1. 类型级别和编译时保证,并且
  2. 每个引用都对应每个只能在一个具有不变生命周期的词法作用域中暴露或揭示的秘密

它与 secrecy crate 类似,但具有类型级别和编译时保证,即 Secret<T, MEC, EC> 值不会超过 MEC 次数暴露,并且仅在定义良好的词法作用域下暴露。

它使用 typenum crate 来实现其所有编译时保证。

功能

  • 暴露控制:秘密值只能暴露有限次数,防止意外信息泄露。这是在编译时保证的。秘密值在一个具有不变生命周期的词法作用域中暴露和可用。
  • 零化:如果配置了 "zeroize" 功能,则在丢弃秘密值时将其零化。
  • 可克隆的秘密:使用 "cloneable-secret" 功能,如果底层类型 T 实现了 CloneableSecret 特性,则可以克隆 Secret 值。
  • 调试秘密:使用 "debug-secret" 功能,如果底层类型 T 实现了 DebugSecret 特性,则可以调试 Secret 值。

使用示例

编译时检查

use sosecrets_rs::{
  prelude::*,
  traits::ExposeSecret,
};
use typenum::U2;

// Define a secret with a maximum exposure count of 2
let secret = Secret::<_, U2>::new("my_secret_value".to_string());

// Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
let (next_secret, exposed_value) = secret.expose_secret(|exposed_secret| {
  // `exposed_secret` is only 'available' from the next line -------
  assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); //     ^
  // Perform operations with the exposed value                     |
  // ...                                                           v
  // to this line... -----------------------------------------------
});

// Expose the secret again and perform some operations with the exposed value; secret has been exposed twice: `EC` = 2, `MEC` = 2;
let (next_secret, exposed_value) = next_secret.expose_secret(|exposed_secret| {
  assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
  // Perform operations with the exposed value
  // ...
});

尝试再次公开秘密并使用公开的值执行一些操作;秘密已被公开第三次:EC = 3,MEC = 2;以下代码不可编译。

let (next_secret, exposed_value) = next_secret.expose_secret(|exposed_secret| {
    assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
    // Perform operations with the exposed value
    // ...
});

不可能将传递给闭包的值(例如上面示例中的 exposed_secret)返回到闭包之外。

以下代码不可编译。

let (next_secret, exposed_value) = next_secret.expose_secret(|exposed_secret| {
    assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
    // Perform operations with the exposed value
    // ...
    exposed_secret // impossible to return `exposed_secret` here
});

注意:如果 TCopy,则上述代码可以成功编译,并且 expose_secret(...) 方法将返回公开的 T 的一个 副本

运行时检查

use sosecrets_rs::{
  prelude::*,
  // Note, for runtime checks, you have to use the `RTExposeSecret` trait instead.
  runtime::traits::RTExposeSecret,
};
use typenum::U2;

// Define a secret with a maximum exposure count of 2
let secret = RTSecret::<_, U2>::new("my_secret_value".to_string());

// Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
let exposed_value = secret.expose_secret(|exposed_secret| {
  // `exposed_secret` is only 'available' from the next line -------
  assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); //     ^
  // Perform operations with the exposed value                     |
  // ...                                                           v
  // to this line... -----------------------------------------------
});

// Expose the secret again and perform some operations with the exposed value; secret has been exposed twice: `EC` = 2, `MEC` = 2;
let exposed_value = secret.expose_secret(|exposed_secret| {
  assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
  // Perform operations with the exposed value
  // ...
});

尝试再次公开秘密并使用公开的值执行一些操作;秘密已被公开第三次:EC = 3,MEC = 2;

.expose_secret(...) 方法将引发 panic 并显示消息

`RTSecret\` has already been exposed for 2 times, the maximum number it is allowed to be exposed for is 2 times."
# use sosecrets_rs::{
#   prelude::*,
#   // Note, for runtime checks, you have to use the `RTExposeSecret` trait instead.
#   runtime::traits::RTExposeSecret,
# };
# use typenum::U2;
#
# // Define a secret with a maximum exposure count of 2
# let secret = RTSecret::<_, U2>::new("my_secret_value".to_string());
#
# // Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
# let exposed_value = secret.expose_secret(|exposed_secret| {
#   // `exposed_secret` is only 'available' from the next line -------
#   assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); //     ^
#   // Perform operations with the exposed value                     |
#   // ...                                                           v
#   // to this line... -----------------------------------------------
# });
#
# // Expose the secret again and perform some operations with the exposed value; secret has been exposed twice: `EC` = 2, `MEC` = 2;
# let exposed_value = secret.expose_secret(|exposed_secret| {
#   assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
#   // Perform operations with the exposed value
#   // ...
# });
let exposed_value = secret.expose_secret(|exposed_secret| {
  assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
  // Perform operations with the exposed value
  // ...
});

注意:您可以使用方法 expose_secret(...) 的非 panic 变体,该方法的名称为 try_expose_secret(...)

try_expose_secret(...) 如果公开次数超过最大允许值,则返回一个 Result::Err

不可能将传递给闭包的值(例如上面示例中的 exposed_secret)返回到闭包之外,除非 TCopy。以下代码不可编译。

let exposed_value = secret.expose_secret(|exposed_secret| {
  assert_eq!(&*exposed_secret.as_str(), "my_secret_value");
  // Perform operations with the exposed value
  // ...
  exposed_secret // impossible to return `exposed_secret` here
});

secrecy 包替换为

您可以使用 SecrecySecret 类型作为 Secret<T> 的替代品,该类型位于 secrecy 包中。

use sosecrets_rs::{
  prelude::*,
  // Note, for runtime checks, you have to use the `RTExposeSecret` trait instead.
  runtime::traits::RTExposeSecret,
};

// Define a secret with NO maximum exposure count
let secret = SecrecySecret::new("my_secret_value".to_string());

// Expose the secret and perform some operations with the exposed value as many times as you like.
for _ in 0..=1_000_000 {
  let exposed_value = secret.expose_secret(|exposed_secret| {
  // `exposed_secret` is only 'available' from the next line -------
  assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); //     ^
  // Perform operations with the exposed value                     |
  // ...                                                           v
  // to this line... -----------------------------------------------
  });
}

更多示例请参阅 示例目录

功能配置

要启用功能,您可以在您的 Cargo.toml 文件中包含它们

[dependencies]
sosecrets-rs = { version = "x.x.x", features = ["zeroize", "cloneable-secret", "debug-secret"] }

模块

特质

例如,如果启用了功能 "cloneable-secret",那么您就可以“克隆”秘密。

示例

#[cfg(all(feature = "cloneable-secret", feature = "alloc"))]
// Need to enable feature = "alloc" because `String` requires feature = "alloc".
{
  use sosecrets_rs::{
      prelude::*,
      traits::{CloneableSecret, ExposeSecret},
  };
  use typenum::U2;

  // Define a secret with a maximum exposure count of 2
  let secret = Secret::<_, U2>::new("my_secret_value".to_string());

  // Clone the secret
  let secret2 = secret.clone();

  // Expose the secret and perform some operations with the exposed value; secret has been exposed once: `EC` = 1, `MEC` = 2;
  let (next_secret, exposed_value) = secret.expose_secret(move |exposed_secret| {
      // `exposed_secret` is only 'available' from the next line --------------------------^
      let (next_secret2, exposed_value2) = secret2.expose_secret(|exposed_secret2| { //    |
          assert_eq!(&*exposed_secret.as_str(), "my_secret_value"); //                     |
          assert_eq!(&*exposed_secret2.as_str(), "my_secret_value"); //                    |
          assert_eq!(&*exposed_secret2.as_str(), &*exposed_secret.as_str()); //            |
          // Perform operations with the exposed value                                      |
          // ...                                                                            |
          // to this line... ---------------------------------------------------------------v
      });
  });
}

最低支持的 Rust 版本

该包目前需要 Rust 1.70。我没有意图将此包的编译器版本要求提高超过这个版本。然而,这仅保证在给定的次要版本号内。

测试

运行

bash scripts/tests-all-features.sh

许可证

许可下

贡献

除非您明确声明,否则,根据 MIT 许可证,您有意提交的任何贡献,以包含在作品中,没有附加条款或条件。

致谢

CAD97

Eric Michael Sumner

  • Rust 论坛 上创建宏 impl_choose_int!()。该宏有助于为 typenum 包提供的所有类型级无符号整数实现 ChooseMinimallyRepresentableUInt trait,这些整数在类型级别上可以从 1 位到 64 位表示。

Simon Farnsworth

  • 就如何管理有关 RTSecret 的优化提供建议,其中结构体的第一个字段根据类型参数 MEC 使用 Rust 的不同原始无符号整数类型 [链接]。

依赖项

~165KB