1use std::io::{Read, Write};
2
3use age::secrecy::ExposeSecret;
4use hkdf::Hkdf;
5use sha2::Sha256;
6
7use crate::error::{AuthyError, Result};
8
9pub fn encrypt_with_passphrase(plaintext: &[u8], passphrase: &str) -> Result<Vec<u8>> {
11 let encryptor = age::Encryptor::with_user_passphrase(
12 age::secrecy::Secret::new(passphrase.to_string()),
13 );
14
15 let mut encrypted = vec![];
16 let mut writer = encryptor
17 .wrap_output(&mut encrypted)
18 .map_err(|e| AuthyError::Encryption(e.to_string()))?;
19 writer
20 .write_all(plaintext)
21 .map_err(|e| AuthyError::Encryption(e.to_string()))?;
22 writer
23 .finish()
24 .map_err(|e| AuthyError::Encryption(e.to_string()))?;
25
26 Ok(encrypted)
27}
28
29pub fn decrypt_with_passphrase(ciphertext: &[u8], passphrase: &str) -> Result<Vec<u8>> {
31 let decryptor = match age::Decryptor::new(ciphertext)
32 .map_err(|e| AuthyError::Decryption(e.to_string()))?
33 {
34 age::Decryptor::Passphrase(d) => d,
35 _ => return Err(AuthyError::Decryption("Expected passphrase-encrypted data".into())),
36 };
37
38 let mut decrypted = vec![];
39 let mut reader = decryptor
40 .decrypt(
41 &age::secrecy::Secret::new(passphrase.to_string()),
42 None,
43 )
44 .map_err(|e| AuthyError::Decryption(e.to_string()))?;
45 reader
46 .read_to_end(&mut decrypted)
47 .map_err(|e| AuthyError::Decryption(e.to_string()))?;
48
49 Ok(decrypted)
50}
51
52pub fn encrypt_with_keyfile(plaintext: &[u8], pubkey: &str) -> Result<Vec<u8>> {
54 let recipient: age::x25519::Recipient = pubkey
55 .parse()
56 .map_err(|e: &str| AuthyError::Encryption(e.to_string()))?;
57
58 let encryptor = age::Encryptor::with_recipients(vec![Box::new(recipient)])
59 .expect("recipients not empty");
60
61 let mut encrypted = vec![];
62 let mut writer = encryptor
63 .wrap_output(&mut encrypted)
64 .map_err(|e| AuthyError::Encryption(e.to_string()))?;
65 writer
66 .write_all(plaintext)
67 .map_err(|e| AuthyError::Encryption(e.to_string()))?;
68 writer
69 .finish()
70 .map_err(|e| AuthyError::Encryption(e.to_string()))?;
71
72 Ok(encrypted)
73}
74
75pub fn decrypt_with_keyfile(ciphertext: &[u8], identity_str: &str) -> Result<Vec<u8>> {
77 let identity: age::x25519::Identity = identity_str
78 .parse()
79 .map_err(|e: &str| AuthyError::InvalidKeyfile(e.to_string()))?;
80
81 let decryptor = match age::Decryptor::new(ciphertext)
82 .map_err(|e| AuthyError::Decryption(e.to_string()))?
83 {
84 age::Decryptor::Recipients(d) => d,
85 _ => return Err(AuthyError::Decryption("Expected recipients-encrypted data".into())),
86 };
87
88 let mut decrypted = vec![];
89 let mut reader = decryptor
90 .decrypt(std::iter::once(&identity as &dyn age::Identity))
91 .map_err(|e| AuthyError::Decryption(e.to_string()))?;
92 reader
93 .read_to_end(&mut decrypted)
94 .map_err(|e| AuthyError::Decryption(e.to_string()))?;
95
96 Ok(decrypted)
97}
98
99pub fn derive_key(master: &[u8], info: &[u8], output_len: usize) -> Vec<u8> {
101 let hk = Hkdf::<Sha256>::new(None, master);
102 let mut okm = vec![0u8; output_len];
103 hk.expand(info, &mut okm)
104 .expect("HKDF output length too large");
105 okm
106}
107
108pub fn generate_keypair() -> (String, String) {
110 let identity = age::x25519::Identity::generate();
111 let secret_key = identity.to_string();
112 let public_key = identity.to_public().to_string();
113 (secret_key.expose_secret().clone(), public_key)
114}