发布 v0.2.1:SM2 密钥交换、HKDF-SM3、DER 编解码
新增功能: - SM2 密钥交换:GB/T 32918.3 完整协议(exchange_a/b)、ECDH - SM2 DER 编解码:签名 DER、SEC1/PKCS#8 私钥解析 - SM2 便捷 API:sign_message/verify_message 自动计算 Z 值 - HKDF-SM3:RFC 5869 兼容的 HKDF - SM3 Hasher 增强:reset/finalize_reset 流式复用 - SM4 AEAD 合并格式:GCM/CCM combined(TLS 格式) 文档更新: - CHANGELOG 添加 v0.2.1 变更记录
This commit is contained in:
+72
-13
@@ -23,6 +23,7 @@
|
||||
//! 如需 HMAC,请使用 [`hmac_sm3`]。
|
||||
|
||||
mod compress;
|
||||
pub mod hkdf;
|
||||
|
||||
use compress::{compress, IV};
|
||||
|
||||
@@ -104,33 +105,56 @@ impl Sm3Hasher {
|
||||
///
|
||||
/// 调用后此 hasher 不应再使用(消耗所有权的版本请用 [`finalize`](Self::finalize))。
|
||||
pub fn finalize(mut self) -> [u8; DIGEST_LEN] {
|
||||
Self::finalize_inner(&mut self)
|
||||
}
|
||||
|
||||
/// 完成哈希并重置状态(供复用,无需重新构造)
|
||||
///
|
||||
/// 等同于 `finalize()` 后调用 `reset()`,但只需一次操作。
|
||||
/// rustls `Hasher` trait 要求此语义(`finish(&mut self)`)。
|
||||
pub fn finalize_reset(&mut self) -> [u8; DIGEST_LEN] {
|
||||
let out = Self::finalize_inner(self);
|
||||
self.reset();
|
||||
out
|
||||
}
|
||||
|
||||
/// 重置为初始状态(等同于重新调用 `new()`,但复用已分配内存)
|
||||
pub fn reset(&mut self) {
|
||||
self.state = IV;
|
||||
self.buffer = [0u8; 64];
|
||||
self.buf_len = 0;
|
||||
self.bit_len = 0;
|
||||
}
|
||||
|
||||
/// 内部完成函数(同时供消耗版和借用版使用)
|
||||
fn finalize_inner(h: &mut Self) -> [u8; DIGEST_LEN] {
|
||||
// 计算总位数(包含缓冲区中的字节)
|
||||
let total_bits = self.bit_len.wrapping_add((self.buf_len as u64) * 8);
|
||||
let total_bits = h.bit_len.wrapping_add((h.buf_len as u64) * 8);
|
||||
|
||||
// Padding:追加 0x80 + 零字节,使消息长度 ≡ 56 (mod 64)
|
||||
self.buffer[self.buf_len] = 0x80;
|
||||
self.buf_len += 1;
|
||||
h.buffer[h.buf_len] = 0x80;
|
||||
h.buf_len += 1;
|
||||
|
||||
if self.buf_len > 56 {
|
||||
if h.buf_len > 56 {
|
||||
// 当前块填不下长度字段,先处理这块,再开一块
|
||||
for i in self.buf_len..64 {
|
||||
self.buffer[i] = 0;
|
||||
for i in h.buf_len..64 {
|
||||
h.buffer[i] = 0;
|
||||
}
|
||||
compress(&mut self.state, &self.buffer);
|
||||
self.buffer = [0u8; 64];
|
||||
compress(&mut h.state, &h.buffer);
|
||||
h.buffer = [0u8; 64];
|
||||
} else {
|
||||
for i in self.buf_len..56 {
|
||||
self.buffer[i] = 0;
|
||||
for i in h.buf_len..56 {
|
||||
h.buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 最后 8 字节写入总位长(大端)
|
||||
self.buffer[56..64].copy_from_slice(&total_bits.to_be_bytes());
|
||||
compress(&mut self.state, &self.buffer);
|
||||
h.buffer[56..64].copy_from_slice(&total_bits.to_be_bytes());
|
||||
compress(&mut h.state, &h.buffer);
|
||||
|
||||
// 输出:8 个 u32 大端序拼接
|
||||
let mut out = [0u8; 32];
|
||||
for (i, &v) in self.state.iter().enumerate() {
|
||||
for (i, &v) in h.state.iter().enumerate() {
|
||||
out[i * 4..i * 4 + 4].copy_from_slice(&v.to_be_bytes());
|
||||
}
|
||||
out
|
||||
@@ -262,6 +286,41 @@ mod tests {
|
||||
assert_eq!(mac.len(), 32);
|
||||
}
|
||||
|
||||
/// reset() 后状态恢复为 new() 初始状态
|
||||
#[test]
|
||||
fn test_reset_equals_new() {
|
||||
let mut h = Sm3Hasher::new();
|
||||
h.update(b"some data");
|
||||
h.reset();
|
||||
let digest_after_reset = h.finalize();
|
||||
let digest_fresh = Sm3Hasher::digest(b"");
|
||||
assert_eq!(digest_after_reset, digest_fresh);
|
||||
}
|
||||
|
||||
/// finalize_reset() 返回正确摘要,且随后状态已重置
|
||||
#[test]
|
||||
fn test_finalize_reset_correctness() {
|
||||
let mut h = Sm3Hasher::new();
|
||||
h.update(b"abc");
|
||||
let d1 = h.finalize_reset();
|
||||
// d1 应等于 SM3("abc")
|
||||
assert_eq!(d1, Sm3Hasher::digest(b"abc"));
|
||||
// 重置后哈希空消息应等于 SM3("")
|
||||
let d2 = h.finalize();
|
||||
assert_eq!(d2, Sm3Hasher::digest(b""));
|
||||
}
|
||||
|
||||
/// finalize_reset() 可连续使用两次,结果一致
|
||||
#[test]
|
||||
fn test_finalize_reset_repeatable() {
|
||||
let mut h = Sm3Hasher::new();
|
||||
h.update(b"test");
|
||||
let d1 = h.finalize_reset();
|
||||
h.update(b"test");
|
||||
let d2 = h.finalize_reset();
|
||||
assert_eq!(d1, d2);
|
||||
}
|
||||
|
||||
// 辅助:从十六进制字符串构造 [u8; 32]
|
||||
fn hex_literal(s: &str) -> [u8; 32] {
|
||||
let mut out = [0u8; 32];
|
||||
|
||||
Reference in New Issue
Block a user