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
97
98
99
100
101
102
103
use crateparse_identity;
use crateResult;
use crateDecryptError;
use ArmoredReader;
use Read;
/// Decrypts an **armor‑encoded** age ciphertext using a secret key.
///
/// # Overview
///
/// This function is the armored counterpart to [`decrypt`]. It takes a
/// PEM‑like string (with `-----BEGIN AGE ENCRYPTED FILE-----` markers)
/// and a secret key, and returns the original plaintext.
///
/// The armored format is defined by the age specification and is
/// identical to the output of the official CLI tool when using the `-a`
/// flag.
///
/// # Parameters
///
/// - `armored`: A string slice containing the complete armored age
/// ciphertext, including `BEGIN` and `END` lines.
/// - `secret_key`: The recipient’s secret key in age format
/// (`AGE-SECRET-KEY-1...`).
///
/// # Returns
///
/// - `Ok(Vec<u8>)` – the decrypted plaintext bytes.
/// - `Err(Error::Decrypt(...))` – if any step fails (see [Errors](#errors)).
///
/// # Errors
///
/// | Condition | Error Variant |
/// |-----------|---------------|
/// | `secret_key` is malformed or not a valid X25519 identity | [`DecryptError::InvalidIdentity`] |
/// | The armored string does not contain a valid age ciphertext | [`DecryptError::InvalidCiphertext`] |
/// | The key does not match the ciphertext or data is tampered | [`DecryptError::Failed`] |
/// | An I/O error occurs while reading the armored stream (extremely rare) | [`DecryptError::Io`] |
///
/// All error variants are automatically converted to the crate‑level
/// [`Error`](crate::errors::Error) by the `?` operator, so callers can
/// match on the outer `Error` or on the inner `DecryptError` as needed.
///
/// # Panics
///
/// **No.** This function never panics; every failure is returned as
/// `Err`.
///
/// # Security Notes
///
/// - Authenticated Encryption – any modification to the armored
/// text will cause decryption to fail.
/// - Armor is not encryption – the armor is only a base64
/// encoding; the cryptographic security comes from the age ciphertext
/// embedded within.
/// - Memory – the entire plaintext is loaded into a `Vec<u8>`.
/// For very large files, consider streaming the decryption using the
/// underlying `age` API directly.
/// - Secret key exposure – the `secret_key` is used only for
/// identity derivation; it is not stored or logged. However, callers
/// should still treat the key string as sensitive and avoid
/// unnecessary copies.
///
/// # Example
///
/// ```
/// use age_crypto::decrypt_armor;
/// use age_setup::build_keypair;
///
/// # fn main() -> age_crypto::errors::Result<()> {
/// // Generate a key pair
/// let keypair = build_keypair().expect("key generation failed");
/// let pubkey = keypair.public.expose(); // "age1..."
/// let secret = keypair.secret.expose(); // "AGE-SECRET-KEY-1..."
///
/// // Encrypt some data into armored form
/// let plaintext = b"Confidential document";
/// let armored = age_crypto::encrypt_armor(plaintext, &[pubkey])?;
///
/// // Decrypt the armor using the secret key
/// let decrypted = decrypt_armor(&armored, secret)?;
/// assert_eq!(decrypted, plaintext);
/// # Ok(())
/// # }
/// ```
///
/// # See Also
///
/// - [`decrypt`] – decryption of binary (non‑armored) ciphertext.
/// - [`decrypt_with_passphrase_armor`] – passphrase‑based armored decryption.