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
//! Cryptographic utilities for key derivation and secret key encryption.
//!
//! This module provides functions to derive a Key Encryption Key (KEK) from a master
//! password using Argon2, and to encrypt/decrypt Age secret keys using that KEK.
use crate;
use SaltString;
use ;
use SecretString;
/// Derives a Key Encryption Key (KEK) from a master password and a salt.
///
/// The function uses Argon2id with default parameters to hash the master password,
/// producing a string that can be used as a KEK. The returned `SecretString` is
/// zeroized on drop for security.
///
/// # Parameters
///
/// * `master_password` - The master password (UTF-8 string).
/// * `salt_bytes` - Cryptographic salt (16 bytes recommended).
///
/// # Returns
///
/// A `SecretString` containing the derived KEK.
///
/// # Errors
///
/// Returns [`Error::Kdf`] if the salt encoding or hashing fails.
///
/// # Panics
///
/// This function does not panic.
///
/// # Examples
///
/// ```
/// use age_vault::crypto::derive_kek;
/// # use age_vault::Error;
/// # fn main() -> Result<(), Error> {
/// let password = "my password";
/// let salt = b"0123456789abcdef"; // 16 bytes
/// let kek = derive_kek(password, salt)?;
/// # Ok(())
/// # }
/// ```
/// Encrypts an Age secret key using a KEK.
///
/// The secret key is encrypted with the KEK using age's passphrase-based encryption.
/// The result is a byte vector that can be stored securely.
///
/// # Parameters
///
/// * `secret_key` - The plaintext Age secret key string.
/// * `kek` - The Key Encryption Key (as a string slice, e.g., derived from `derive_kek`).
///
/// # Returns
///
/// Encrypted ciphertext as `Vec<u8>`.
///
/// # Errors
///
/// Returns [`Error::Crypto`] if the underlying age encryption fails.
///
/// # Panics
///
/// This function does not panic.
///
/// # Examples
///
/// ```
/// use secrecy::ExposeSecret;
/// use age_vault::crypto::{derive_kek, encrypt_secret_key};
/// # use age_vault::Error;
/// # fn main() -> Result<(), Error> {
/// let password = "master";
/// let salt = b"0123456789abcdef";
/// let kek = derive_kek(password, salt)?;
/// let secret_key = "AGE-SECRET-KEY-...";
/// let encrypted = encrypt_secret_key(secret_key, kek.expose_secret())?;
/// # Ok(())
/// # }
/// ```
/// Decrypts an encrypted Age secret key using a KEK.
///
/// Reverses `encrypt_secret_key`. The returned plaintext is a UTF-8 string.
///
/// # Parameters
///
/// * `encrypted` - The encrypted secret key bytes.
/// * `kek` - The Key Encryption Key (same as used for encryption).
///
/// # Returns
///
/// The decrypted secret key as a `String`.
///
/// # Errors
///
/// Returns [`Error::Crypto`] if decryption fails (wrong KEK or corrupted data).
/// Returns [`Error::DecryptionFailed`] if the decrypted data is not valid UTF-8.
///
/// # Panics
///
/// This function does not panic.
///
/// # Examples
///
/// ```
/// use secrecy::ExposeSecret;
/// use age_vault::crypto::{derive_kek, encrypt_secret_key, decrypt_secret_key};
/// # use age_vault::Error;
/// # fn main() -> Result<(), Error> {
/// let password = "master";
/// let salt = b"0123456789abcdef";
/// let kek = derive_kek(password, salt)?;
/// let original = "AGE-SECRET-KEY-...";
/// let encrypted = encrypt_secret_key(original, kek.expose_secret())?;
/// let decrypted = decrypt_secret_key(&encrypted, kek.expose_secret())?;
/// assert_eq!(original, decrypted);
/// # Ok(())
/// # }
/// ```