use crate::crypto::{decrypt_shard, derive_key_from_section, encrypt_shard};
use crate::error::{Error, Result};
use crate::metadata::KeyMetadata;
use object::{Object, ObjectSection};
use std::env;
use std::fs::{self, File};
use std::io::Read;
use std::path::PathBuf;
include!(concat!(env!("OUT_DIR"), "/crypto_constants.rs"));
pub struct KeyStore {
exe_path: PathBuf,
metadata: KeyMetadata,
}
impl KeyStore {
const METADATA_SECTION: &'static str = ".key_meta";
const DERIVE_SECTION: &'static str = ".text";
pub fn new() -> Result<Self> {
let exe_path = env::current_exe()?;
let mut file = File::open(&exe_path)?;
let mut binary_data = Vec::new();
file.read_to_end(&mut binary_data)?;
drop(file);
let metadata = Self::read_metadata(&binary_data).unwrap_or_else(|_| {
KeyMetadata::generate()
});
metadata.validate()?;
Ok(Self { exe_path, metadata })
}
pub fn update_bytes(&mut self, new_key: &[u8]) -> Result<()> {
let mut binary_data = fs::read(&self.exe_path)?;
let needs_metadata_init = Self::read_metadata(&binary_data).is_err();
if needs_metadata_init {
self.write_metadata_to_binary(&mut binary_data)?;
}
let total_capacity = self.metadata.total_capacity();
if new_key.len() > total_capacity {
return Err(Error::Config(format!(
"密钥长度({})超出总容量({}), 请考虑重新编译以增加容量",
new_key.len(),
total_capacity
)));
}
let mut padded_key = new_key.to_vec();
padded_key.resize(total_capacity, 0);
let mut offset_in_key = 0;
for (i, &shard_size) in self.metadata.shard_sizes.iter().enumerate() {
let shard_data = &padded_key[offset_in_key..offset_in_key + shard_size];
offset_in_key += shard_size;
let section_name = &self.metadata.shard_names[i];
let (section_offset, section_size) = Self::find_section(&binary_data, section_name)?;
if section_size < shard_size {
return Err(Error::SizeMismatch {
expected: shard_size,
actual: section_size,
});
}
let derive_key =
derive_key_from_section(&binary_data, Self::DERIVE_SECTION, shard_size)?;
let shard_seed = SHARD_SEED_OFFSETS[i % SHARD_SEED_OFFSETS.len()];
let encrypted =
encrypt_shard(shard_data, &derive_key, shard_seed.wrapping_add(i as u8));
binary_data[section_offset..section_offset + shard_size].copy_from_slice(&encrypted);
}
let (meta_offset, _) = Self::find_section(&binary_data, Self::METADATA_SECTION)?;
let key_len_bytes = (new_key.len() as u64).to_le_bytes();
binary_data[meta_offset..meta_offset + 8].copy_from_slice(&key_len_bytes);
Self::atomic_write(&self.exe_path, &binary_data)?;
Ok(())
}
pub fn update(&mut self, new_key: &str) -> Result<()> {
self.update_bytes(new_key.as_bytes())
}
pub fn read_bytes(&self) -> Result<Vec<u8>> {
let binary_data = fs::read(&self.exe_path)?;
let (meta_offset, _) = Self::find_section(&binary_data, Self::METADATA_SECTION)?;
let key_len_bytes = &binary_data[meta_offset..meta_offset + 8];
let actual_key_len = u64::from_le_bytes([
key_len_bytes[0],
key_len_bytes[1],
key_len_bytes[2],
key_len_bytes[3],
key_len_bytes[4],
key_len_bytes[5],
key_len_bytes[6],
key_len_bytes[7],
]) as usize;
if actual_key_len == 0 {
return Ok(Vec::new());
}
let total_capacity = self.metadata.total_capacity();
if actual_key_len > total_capacity {
return Err(Error::Config(format!(
"存储的密钥长度异常: {} > {}",
actual_key_len, total_capacity
)));
}
let mut decrypted_bytes = Vec::new();
let mut bytes_needed = actual_key_len;
for (i, &shard_size) in self.metadata.shard_sizes.iter().enumerate() {
if bytes_needed == 0 {
break;
}
let section_name = &self.metadata.shard_names[i];
let (section_offset, section_size) = Self::find_section(&binary_data, section_name)?;
if section_size < shard_size {
return Err(Error::SizeMismatch {
expected: shard_size,
actual: section_size,
});
}
let encrypted_data = &binary_data[section_offset..section_offset + shard_size];
let derive_key =
derive_key_from_section(&binary_data, Self::DERIVE_SECTION, shard_size)?;
let shard_seed = SHARD_SEED_OFFSETS[i % SHARD_SEED_OFFSETS.len()];
let decrypted = decrypt_shard(
encrypted_data,
&derive_key,
shard_seed.wrapping_add(i as u8),
);
let bytes_to_take = bytes_needed.min(decrypted.len());
decrypted_bytes.extend(&decrypted[..bytes_to_take]);
bytes_needed -= bytes_to_take;
}
Ok(decrypted_bytes)
}
pub fn read(&self) -> Result<String> {
let bytes = self.read_bytes()?;
String::from_utf8(bytes).map_err(|e| Error::Parse(format!("密钥不是有效的UTF-8: {}", e)))
}
pub fn capacity(&self) -> usize {
self.metadata.total_capacity()
}
pub fn generate_random_key(length: usize) -> String {
use rand::Rng;
let mut rng = rand::thread_rng();
(0..length)
.map(|_| rng.gen_range(33..=126) as u8 as char)
.collect()
}
pub fn generate_random_bytes(length: usize) -> Vec<u8> {
use rand::Rng;
let mut rng = rand::thread_rng();
(0..length).map(|_| rng.gen()).collect()
}
fn read_metadata(binary_data: &[u8]) -> Result<KeyMetadata> {
let (offset, size) = Self::find_section(binary_data, Self::METADATA_SECTION)?;
if size < 8 {
return Err(Error::Config(format!("元数据section太小: {} < 8", size)));
}
let metadata_bytes = &binary_data[offset + 8..offset + size];
KeyMetadata::from_bytes(metadata_bytes)
}
fn write_metadata_to_binary(&self, binary_data: &mut Vec<u8>) -> Result<()> {
let (meta_offset, meta_size) = Self::find_section(binary_data, Self::METADATA_SECTION)?;
let json_bytes = self.metadata.to_bytes()?;
if json_bytes.len() + 8 > meta_size {
return Err(Error::Config(format!(
"元数据section空间不足: {} + 8 > {}",
json_bytes.len(),
meta_size
)));
}
binary_data[meta_offset + 8..meta_offset + 8 + json_bytes.len()]
.copy_from_slice(&json_bytes);
Ok(())
}
fn find_section(binary_data: &[u8], section_name: &str) -> Result<(usize, usize)> {
let obj_file = object::File::parse(binary_data)
.map_err(|e| Error::Parse(format!("无法解析二进制格式: {}", e)))?;
for section in obj_file.sections() {
if let Ok(name) = section.name() {
if name == section_name {
let (offset, size) = section.file_range().ok_or_else(|| {
Error::Parse(format!("无法获取section {}的文件偏移", section_name))
})?;
return Ok((offset as usize, size as usize));
}
}
}
Err(Error::SectionNotFound(section_name.to_string()))
}
fn atomic_write(path: &PathBuf, data: &[u8]) -> Result<()> {
let temp_path = path.with_extension("tmp");
fs::write(&temp_path, data)?;
#[cfg(unix)]
{
let metadata = fs::metadata(path)?;
let permissions = metadata.permissions();
fs::set_permissions(&temp_path, permissions)?;
}
fs::rename(&temp_path, path)?;
Ok(())
}
}