]>
Commit | Line | Data |
---|---|---|
1cb08a0a DM |
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 | } |