1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crateResult;
use crateDecryptError;
use ArmoredReader;
use SecretString;
use Read;
/// Decrypts an **armor‑encoded** age ciphertext that was encrypted with a
/// passphrase.
///
/// This function is the armored counterpart to
/// [`decrypt_with_passphrase`]. It accepts a PEM‑like string (the kind
/// produced by `age -p -a` or [`encrypt_with_passphrase_armor`]) together
/// with the correct passphrase, and returns the original plaintext.
///
/// Internally, the passphrase is moved into a [`SecretString`] and used to
/// derive an scrypt identity. The armored wrapper is stripped by an
/// [`ArmoredReader`], after which decryption proceeds exactly like the
/// binary passphrase path.
///
/// # Parameters
///
/// * `armored` – The complete armored age ciphertext, including the
/// `-----BEGIN AGE ENCRYPTED FILE-----` and `-----END AGE ENCRYPTED FILE-----`
/// markers.
/// * `passphrase` – The passphrase that was used to encrypt the data.
///
/// # Returns
///
/// * `Ok(Vec<u8>)` – The decrypted plaintext bytes.
/// * `Err(Error::Decrypt(...))` – If the armored data is malformed, the
/// passphrase is wrong, the data has been tampered with, or an internal
/// I/O error occurs.
///
/// # Errors
///
/// | Condition | Error Variant |
/// |-------------------------------------------------------------|----------------------------------------|
/// | Armored text does not contain a valid age ciphertext | [`DecryptError::InvalidCiphertext`] |
/// | Passphrase does not match or data has been tampered | [`DecryptError::Failed`] |
/// | I/O error while reading the armored stream (extremely rare) | [`DecryptError::Io`] |
///
/// # Security Considerations
///
/// * **AEAD** – The underlying age encryption is authenticated. Any
/// modification to the armored text (including whitespace) will cause
/// decryption to fail.
/// * **scrypt KDF** – The passphrase is used to derive a symmetric key
/// via scrypt, which makes brute‑force attacks computationally
/// expensive. However, weak passphrases remain vulnerable – always use
/// a long, high‑entropy passphrase.
/// * **Passphrase handling** – The passphrase is immediately moved into
/// a `SecretString` and zeroized after use. The caller’s original
/// `&str` is left untouched; avoid logging or persisting it.
/// * **Armor is not encryption** – The armor encoding adds no extra
/// secrecy; it simply encodes the ciphertext in a text‑safe format.
/// * **Memory** – The entire plaintext is returned as a single `Vec<u8>`.
/// For very large files, consider streaming decryption directly with the
/// `age` crate to avoid high memory usage.
///
/// # Example
///
/// ```rust
/// # fn main() -> age_crypto::errors::Result<()> {
/// let plaintext = b"Confidential message";
/// let pass = "correct horse battery staple";
///
/// // Encrypt with armor
/// let armored = age_crypto::encrypt_with_passphrase_armor(plaintext, pass)?;
/// assert!(armored.starts_with("-----BEGIN AGE ENCRYPTED FILE-----"));
///
/// // Decrypt the armored output
/// let decrypted = age_crypto::decrypt_with_passphrase_armor(&armored, pass)?;
/// assert_eq!(decrypted, plaintext);
/// # Ok(())
/// # }
/// ```
///
/// # See Also
///
/// * [`decrypt_with_passphrase`] – binary (non‑armored) variant.
/// * [`decrypt_armor`] – key‑based armored decryption.
/// * [`encrypt_with_passphrase_armor`] – the encryption counterpart.