Files
secrets/crates/crypto/src/lib.rs
agent 0374899dab
Some checks failed
Secrets v3 CI / 检查 (push) Has been cancelled
feat(v3): migrate workspace to API, Tauri desktop, and v3 crates; remove legacy MCP stack
- Add apps/api, desktop Tauri shell, domain/application/crypto/device-auth/infrastructure-db
- Replace desktop-daemon vault integration; drop secrets-core and secrets-mcp*
- Ignore apps/desktop/dist and generated Tauri icons; document icon/dist steps in AGENTS.md
- Apply rustfmt; fix clippy (collapsible_if, HTTP method as str)
2026-04-14 17:37:12 +08:00

48 lines
1.4 KiB
Rust

use aes_gcm::aead::{Aead, KeyInit};
use aes_gcm::{Aes256Gcm, Nonce};
use anyhow::{Context, Result};
use rand::Rng;
pub const KEY_CHECK_PLAINTEXT: &[u8] = b"secrets-v3-key-check";
pub fn decode_hex(input: &str) -> Result<Vec<u8>> {
hex::decode(input.trim()).context("invalid hex")
}
pub fn encode_hex(input: &[u8]) -> String {
hex::encode(input)
}
pub fn extract_key_32(input: &str) -> Result<[u8; 32]> {
let bytes = decode_hex(input)?;
let key: [u8; 32] = bytes
.try_into()
.map_err(|_| anyhow::anyhow!("expected 32-byte key"))?;
Ok(key)
}
pub fn encrypt(key: &[u8; 32], plaintext: &[u8]) -> Result<Vec<u8>> {
let cipher = Aes256Gcm::new_from_slice(key).context("invalid AES-256 key")?;
let mut nonce_bytes = [0_u8; 12];
rand::rng().fill_bytes(&mut nonce_bytes);
let nonce = Nonce::from_slice(&nonce_bytes);
let mut out = nonce_bytes.to_vec();
out.extend(
cipher
.encrypt(nonce, plaintext)
.map_err(|_| anyhow::anyhow!("encryption failed"))?,
);
Ok(out)
}
pub fn decrypt(key: &[u8; 32], ciphertext: &[u8]) -> Result<Vec<u8>> {
if ciphertext.len() < 12 {
anyhow::bail!("ciphertext too short");
}
let cipher = Aes256Gcm::new_from_slice(key).context("invalid AES-256 key")?;
let (nonce, body) = ciphertext.split_at(12);
cipher
.decrypt(Nonce::from_slice(nonce), body)
.map_err(|_| anyhow::anyhow!("decryption failed"))
}