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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Error types for secure_data.
use thiserror::Error;
/// Errors produced by `secure_data` operations.
///
/// # Examples
///
/// ```
/// use secure_data::error::DataError;
///
/// let err = DataError::KeyNotFound { alias: "missing".into() };
/// assert!(err.to_string().contains("missing"));
/// ```
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum DataError {
/// The key with the given alias was not found.
#[error("key not found: {alias}")]
KeyNotFound {
/// The key alias that was not found.
alias: String,
},
/// The key version is not available for the requested operation.
#[error("key version unavailable: alias={alias}, version={version}")]
KeyVersionUnavailable {
/// The key alias.
alias: String,
/// The key version identifier.
version: String,
},
/// The key version has been deactivated and cannot be used for decryption.
#[error("key deactivated: alias={alias}, version={version}")]
KeyDeactivated {
/// The key alias.
alias: String,
/// The key version identifier.
version: String,
},
/// AEAD authentication failed — ciphertext or AAD was tampered.
#[error("authentication failure: ciphertext or AAD was tampered")]
AuthenticationFailure,
/// Encryption operation failed.
#[error("encryption failed: {reason}")]
EncryptionFailed {
/// Human-readable reason for the failure.
reason: String,
},
/// Decryption operation failed.
#[error("decryption failed: {reason}")]
DecryptionFailed {
/// Human-readable reason for the failure.
reason: String,
},
/// Invalid nonce length.
#[error("invalid nonce length: expected {expected}, got {actual}")]
InvalidNonce {
/// Expected nonce length.
expected: usize,
/// Actual nonce length received.
actual: usize,
},
/// Cannot deactivate the last remaining active/decrypt-only key version.
#[error("cannot deactivate last key version for alias={alias}")]
CannotDeactivateLastVersion {
/// The key alias.
alias: String,
},
/// The key ring does not contain the given alias.
#[error("unknown key alias: {alias}")]
UnknownAlias {
/// The key alias that was not found.
alias: String,
},
/// Secret reference parsing error.
#[error("invalid secret reference: {input}")]
InvalidSecretReference {
/// The input string that could not be parsed.
input: String,
},
/// A wrapped key had an unexpected length.
#[error("wrapped key length mismatch")]
WrappedKeyLengthMismatch,
/// A key provider was unreachable or returned an unexpected error.
#[error("provider unavailable: provider={provider}, reason={reason}")]
ProviderUnavailable {
/// The provider that was unavailable (e.g. "vault", "aws-kms").
provider: String,
/// Human-readable reason for the failure.
reason: String,
},
/// A key provider rejected the request due to an authentication error.
#[error("provider auth error: provider={provider}, reason={reason}")]
ProviderAuthError {
/// The provider that returned the auth error.
provider: String,
/// Human-readable reason for the failure.
reason: String,
},
/// A secret reference could not be resolved because the secret does not exist.
#[error("secret not found: {reference}")]
SecretNotFound {
/// The secret reference that was not found.
reference: String,
},
/// The algorithm specified in an encrypted envelope is not supported.
#[error("unsupported algorithm: {algorithm}")]
UnsupportedAlgorithm {
/// The algorithm identifier that was not recognized.
algorithm: String,
},
/// The requested algorithm is below the policy minimum.
#[error("algorithm below policy minimum: requested={requested}, minimum={minimum}")]
AlgorithmBelowPolicyMinimum {
/// The algorithm that was requested.
requested: String,
/// The minimum algorithm required by policy.
minimum: String,
},
/// A post-quantum operation was requested but the `pq` feature is not
/// compiled into this build.
///
/// Emitted when `CryptoAlgorithm::HybridX25519MlKem768` is selected on a
/// build without `--features pq`. The `pq` feature gates the optional
/// dependencies (`ml-kem`, `x25519-dalek`, `hkdf`, `sha2`); without them
/// the encrypt/decrypt path cannot construct the hybrid KEM. There is no
/// silent fallback to a classical algorithm — see
/// `docs/slo/design/pq-migration-plan.md` for the rationale.
#[error("post-quantum unavailable: rebuild with `--features pq`")]
PqUnavailable,
/// A post-quantum envelope (carrying a `combiner_id`) was decoded on a
/// build without `--features pq`.
///
/// Distinct from `PqUnavailable` (encrypt-side request) — this variant is
/// the decrypt-side counterpart, returned when a v2 hybrid envelope is
/// presented to a non-PQ build. Never silently downgrades to a classical
/// algorithm.
#[error("post-quantum feature required: this envelope was produced with the `pq` feature; rebuild with `--features pq` to decrypt")]
PqFeatureRequired,
/// An envelope was rejected by an `AlgorithmPolicy` constraint that the
/// existing `AlgorithmBelowPolicyMinimum` variant does not capture (e.g.,
/// a wire-format-version policy that requires v2-or-higher envelopes).
///
/// Distinct from `AlgorithmBelowPolicyMinimum`: that variant is about the
/// rank of the AEAD algorithm. This variant is about higher-level policy
/// decisions like minimum envelope version or required combiner.
#[error("algorithm rejected by policy: {reason}")]
AlgorithmRejectedByPolicy {
/// Human-readable reason — must not include sensitive material.
reason: String,
},
/// An envelope failed structural validation before any cryptographic
/// operation was attempted.
///
/// Examples: a v1 envelope (classical AEAD) carrying a `combiner_id`
/// field; an envelope with internally inconsistent metadata. Returned
/// from the deserialize / validate boundary, not from the AEAD path.
#[error("envelope malformed: {reason}")]
EnvelopeMalformed {
/// Human-readable reason — must not include the malformed bytes.
reason: String,
},
}