]> git.proxmox.com Git - proxmox-backup.git/blame - pbs-tools/src/crypt.rs
use proxmox::tools::fd::fd_change_cloexec from proxmox 0.15.3
[proxmox-backup.git] / pbs-tools / src / crypt.rs
CommitLineData
1cb08a0a
DM
1use std::ffi::CStr;
2
3use anyhow::{bail, Error};
4
5// from libcrypt1, 'lib/crypt.h.in'
6const CRYPT_OUTPUT_SIZE: usize = 384;
7const CRYPT_MAX_PASSPHRASE_SIZE: usize = 512;
8const CRYPT_DATA_RESERVED_SIZE: usize = 767;
9const CRYPT_DATA_INTERNAL_SIZE: usize = 30720;
10
11#[repr(C)]
12struct 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
21pub 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
54pub 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
62pub 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}