kanidm_lib_crypto/
crypt_md5.rs
1use md5::{Digest, Md5};
2use std::cmp::min;
3
4const MD5_MAGIC: &str = "$1$";
6const MD5_TRANSPOSE: &[u8] = b"\x0c\x06\x00\x0d\x07\x01\x0e\x08\x02\x0f\x09\x03\x05\x0a\x04\x0b";
7
8const CRYPT_HASH64: &[u8] = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
9
10pub fn md5_sha2_hash64_encode(bs: &[u8]) -> String {
11 let ngroups = bs.len().div_ceil(3);
12 let mut out = String::with_capacity(ngroups * 4);
13 for g in 0..ngroups {
14 let mut g_idx = g * 3;
15 let mut enc = 0u32;
16 for _ in 0..3 {
17 let b = (if g_idx < bs.len() { bs[g_idx] } else { 0 }) as u32;
18 enc >>= 8;
19 enc |= b << 16;
20 g_idx += 1;
21 }
22 for _ in 0..4 {
23 out.push(char::from_u32(CRYPT_HASH64[(enc & 0x3F) as usize] as u32).unwrap_or('!'));
24 enc >>= 6;
25 }
26 }
27 match bs.len() % 3 {
28 1 => {
29 out.pop();
30 out.pop();
31 }
32 2 => {
33 out.pop();
34 }
35 _ => (),
36 }
37 out
38}
39
40pub fn do_md5_crypt(pass: &[u8], salt: &[u8]) -> Vec<u8> {
41 let mut dgst_b = Md5::new();
42 dgst_b.update(pass);
43 dgst_b.update(salt);
44 dgst_b.update(pass);
45 let mut hash_b = dgst_b.finalize();
46
47 let mut dgst_a = Md5::new();
48 dgst_a.update(pass);
49 dgst_a.update(MD5_MAGIC.as_bytes());
50 dgst_a.update(salt);
51
52 let mut plen = pass.len();
53 while plen > 0 {
54 dgst_a.update(&hash_b[..min(plen, 16)]);
55 if plen < 16 {
56 break;
57 }
58 plen -= 16;
59 }
60
61 plen = pass.len();
62 while plen > 0 {
63 if plen & 1 == 0 {
64 dgst_a.update(&pass[..1])
65 } else {
66 dgst_a.update([0u8])
67 }
68 plen >>= 1;
69 }
70
71 let mut hash_a = dgst_a.finalize();
72
73 for r in 0..1000 {
74 let mut dgst_a = Md5::new();
75 if r % 2 == 1 {
76 dgst_a.update(pass);
77 } else {
78 dgst_a.update(hash_a);
79 }
80 if r % 3 > 0 {
81 dgst_a.update(salt);
82 }
83 if r % 7 > 0 {
84 dgst_a.update(pass);
85 }
86 if r % 2 == 0 {
87 dgst_a.update(pass);
88 } else {
89 dgst_a.update(hash_a);
90 }
91 hash_a = dgst_a.finalize();
92 }
93
94 for (i, &ti) in MD5_TRANSPOSE.iter().enumerate() {
95 hash_b[i] = hash_a[ti as usize];
96 }
97
98 md5_sha2_hash64_encode(&hash_b).into_bytes()
99}