tinyhumansai/openhuman · error · anyhow::Error
Decryption failed — wrong key or tampered data
Error message
Decryption failed — wrong key or tampered data
What it means
ChaCha20-Poly1305 authentication of the ciphertext failed during decryption. The AEAD tag did not verify, which means the master key does not match the one used to encrypt (key regenerated, different user/machine) or the ciphertext was tampered with/corrupted. There is no recovery path from this error for the data itself.
Source
Thrown at src/openhuman/security/keyring/encrypted_store.rs:160
/// Decrypt using ChaCha20-Poly1305 (current secure format).
fn decrypt_chacha20(&self, hex_str: &str) -> Result<String> {
let blob =
hex_decode(hex_str).context("Failed to decode encrypted secret (corrupt hex)")?;
anyhow::ensure!(
blob.len() > NONCE_LEN,
"Encrypted value too short (missing nonce)"
);
let (nonce_bytes, ciphertext) = blob.split_at(NONCE_LEN);
let nonce = Nonce::from_slice(nonce_bytes);
let key_bytes = self.load_or_create_key()?;
let key = Key::from_slice(&key_bytes);
let cipher = ChaCha20Poly1305::new(key);
let plaintext_bytes = cipher
.decrypt(nonce, ciphertext)
.map_err(|_| anyhow::anyhow!("Decryption failed — wrong key or tampered data"))?;
String::from_utf8(plaintext_bytes)
.context("Decrypted secret is not valid UTF-8 — corrupt data")
}
/// Decrypt using legacy XOR cipher (insecure, for backward compatibility only).
///
/// This is the single choke-point for the insecure `enc:` format, so it logs
/// a loud security warning every time it runs. The repeating-key XOR is
/// unauthenticated and leaks the master key to anyone who knows (or can guess
/// the structure of) the plaintext — e.g. `xoxb-`/`sk-` token prefixes give
/// `key[i] = ct[i] XOR pt[i]`. Callers on the read path should prefer
/// [`decrypt_and_migrate`](Self::decrypt_and_migrate) so the value is rewritten
/// to `enc2:` and the legacy ciphertext stops persisting on disk.
fn decrypt_legacy_xor(&self, hex_str: &str) -> Result<String> {
log::warn!(
"[security] decrypting legacy XOR-encrypted secret (enc: prefix). \
This format is INSECURE (unauthenticated repeating-key XOR; known-plaintext \View on GitHub (pinned to 7491200858)
Solutions
- Verify the master key matches the one used at encryption time (key file/keychain restored?)
- Check for workspace or user-id changes that switch key identity
- If the key is genuinely lost, re-enter the secrets — the data is unrecoverable by design
- Audit for tampering if key identity is confirmed correct
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at src/openhuman/security/keyring/encrypted_store.rs:160 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/afdb26bd801be857.
Report an issue: GitHub.