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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! Age secret key type.
//!
//! This module provides the [`SecretKey`] type, a validated, memory‑safe
//! wrapper around an age secret key string (starting with `AGE-SECRET-KEY-1`).
//! The type is the private half of an [`KeyPair`](crate::KeyPair) and is
//! designed to keep the secret confidential:
//!
//! - It uses [`zeroize::Zeroizing`] internally to overwrite memory on drop.
//! - Its [`Display`] and [`Debug`] implementations intentionally redact the
//! key material, printing `[REDACTED]` instead.
//!
//! # Accessing the secret
//!
//! To obtain the raw key string (e.g., for writing to a file or passing to
//! an age encryption function), call [`expose_secret`](SecretKey::expose_secret).
//! Do so **only when necessary** and ensure the returned reference is not
//! copied, logged, or leaked accidentally.
use crate;
use fmt;
use Zeroizing;
/// A validated age secret key protected by memory zeroization.
///
/// `SecretKey` wraps the raw key string inside [`Zeroizing`], which guarantees
/// that the memory is securely erased when the value is dropped. This prevents
/// secrets from lingering in memory dumps or swap files.
///
/// # Validation
///
/// The key is validated at construction time via [`new`](SecretKey::new):
/// - It must be non‑empty.
/// - It must start with the string `AGE-SECRET-KEY-1` (case‑sensitive).
///
/// # Security properties
///
/// - **Redacted display** – `Display` and `Debug` print `[REDACTED]`, never
/// the actual key.
/// - **Zeroization on drop** – memory is overwritten with zeros when the
/// `SecretKey` (or any clone) is dropped.
/// - **Cloneable** – cloning creates a new independent `Zeroizing` copy that
/// is also zeroized separately.
///
/// # Examples
///
/// ```rust
/// use age_setup::SecretKey;
///
/// let sk = SecretKey::new("AGE-SECRET-KEY-1mytestkey".into())?;
/// println!("{}", sk); // prints: [REDACTED]
/// println!("{:?}", sk); // prints: SecretKey { ... [REDACTED] ... }
/// let raw = sk.expose_secret(); // careful: raw secret exposed
/// # Ok::<(), age_setup::Error>(())
/// ```
/// The `Debug` implementation records the secret value as `[REDACTED]` to
/// prevent accidental leakage through debug output.
/// The `Display` implementation always writes `[REDACTED]`, never the actual
/// key. Use [`expose_secret`](SecretKey::expose_secret) if you need the raw
/// string.