1use sha1::Sha1;
10use sha2::{Digest, Sha256};
11
12fn xor<T, U>(mut left: T, right: U) -> T
13where
14 T: AsMut<[u8]>,
15 U: AsRef<[u8]>,
16{
17 left.as_mut()
18 .iter_mut()
19 .zip(right.as_ref().iter())
20 .map(|(l, r)| *l ^= r)
21 .last();
22 left
23}
24
25fn to_u8_32(bytes: impl AsRef<[u8]>) -> [u8; 32] {
26 let mut out = [0; 32];
27 out[..].copy_from_slice(bytes.as_ref());
28 out
29}
30
31fn hash_password(output: &mut [u32; 2], password: &[u8]) {
33 let mut nr: u32 = 1345345333;
34 let mut add: u32 = 7;
35 let mut nr2: u32 = 0x12345671;
36
37 let mut tmp: u32;
38
39 for x in password {
40 if *x == b' ' || *x == b'\t' {
41 continue;
42 }
43
44 tmp = *x as u32;
45 nr ^= (nr & 63)
46 .wrapping_add(add)
47 .wrapping_mul(tmp)
48 .wrapping_add(nr << 8);
49 nr2 = nr2.wrapping_add((nr2 << 8) ^ nr);
50 add = add.wrapping_add(tmp);
51 }
52
53 output[0] = nr & 0b01111111_11111111_11111111_11111111;
54 output[1] = nr2 & 0b01111111_11111111_11111111_11111111;
55}
56
57pub fn scramble_323(nonce: &[u8], password: &[u8]) -> Option<[u8; 8]> {
58 struct Rand323 {
59 seed1: u32,
60 seed2: u32,
61 max_value: u32,
62 max_value_dbl: f64,
63 }
64
65 impl Rand323 {
66 fn init(seed1: u32, seed2: u32) -> Self {
67 Self {
68 max_value: 0x3FFFFFFF,
69 max_value_dbl: 0x3FFFFFFF as f64,
70 seed1: seed1 % 0x3FFFFFFF,
71 seed2: seed2 % 0x3FFFFFFF,
72 }
73 }
74
75 fn my_rnd(&mut self) -> f64 {
76 self.seed1 = (self.seed1 * 3 + self.seed2) % self.max_value;
77 self.seed2 = (self.seed1 + self.seed2 + 33) % self.max_value;
78 (self.seed1 as f64) / self.max_value_dbl
79 }
80 }
81
82 let mut hash_pass = [0_u32; 2];
83 let mut hash_message = [0_u32; 2];
84
85 if password.is_empty() {
86 return None;
87 }
88
89 let mut output = [0_u8; 8];
90
91 hash_password(&mut hash_pass, password);
92 hash_password(&mut hash_message, nonce);
93
94 let mut rand_st = Rand323::init(
95 hash_pass[0] ^ hash_message[0],
96 hash_pass[1] ^ hash_message[1],
97 );
98
99 for x in output.iter_mut() {
100 *x = ((rand_st.my_rnd() * 31_f64).floor() + 64_f64) as u8;
101 }
102
103 let extra = (rand_st.my_rnd() * 31_f64).floor() as u8;
104
105 for x in output.iter_mut() {
106 *x ^= extra;
107 }
108
109 Some(output)
110}
111
112pub fn scramble_native(nonce: &[u8], password: &[u8]) -> Option<[u8; 20]> {
116 fn sha1_1(bytes: impl AsRef<[u8]>) -> [u8; 20] {
117 Sha1::digest(bytes).into()
118 }
119
120 fn sha1_2(bytes1: impl AsRef<[u8]>, bytes2: impl AsRef<[u8]>) -> [u8; 20] {
121 let mut hasher = Sha1::new();
122 hasher.update(bytes1.as_ref());
123 hasher.update(bytes2.as_ref());
124 hasher.finalize().into()
125 }
126
127 if password.is_empty() {
128 return None;
129 }
130
131 Some(xor(
132 sha1_1(password),
133 sha1_2(nonce, sha1_1(sha1_1(password))),
134 ))
135}
136
137pub fn scramble_sha256(nonce: &[u8], password: &[u8]) -> Option<[u8; 32]> {
141 fn sha256_1(bytes: impl AsRef<[u8]>) -> [u8; 32] {
142 let mut hasher = Sha256::default();
143 hasher.update(bytes.as_ref());
144 to_u8_32(hasher.finalize())
145 }
146
147 fn sha256_2(bytes1: impl AsRef<[u8]>, bytes2: impl AsRef<[u8]>) -> [u8; 32] {
148 let mut hasher = Sha256::default();
149 hasher.update(bytes1.as_ref());
150 hasher.update(bytes2.as_ref());
151 to_u8_32(hasher.finalize())
152 }
153
154 if password.is_empty() {
155 return None;
156 }
157
158 Some(xor(
159 sha256_1(password),
160 sha256_2(sha256_1(sha256_1(password)), nonce),
161 ))
162}
163
164#[cfg(test)]
165mod test {
166 use super::*;
167
168 #[test]
169 fn should_compute_scrambled_password() {
170 let scr = [
171 0x4e, 0x52, 0x33, 0x48, 0x50, 0x3a, 0x71, 0x49, 0x59, 0x61, 0x5f, 0x39, 0x3d, 0x64,
172 0x62, 0x3f, 0x53, 0x64, 0x7b, 0x60,
173 ];
174 let password = [0x47, 0x21, 0x69, 0x64, 0x65, 0x72, 0x32, 0x37];
175 let output1 = scramble_native(&scr, &password);
176 let output2 = scramble_sha256(&scr, &password);
177 assert!(output1.is_some());
178 assert!(output2.is_some());
179 assert_eq!(
180 output1.unwrap(),
181 [
182 0x09, 0xcf, 0xf8, 0x85, 0x5e, 0x9e, 0x70, 0x53, 0x40, 0xff, 0x22, 0x70, 0xd8, 0xfb,
183 0x9f, 0xad, 0xba, 0x90, 0x6b, 0x70,
184 ]
185 );
186 assert_eq!(
187 output2.unwrap(),
188 [
189 0x4f, 0x97, 0xbb, 0xfd, 0x20, 0x24, 0x01, 0xc4, 0x2a, 0x69, 0xde, 0xaa, 0xe5, 0x3b,
190 0xda, 0x07, 0x7e, 0xd7, 0x57, 0x85, 0x63, 0xc1, 0xa8, 0x0e, 0xb8, 0x16, 0xc8, 0x21,
191 0x19, 0xb6, 0x8d, 0x2e,
192 ]
193 );
194 }
195}