审计发现 55 检查点,46 PASS / 7 WARN / 2 FAIL,修复内容: Critical: - C1: 密钥轮换端点现在持久化新 DEK 到 tenant_crypto_keys 表 - C2: CachedDek 实现 Drop trait,释放时清零密钥材料 Medium: - M1: 密文格式添加版本前缀 0x01,向后兼容旧格式 - M2: HMAC 索引使用独立子密钥,与加密 KEK 分离 - M4: 脱敏函数使用 chars() 迭代器,UTF-8 安全 - M5-M6: 医生执业证号详情响应脱敏 (mask_license_number) Low: - L1: dek_manager 改为 pub(crate),暴露 invalidate_dek() 方法 - L3: 合并 patient 列表搜索中冗余的重复 HMAC 计算 - L4: update_family_member/update_doctor 更新时设置 key_version
25 lines
787 B
Rust
25 lines
787 B
Rust
use hmac::{Hmac, Mac};
|
|
use sha2::Sha256;
|
|
|
|
type HmacSha256 = Hmac<Sha256>;
|
|
|
|
/// HMAC-SHA256 搜索索引。使用 KEK 派生的独立子密钥,与加密密钥分离。
|
|
pub fn hmac_hash(key: &[u8; 32], value: &str) -> String {
|
|
let hmac_key = derive_hmac_key(key);
|
|
let mut mac = HmacSha256::new_from_slice(&hmac_key).expect("HMAC key length is valid");
|
|
mac.update(value.as_bytes());
|
|
hex::encode(mac.finalize().into_bytes())
|
|
}
|
|
|
|
/// 从 KEK 派生独立的 HMAC 子密钥,避免密钥复用
|
|
fn derive_hmac_key(kek: &[u8; 32]) -> [u8; 32] {
|
|
use sha2::Digest;
|
|
let derived = <Sha256 as Digest>::new()
|
|
.chain_update(b"pii-hmac-index-v1")
|
|
.chain_update(kek)
|
|
.finalize();
|
|
let mut key = [0u8; 32];
|
|
key.copy_from_slice(&derived);
|
|
key
|
|
}
|