gaussdb_protocol/authentication/
mod.rs1use hmac::{Hmac, Mac};
3use md5::{Digest, Md5};
4use pbkdf2::pbkdf2_hmac;
5use sha1::Sha1;
6use sha2::Sha256;
7
8pub mod sasl;
9
10#[inline]
16pub fn md5_hash(username: &[u8], password: &[u8], salt: [u8; 4]) -> String {
17 let mut md5 = Md5::new();
18 md5.update(password);
19 md5.update(username);
20 let output = md5.finalize_reset();
21 md5.update(format!("{:x}", output));
22 md5.update(salt);
23 format!("md5{:x}", md5.finalize())
24}
25
26#[inline]
31pub fn sha256_hash(username: &[u8], password: &[u8], salt: &[u8]) -> String {
32 let mut md5 = Md5::new();
34 md5.update(password);
35 md5.update(username);
36 let md5_result = md5.finalize();
37 let md5_hex = format!("{:x}", md5_result);
38
39 let mut sha256 = Sha256::new();
41 sha256.update(md5_hex.as_bytes());
42 sha256.update(salt);
43 let sha256_result = sha256.finalize();
44
45 format!("sha256{:x}", sha256_result)
46}
47
48#[inline]
53pub fn md5_sha256_hash(password: &str, random_code: &str, salt: &[u8]) -> String {
54 let random_bytes = hex::decode(random_code).unwrap_or_else(|_| random_code.as_bytes().to_vec());
56 let mut k = [0u8; 32];
57 pbkdf2_hmac::<Sha1>(password.as_bytes(), &random_bytes, 2048, &mut k);
58
59 let mut server_key_mac =
61 Hmac::<Sha256>::new_from_slice(&k).expect("HMAC can take key of any size");
62 server_key_mac.update(b"Sever Key"); let server_key = server_key_mac.finalize().into_bytes();
64
65 let mut client_key_mac =
66 Hmac::<Sha256>::new_from_slice(&k).expect("HMAC can take key of any size");
67 client_key_mac.update(b"Client Key");
68 let client_key = client_key_mac.finalize().into_bytes();
69
70 let mut sha256 = Sha256::new();
72 sha256.update(client_key);
73 let stored_key = sha256.finalize();
74
75 let encrypt_string = format!(
77 "{}{}{}",
78 random_code,
79 hex::encode(server_key),
80 hex::encode(stored_key)
81 );
82
83 let mut md5 = Md5::new();
85 md5.update(encrypt_string.as_bytes());
86 md5.update(salt);
87 let md5_result = md5.finalize();
88
89 format!("md5{:x}", md5_result)
90}
91
92#[cfg(test)]
93mod test {
94 use super::*;
95
96 #[test]
97 fn md5() {
98 let username = b"md5_user";
99 let password = b"password";
100 let salt = [0x2a, 0x3d, 0x8f, 0xe0];
101
102 assert_eq!(
103 md5_hash(username, password, salt),
104 "md562af4dd09bbb41884907a838a3233294"
105 );
106 }
107
108 #[test]
109 fn sha256() {
110 let username = b"testuser";
111 let password = b"testpass";
112 let salt = b"salt1234";
113 let result = sha256_hash(username, password, salt);
114 assert!(result.starts_with("sha256"));
115 assert_eq!(result.len(), 70); }
117
118 #[test]
119 fn md5_sha256() {
120 let password = "Gaussdb@123";
121 let random_code = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
122 let salt = b"randomsalt";
123 let result = md5_sha256_hash(password, random_code, salt);
124 assert!(result.starts_with("md5"));
125 assert_eq!(result.len(), 35); let result2 = md5_sha256_hash(password, random_code, salt);
129 assert_eq!(result, result2);
130 }
131
132 #[test]
133 fn gaussdb_authentication_compatibility() {
134 let test_cases: Vec<(&str, &str, &[u8])> = vec![
136 ("omm", "Enmo@123", b"salt"),
137 ("gaussdb", "Gaussdb@123", b"test_salt"),
138 ("postgres_user", "password", b"random_salt"),
139 ];
140
141 for (username, password, salt) in test_cases {
142 let sha256_result = sha256_hash(username.as_bytes(), password.as_bytes(), salt);
143 let random_code = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
144 let md5_sha256_result = md5_sha256_hash(password, random_code, salt);
145
146 assert!(sha256_result.starts_with("sha256"));
148 assert!(md5_sha256_result.starts_with("md5"));
149 assert_eq!(sha256_result.len(), 70);
150 assert_eq!(md5_sha256_result.len(), 35);
151
152 assert_ne!(sha256_result, md5_sha256_result);
154 }
155 }
156}