#ietf-rfc #otp #time #pad #one-time #rfc2289 #one

no-std rfc2289-otp

根据 IETF RFC 2289 的单次密码 (OTP)

2 个稳定版本

1.1.0 2024年6月18日
1.0.0 2024年6月17日

#371 in 加密学

MIT 许可证

55KB
791

RFC 2289 单次密码

实现了 IETF RFC 2289 中描述的单次密码 (OTP) 算法,包括解析字符串和在词典单词与 OTP 值之间进行映射的函数。

此算法与今天广泛用于多因素身份验证的 TOTP 和 HOTP 算法不同:这些算法在其他的 RFC 中定义。然而,此算法在 IETF RFC 2444 中描述的 OTP SASL 机制中使用。

安全性

请注意,此算法只定义了三种哈希算法,并且 所有这些算法都不再被认为是安全的。这些是

  • MD4
  • MD5
  • SHA1

然而,我作为非专业人士认为,这些算法在 OTP 算法中使用的这种方式是完全可以接受的,因为 OTP 算法使用固定的种子和密码进行固定次数的哈希。尽管如此,我 强烈 建议只使用 sha1 算法。它是三者中最新的、最安全的。

如果将来有更多的算法被正式化,你应该在这里查看新算法:here.

我计划实现更多这样的算法,即使它们没有标准化。标准算法背后的原则在现代算法中具有明显的推论。如果您希望支持某个特定的算法,请提出请求!

功能标志

此库的功能标志包括

  • md4:MD4 支持
  • md5:MD5 支持
  • sha1:SHA1 支持
  • words:词典单词的翻译
  • dyndig:支持实现 digest::DynDigest 的任何摘要
  • parsing:解析 OTP 字符串

上述所有功能默认启用。

用法

假设你以以下字符串形式接收一个 OTP 挑战

otp-md5 499 ke1234 ext

按照如下方式解码此字符串

let challenge_str = "otp-md5 487 dog2";
let challenge = parse_otp_challenge(challenge_str).unwrap();

如果它是一个有效的字符串,你应该得到一个类似以下的数据结构

pub struct OTPChallenge <'a> {
    pub hash_alg: &'a str,
    pub hash_count: usize,
    pub seed: &'a str,
}

您可以使用此数据结构按如下方式计算OTP

let extremely_secure_passphrase = "banana";
let otp = calculate_otp(
    challenge.hash_alg,
    extremely_secure_passphrase,
    challenge.seed,
    challenge.hash_count,
    None,
).unwrap();

如果算法已理解,且没有其他问题,您应该得到一个 [u8; 8] 返回值(64位),这是您的OTP值。

您可以直接将此值转换为十六进制,并在其前面加上 hex: 以生成有效的OTP响应。

或者,您可以使用 convert_to_word_format 将其转换为规范字典定义的标准字典中的字典单词。用空格连接这些单词,并在前面加上 word:

如果实现OTP服务器,您可以像这样解析这些响应

let otp_response = "hex:5Bf0 75d9 959d 036f";
let r = parse_otp_response(&otp_response).unwrap();

如果语法有效,您应该得到一个如下所示的 OTPResponse

pub enum HexOrWords <'a> {
    Hex(Hex64Bit),
    Words(&'a str),
}

pub struct OTPInit <'a> {
    pub current_otp: HexOrWords<'a>,
    pub new_otp: HexOrWords<'a>,
    pub new_alg: &'a str,
    pub new_seq_num: usize,
    pub new_seed: &'a str,
}

pub enum OTPResponse <'a> {
    Init(OTPInit <'a>),
    Current(HexOrWords<'a>)
}

服务器需要计算OTP并将该值与客户端提供的解码的十六进制或单词进行比较。您可以使用 decode_word_format_with_std_dict 将单词解码为二进制OTP值

let decoded = decode_word_format_with_std_dict(words).unwrap();

如果客户端响应是 Init 变体之一,服务器如何处理这是一个实现细节。

许可

版权所有 2024 (c) Jonathan M. Wilbur。

此内容受MIT许可协议的许可。双重许可真的很烦人,我也不理解其合理性。如果您真的需要Apache许可,只需向我提出,我会为您解决。

依赖项

~410KB