Skip to main content

Mountain/IPC/WindServiceHandlers/Encryption/
Decrypt.rs

1
2//! `encryption:decrypt(value: string) -> string`
3//!
4//! Reverses `encryption:encrypt`: base64-decodes, splits the 12-byte nonce
5//! from the ciphertext+tag, decrypts with AES-256-GCM, and returns the
6//! original plaintext string. Returns an empty string on any failure so the
7//! workbench treats a corrupt blob as "no stored secret" rather than crashing.
8
9use base64::{Engine, engine::general_purpose::STANDARD as B64};
10use ring::aead::{AES_256_GCM, Aad, LessSafeKey, Nonce, UnboundKey};
11use serde_json::{Value, json};
12
13use crate::dev_log;
14use super::Key::Fn as DeriveKey;
15
16pub async fn Fn(Arguments:Vec<Value>) -> Result<Value, String> {
17	let Ciphertext = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
18
19	if Ciphertext.is_empty() {
20		return Ok(json!(""));
21	}
22
23	let Blob = match B64.decode(&Ciphertext) {
24		Ok(B) => B,
25
26		Err(_) => {
27			dev_log!("encryption", "warn: encryption:decrypt invalid base64 - returning empty");
28
29			return Ok(json!(""));
30		},
31	};
32
33	// Minimum: 12 (nonce) + 16 (GCM tag) = 28 bytes
34	if Blob.len() < 28 {
35		dev_log!("encryption", "warn: encryption:decrypt blob too short ({} bytes)", Blob.len());
36
37		return Ok(json!(""));
38	}
39
40	let KeyBytes = DeriveKey().map_err(|E| format!("encryption:decrypt unavailable - {E}"))?;
41
42	let UnboundK = match UnboundKey::new(&AES_256_GCM, &KeyBytes) {
43		Ok(K) => K,
44
45		Err(_) => return Ok(json!("")),
46	};
47
48	let Key = LessSafeKey::new(UnboundK);
49
50	let NonceBytes:[u8; 12] = Blob[..12].try_into().unwrap();
51
52	let NonceVal = Nonce::assume_unique_for_key(NonceBytes);
53
54	let mut Data = Blob[12..].to_vec();
55
56	match Key.open_in_place(NonceVal, Aad::empty(), &mut Data) {
57		Ok(Plaintext) => {
58			let S = String::from_utf8_lossy(Plaintext).into_owned();
59
60			dev_log!("encryption", "encryption:decrypt ok ({} bytes)", S.len());
61
62			Ok(json!(S))
63		},
64
65		Err(_) => {
66			dev_log!(
67				"encryption",
68				"warn: encryption:decrypt open_in_place failed (wrong key or corrupt)"
69			);
70
71			Ok(json!(""))
72		},
73	}
74}