feat(v3): migrate workspace to API, Tauri desktop, and v3 crates; remove legacy MCP stack
Some checks failed
Secrets v3 CI / 检查 (push) Has been cancelled
Some checks failed
Secrets v3 CI / 检查 (push) Has been cancelled
- 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)
This commit is contained in:
47
crates/crypto/src/lib.rs
Normal file
47
crates/crypto/src/lib.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
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"))
|
||||
}
|
||||
Reference in New Issue
Block a user