]> git.proxmox.com Git - proxmox-backup.git/blob - pbs-tools/src/crypt.rs
move token_shadow to pbs_config workspace
[proxmox-backup.git] / pbs-tools / src / crypt.rs
1 use std::ffi::CStr;
2
3 use anyhow::{bail, Error};
4
5 // from libcrypt1, 'lib/crypt.h.in'
6 const CRYPT_OUTPUT_SIZE: usize = 384;
7 const CRYPT_MAX_PASSPHRASE_SIZE: usize = 512;
8 const CRYPT_DATA_RESERVED_SIZE: usize = 767;
9 const CRYPT_DATA_INTERNAL_SIZE: usize = 30720;
10
11 #[repr(C)]
12 struct crypt_data {
13 output: [libc::c_char; CRYPT_OUTPUT_SIZE],
14 setting: [libc::c_char; CRYPT_OUTPUT_SIZE],
15 input: [libc::c_char; CRYPT_MAX_PASSPHRASE_SIZE],
16 reserved: [libc::c_char; CRYPT_DATA_RESERVED_SIZE],
17 initialized: libc::c_char,
18 internal: [libc::c_char; CRYPT_DATA_INTERNAL_SIZE],
19 }
20
21 pub fn crypt(password: &[u8], salt: &[u8]) -> Result<String, Error> {
22 #[link(name = "crypt")]
23 extern "C" {
24 #[link_name = "crypt_r"]
25 fn __crypt_r(
26 key: *const libc::c_char,
27 salt: *const libc::c_char,
28 data: *mut crypt_data,
29 ) -> *mut libc::c_char;
30 }
31
32 let mut data: crypt_data = unsafe { std::mem::zeroed() };
33 for (i, c) in salt.iter().take(data.setting.len() - 1).enumerate() {
34 data.setting[i] = *c as libc::c_char;
35 }
36 for (i, c) in password.iter().take(data.input.len() - 1).enumerate() {
37 data.input[i] = *c as libc::c_char;
38 }
39
40 let res = unsafe {
41 let status = __crypt_r(
42 &data.input as *const _,
43 &data.setting as *const _,
44 &mut data as *mut _,
45 );
46 if status.is_null() {
47 bail!("internal error: crypt_r returned null pointer");
48 }
49 CStr::from_ptr(&data.output as *const _)
50 };
51 Ok(String::from(res.to_str()?))
52 }
53
54 pub fn encrypt_pw(password: &str) -> Result<String, Error> {
55
56 let salt = proxmox::sys::linux::random_data(8)?;
57 let salt = format!("$5${}$", base64::encode_config(&salt, base64::CRYPT));
58
59 crypt(password.as_bytes(), salt.as_bytes())
60 }
61
62 pub fn verify_crypt_pw(password: &str, enc_password: &str) -> Result<(), Error> {
63 let verify = crypt(password.as_bytes(), enc_password.as_bytes())?;
64 if verify != enc_password {
65 bail!("invalid credentials");
66 }
67 Ok(())
68 }