use std::{cmp, ptr};
macro_rules! escape {
($c:expr, $escaped:ident, $and_then:expr, $or_else:expr, $([$from:pat, $to:expr]),*) => {
match $c {
$(
$from => {
let $escaped = $to;
$and_then
}
),*
_ => $or_else,
}
};
}
macro_rules! fourchan_escape {
($c:expr, |$escaped:ident| $and_then:expr, || $or_else:expr) => {
escape!($c, $escaped, $and_then, $or_else, [b'"', b"""], [b'&', b"&"], [b'<', b"<"], [b'>', b">"])
};
}
macro_rules! mona_escape {
($c:expr, |$escaped:ident| $and_then:expr, || $or_else:expr) => {
escape!($c, $escaped, $and_then, $or_else, [b'"', b"""], [b'<', b"<"], [b'>', b">"])
};
}
pub fn pack_u64_be(bytes: &[u8]) -> u64 {
let mut ret = 0u64;
unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), &mut ret as *mut _ as *mut u8, cmp::min(bytes.len(), 8));
}
u64::from_be(ret)
}
pub fn secret_to_key(password: &[u8]) -> u64 {
pack_u64_be(password) << 1 & 0xFEFE_FEFE_FEFE_FEFE
}
pub fn sc_password_starts_with_katakana(password: &[u8]) -> bool {
if password[1] == 0xEF {
match password[2] {
0xBD => {
let b = password[3];
return 0xA1 <= b && b <= 0xBF;
},
0xBE => {
let b = password[3];
return 0x80 <= b && b <= 0x9F;
},
_ => (),
}
}
false
}
pub fn hex_to_i(c: u8) -> u8 {
const HEX_DECODING: &'static [u8; 0x100] = b"\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x10\x10\x10\x10\x10\
\x10\x0a\x0b\x0c\x0d\x0e\x0f\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x0a\x0b\x0c\x0d\x0e\x0f\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\
\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10";
HEX_DECODING[c as usize]
}
pub fn decode_salt(salt1: u8, salt2: u8) -> u32 {
const SALT_DECODING: [u32; 256] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11,
0x12, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
(SALT_DECODING[salt1 as usize] << 26) | (SALT_DECODING[salt2 as usize] << 18)
}
pub fn decode_salt_strict(salt1: u8, salt2: u8) -> Option<u32> {
const SALT_DECODING_STRICT: [u32; 256] = [
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
];
macro_rules! try_dec {
($c:expr) => {
match SALT_DECODING_STRICT[$c as usize] {
d @ 0...0x3F => d,
_ => return None,
}
};
}
Some((try_dec!(salt1) << 26) | (try_dec!(salt2) << 18))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn starts_with_katakana() {
assert!(sc_password_starts_with_katakana("$。春".as_bytes()));
assert!(sc_password_starts_with_katakana("$「は".as_bytes()));
assert!(sc_password_starts_with_katakana("$」あ".as_bytes()));
assert!(sc_password_starts_with_katakana("$、げ".as_bytes()));
assert!(sc_password_starts_with_katakana("$・ぽ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ヲよー".as_bytes()));
assert!(sc_password_starts_with_katakana("$ァa".as_bytes()));
assert!(sc_password_starts_with_katakana("$ィb".as_bytes()));
assert!(sc_password_starts_with_katakana("$ゥc".as_bytes()));
assert!(sc_password_starts_with_katakana("$ェdefg".as_bytes()));
assert!(sc_password_starts_with_katakana("$ォ ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ャ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ュ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ョ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ッ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ー".as_bytes()));
assert!(sc_password_starts_with_katakana("$ア".as_bytes()));
assert!(sc_password_starts_with_katakana("$イ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ウ".as_bytes()));
assert!(sc_password_starts_with_katakana("$エ".as_bytes()));
assert!(sc_password_starts_with_katakana("$オ".as_bytes()));
assert!(sc_password_starts_with_katakana("$カ".as_bytes()));
assert!(sc_password_starts_with_katakana("$キ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ク".as_bytes()));
assert!(sc_password_starts_with_katakana("$ケ".as_bytes()));
assert!(sc_password_starts_with_katakana("$コ".as_bytes()));
assert!(sc_password_starts_with_katakana("$サ".as_bytes()));
assert!(sc_password_starts_with_katakana("$シ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ス".as_bytes()));
assert!(sc_password_starts_with_katakana("$セ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ソ".as_bytes()));
assert!(sc_password_starts_with_katakana("$タ".as_bytes()));
assert!(sc_password_starts_with_katakana("$チ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ツ".as_bytes()));
assert!(sc_password_starts_with_katakana("$テ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ト".as_bytes()));
assert!(sc_password_starts_with_katakana("$ナ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ニ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ヌ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ネ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ノ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ハ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ヒ".as_bytes()));
assert!(sc_password_starts_with_katakana("$フ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ヘ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ホ".as_bytes()));
assert!(sc_password_starts_with_katakana("$マ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ミ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ム".as_bytes()));
assert!(sc_password_starts_with_katakana("$メ".as_bytes()));
assert!(sc_password_starts_with_katakana("$モ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ヤ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ユ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ヨ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ラ".as_bytes()));
assert!(sc_password_starts_with_katakana("$リ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ル".as_bytes()));
assert!(sc_password_starts_with_katakana("$レ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ロ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ワ".as_bytes()));
assert!(sc_password_starts_with_katakana("$ン".as_bytes()));
assert!(sc_password_starts_with_katakana("$゙".as_bytes()));
assert!(sc_password_starts_with_katakana("$゚".as_bytes()));
assert!(!sc_password_starts_with_katakana("$⦆".as_bytes()));
assert!(!sc_password_starts_with_katakana("$ᅠ".as_bytes()));
assert!(!sc_password_starts_with_katakana("$ アアアアア".as_bytes()));
}
}