use crate::audit::AuditLogger;
use crate::error::{CryptoError, Result};
use crate::key::Key;
use crate::types::Algorithm;
use argon2::{Algorithm as Argon2Algorithm, Argon2, Params, Version};
use hmac::Hmac;
use libsm::sm3::hash::Sm3Hash;
use pbkdf2::pbkdf2;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use ring::hkdf;
use sha2::Sha256;
use zeroize::Zeroize;
#[inline]
pub fn is_sha_ni_available() -> bool {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
std::is_x86_feature_detected!("sha")
}
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
{
false
}
}
#[allow(dead_code)]
pub struct Hkdf;
impl Hkdf {
#[allow(dead_code)]
pub fn derive(
master_key: &Key,
salt: &[u8],
info: &[u8],
output_algo: Algorithm,
) -> Result<Key> {
if salt.len() > 128 {
return Err(CryptoError::InvalidParameter(
"Salt长度不应超过128字节以保证性能".to_string(),
));
}
if info.len() > 1024 {
return Err(CryptoError::InvalidParameter(
"Info长度不应超过1024字节以保证性能".to_string(),
));
}
let _secret = master_key.secret_bytes()?;
let key_size = output_algo.key_size();
let sha_ni_available = is_sha_ni_available();
AuditLogger::log(
"HKDF_DERIVE_START",
None,
None,
if sha_ni_available {
Ok(())
} else {
Err(CryptoError::HardwareAccelerationUnavailable(
"SHA-NI not available for HKDF".into(),
))
},
);
if key_size == 32 {
return Self::derive_32_bytes(master_key, salt, info, output_algo);
}
if key_size == 16 {
let full_key = Self::derive_32_bytes(master_key, salt, info, Algorithm::AES256GCM)?;
let full_bytes = full_key.secret_bytes()?;
let truncated: Vec<u8> = full_bytes.as_bytes()[..16].to_vec();
drop(full_key);
return Key::new_active(output_algo, truncated);
}
if key_size == 24 {
let full_key = Self::derive_32_bytes(master_key, salt, info, Algorithm::AES256GCM)?;
let full_bytes = full_key.secret_bytes()?;
let truncated: Vec<u8> = full_bytes.as_bytes()[..24].to_vec();
drop(full_key);
return Key::new_active(output_algo, truncated);
}
Err(CryptoError::InvalidParameter(format!(
"Unsupported key size: {}",
key_size
)))
}
#[allow(dead_code)]
fn derive_32_bytes(
master_key: &Key,
salt: &[u8],
info: &[u8],
output_algo: Algorithm,
) -> Result<Key> {
let secret = master_key.secret_bytes()?;
let mut derived_bytes = vec![0u8; 32];
let salt_obj = hkdf::Salt::new(hkdf::HKDF_SHA256, salt);
let prk = salt_obj.extract(secret.as_bytes());
let info_array = [info];
let okm = prk
.expand(&info_array, hkdf::HKDF_SHA256)
.map_err(|e| CryptoError::EncryptionFailed(format!("HKDF Expand failed: {:?}", e)))?;
okm.fill(&mut derived_bytes)
.map_err(|e| CryptoError::EncryptionFailed(format!("HKDF Fill failed: {:?}", e)))?;
let result = Key::new_active(output_algo, derived_bytes.clone());
derived_bytes.zeroize();
AuditLogger::log("HKDF_DERIVE_COMPLETE", None, None, Ok(()));
result
}
}
#[allow(dead_code)]
pub struct Pbkdf2;
#[allow(dead_code)]
impl Pbkdf2 {
#[allow(dead_code)]
pub fn derive(
password: &[u8],
salt: &[u8],
iterations: u32,
output_algo: Algorithm,
) -> Result<Key> {
debug_assert!(
!password.is_empty(),
"Password should not be empty for PBKDF2"
);
debug_assert!(
salt.len() <= 128,
"Salt should not exceed 128 bytes for performance"
);
debug_assert!(
iterations >= 10000,
"PBKDF2 iterations should be at least 10000 for security"
);
let sha_ni_available = is_sha_ni_available();
AuditLogger::log(
"PBKDF2_DERIVE_START",
None,
None,
if sha_ni_available {
Ok(())
} else {
Err(CryptoError::HardwareAccelerationUnavailable(
"SHA-NI not available for PBKDF2".into(),
))
},
);
let key_size = output_algo.key_size();
let mut derived_key = vec![0u8; key_size];
pbkdf2::<Hmac<Sha256>>(password, salt, iterations, &mut derived_key)
.map_err(|e| CryptoError::EncryptionFailed(format!("PBKDF2 failed: {:?}", e)))?;
let result = Key::new_active(output_algo, derived_key.clone());
derived_key.zeroize();
AuditLogger::log("PBKDF2_DERIVE_COMPLETE", None, None, Ok(()));
result
}
}
#[allow(dead_code)]
pub struct Argon2id;
#[allow(dead_code)]
impl Argon2id {
#[allow(dead_code)]
pub fn derive(password: &[u8], salt: &[u8], output_algo: Algorithm) -> Result<Key> {
let key_size = output_algo.key_size();
let mut derived_key = vec![0u8; key_size];
let params = Params::new(65536, 3, 4, Some(key_size))
.map_err(|e| CryptoError::EncryptionFailed(format!("Argon2 params failed: {:?}", e)))?;
let argon2 = Argon2::new(Argon2Algorithm::Argon2id, Version::V0x13, params);
argon2
.hash_password_into(password, salt, &mut derived_key)
.map_err(|e| CryptoError::EncryptionFailed(format!("Argon2 failed: {:?}", e)))?;
let result = Key::new_active(output_algo, derived_key.clone());
derived_key.zeroize();
result
}
}
#[allow(dead_code)]
pub struct Sm3Kdf;
impl Sm3Kdf {
#[allow(dead_code)]
pub fn derive(
master_key: &Key,
data: &[u8],
key_len: usize,
output_algo: Algorithm,
) -> Result<Key> {
const HASH_LEN: usize = 32;
if key_len == 0 || key_len > 1024 {
return Err(CryptoError::InvalidParameter(format!(
"Invalid key length for KDF: {}",
key_len
)));
}
let secret = master_key.secret_bytes()?;
let secret_bytes = secret.as_bytes();
let n = key_len.div_ceil(HASH_LEN);
if n > (u32::MAX as usize) {
return Err(CryptoError::InvalidParameter(
"Key length too large".to_string(),
));
}
let mut derived_key = Vec::with_capacity(key_len);
for i in 1..=n {
let mut input = Vec::with_capacity(secret_bytes.len() + data.len() + 4);
input.extend_from_slice(secret_bytes);
input.extend_from_slice(data);
input.extend_from_slice(&(i as u32).to_be_bytes());
let mut hasher = Sm3Hash::new(&input);
let hash = hasher.get_hash();
derived_key.extend_from_slice(&hash);
}
derived_key.truncate(key_len);
let result = Key::new_active(output_algo, derived_key.clone());
derived_key.zeroize();
result
}
#[cfg(feature = "parallel")]
#[allow(dead_code)]
pub fn parallel_derive(
master_key: &Key,
data: &[u8],
key_len: usize,
output_algo: Algorithm,
) -> Result<Key> {
const HASH_LEN: usize = 32;
if key_len == 0 || key_len > 1024 {
return Err(CryptoError::InvalidParameter(format!(
"Invalid key length for KDF: {}",
key_len
)));
}
let secret = master_key.secret_bytes()?;
let secret_bytes = secret.as_bytes();
let n = key_len.div_ceil(HASH_LEN);
if n > (u32::MAX as usize) {
return Err(CryptoError::InvalidParameter(
"Key length too large".to_string(),
));
}
AuditLogger::log("SM3KDF_PARALLEL_DERIVE_START", None, None, Ok(()));
let hashes: Vec<Vec<u8>> = (1..=n)
.into_par_iter()
.map(|i| {
let mut input = Vec::with_capacity(secret_bytes.len() + data.len() + 4);
input.extend_from_slice(secret_bytes);
input.extend_from_slice(data);
input.extend_from_slice(&(i as u32).to_be_bytes());
let mut hasher = Sm3Hash::new(&input);
hasher.get_hash().to_vec()
})
.collect();
let mut derived_key = Vec::with_capacity(key_len);
for hash in hashes {
derived_key.extend_from_slice(&hash);
}
derived_key.truncate(key_len);
let result = Key::new_active(output_algo, derived_key.clone());
derived_key.zeroize();
AuditLogger::log("SM3KDF_PARALLEL_DERIVE_COMPLETE", None, None, Ok(()));
result
}
#[cfg(feature = "parallel")]
#[allow(dead_code)]
pub fn derive_optimal(
master_key: &Key,
data: &[u8],
key_len: usize,
output_algo: Algorithm,
) -> Result<Key> {
if key_len > 64 {
return Self::parallel_derive(master_key, data, key_len, output_algo);
}
Self::derive(master_key, data, key_len, output_algo)
}
#[cfg(not(feature = "parallel"))]
#[allow(dead_code)]
pub fn derive_optimal(
master_key: &Key,
data: &[u8],
key_len: usize,
output_algo: Algorithm,
) -> Result<Key> {
Self::derive(master_key, data, key_len, output_algo)
}
}
#[cfg(test)]
mod sm3_tests {
use crate::key::derivation::Sm3Kdf;
use crate::key::Key;
use crate::types::Algorithm;
#[test]
fn test_sm3_hash_implementation() {
let master_key_bytes = vec![0x42u8; 32]; let master_key =
Key::new_active(Algorithm::AES256GCM, master_key_bytes).expect("创建主密钥失败");
let fixed_data = b"test_fixed_data";
let key1 = Sm3Kdf::derive(&master_key, fixed_data, 32, Algorithm::AES256GCM)
.expect("SM3密钥派生应该成功");
let key1_bytes = key1.secret_bytes().expect("应该获取到密钥字节");
let is_non_zero = key1_bytes.as_bytes().iter().any(|&b| b != 0);
assert!(is_non_zero, "派生的密钥应包含非零字节");
let key2 = Sm3Kdf::derive(&master_key, fixed_data, 32, Algorithm::AES256GCM)
.expect("第二次SM3密钥派生应该成功");
let key2_bytes = key2.secret_bytes().expect("应该获取到密钥字节");
assert_eq!(
key1_bytes.as_bytes(),
key2_bytes.as_bytes(),
"SM3实现应该是确定性的"
);
let different_data = b"different_data";
let key3 = Sm3Kdf::derive(&master_key, different_data, 32, Algorithm::AES256GCM)
.expect("使用不同数据的SM3密钥派生应该成功");
let key3_bytes = key3.secret_bytes().expect("应该获取到密钥字节");
assert_ne!(
key1_bytes.as_bytes(),
key3_bytes.as_bytes(),
"不同输入应该产生不同的密钥"
);
println!("SM3哈希实现测试通过!");
}
}