mysql_connector/utils/
scramble.rs

1use sha1::{Digest, Sha1};
2
3fn xor<T, U>(mut left: T, right: U) -> T
4where
5    T: AsMut<[u8]>,
6    U: AsRef<[u8]>,
7{
8    for (l, r) in left.as_mut().iter_mut().zip(right.as_ref().iter()) {
9        *l ^= r;
10    }
11    left
12}
13
14/// SHA1(password) XOR SHA1(nonce, SHA1(SHA1(password)))
15pub fn scramble_native(nonce: &[u8], password: &[u8]) -> Option<[u8; 20]> {
16    if password.is_empty() {
17        return None;
18    }
19
20    fn sha1<T: AsRef<[u8]>>(bytes: &[T]) -> [u8; 20] {
21        let mut hasher = Sha1::new();
22        for bytes in bytes {
23            hasher.update(bytes);
24        }
25        hasher.finalize().into()
26    }
27
28    Some(xor(
29        sha1(&[password]),
30        sha1(&[nonce, &sha1(&[sha1(&[password])])]),
31    ))
32}
33
34/// SHA256(password) XOR SHA256(SHA256(SHA256(password)), nonce)
35#[cfg(feature = "caching-sha2-password")]
36#[cfg_attr(doc, doc(cfg(feature = "caching-sha2-password")))]
37pub fn scramble_sha256(nonce: &[u8], password: &[u8]) -> Option<[u8; 32]> {
38    if password.is_empty() {
39        return None;
40    }
41
42    fn sha256<T: AsRef<[u8]>>(bytes: &[T]) -> [u8; 32] {
43        let mut hasher = sha2::Sha256::new();
44        for bytes in bytes {
45            hasher.update(bytes);
46        }
47        hasher.finalize().into()
48    }
49
50    Some(xor(
51        sha256(&[password]),
52        sha256(&[&sha256(&[sha256(&[password])])[..], nonce]),
53    ))
54}