├── src ├── game │ ├── apis │ │ ├── mod.rs │ │ └── authentication.rs │ ├── protos │ │ ├── v1_0_0 │ │ │ ├── mod.rs │ │ │ ├── cmd_types.rs │ │ │ └── proto.rs │ │ └── mod.rs │ ├── mod.rs │ ├── packet.rs │ └── session.rs ├── http │ ├── mod.rs │ ├── gate.rs │ └── sdk.rs ├── common │ ├── mod.rs │ ├── xor.rs │ ├── mt64.rs │ ├── hmac.rs │ ├── ec2b │ │ ├── mod.rs │ │ ├── mhy_aes.rs │ │ └── magic.rs │ └── rsa.rs └── main.rs ├── .gitignore ├── assert ├── client_secret_key.ec2b ├── password_key.pem └── rsakey_config │ ├── 2 │ ├── server_private_key.pem │ └── client_public_key.pem │ └── 3 │ ├── server_private_key.pem │ └── client_public_key.pem ├── Cargo.toml └── .vscode └── launch.json /src/game/apis/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod authentication; -------------------------------------------------------------------------------- /src/http/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod gate; 2 | pub mod sdk; -------------------------------------------------------------------------------- /src/game/protos/v1_0_0/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cmd_types; 2 | pub mod proto; -------------------------------------------------------------------------------- /src/game/mod.rs: -------------------------------------------------------------------------------- 1 | mod apis; 2 | mod protos; 3 | 4 | mod packet; 5 | 6 | pub mod session; -------------------------------------------------------------------------------- /src/game/protos/mod.rs: -------------------------------------------------------------------------------- 1 | mod v1_0_0; 2 | 3 | pub use v1_0_0::cmd_types; 4 | pub use v1_0_0::proto; -------------------------------------------------------------------------------- /src/common/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ec2b; 2 | pub mod hmac; 3 | pub mod rsa; 4 | pub mod mt64; 5 | pub mod xor; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | debug/ 2 | target/ 3 | 4 | /*.json 5 | Cargo.lock 6 | 7 | **/*.rs.bk 8 | *.pdb 9 | .vs/ 10 | -------------------------------------------------------------------------------- /assert/client_secret_key.ec2b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Simplxss/ZZZ-ClientSimulator/HEAD/assert/client_secret_key.ec2b -------------------------------------------------------------------------------- /src/common/xor.rs: -------------------------------------------------------------------------------- 1 | pub fn xor(buf: &mut [u8], key: &[u8]) { 2 | buf.iter_mut() 3 | .enumerate() 4 | .for_each(|(i, v)| *v ^= key[i % key.len()]); 5 | } -------------------------------------------------------------------------------- /src/game/protos/v1_0_0/cmd_types.rs: -------------------------------------------------------------------------------- 1 | 2 | pub const PLAYER_GET_TOKEN_CS_REQ: u16 = 0x004a; 3 | pub const PLAYER_GET_TOKEN_SC_RSP: u16 = 0x0062; 4 | pub const PLAYER_LOGIN_CS_REQ: u16 = 0x0053; 5 | pub const PLAYER_LOGIN_SC_RSP: u16 = 0x005b; 6 | -------------------------------------------------------------------------------- /assert/password_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDvekdPMHN3AYhm/vktJT+YJr7 3 | cI5DcsNKqdsx5DZX0gDuWFuIjzdwButrIYPNmRJ1G8ybDIF7oDW2eEpm5sMbL9zs 4 | 9ExXCdvqrn51qELbqj0XxtMTIpaCHFSI50PfPpTFV9Xt/hmyVwokoOXFlAEgCn+Q 5 | CgGs52bFoYMtyi+xEQIDAQAB 6 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /assert/rsakey_config/2/server_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCr9LU1hQA2RWpg5RrNlUcVQXaL 3 | BR2m/JfckLHPGHSA15RzXSDf5UbOPXiZZALhoEEVgETURkX3id/i2aqLSfjf0LzV 4 | 7ujnKzD8rwbC0n/m5nGcBWwi7njP7vEp1a2KgC3v9ds4cwelYb4S7aUpxrteASSQ 5 | 7YUXfsPI+Et/qmwe3wIDAQAB 6 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /assert/rsakey_config/3/server_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDuTJKlKQrakKApLDkDqdj/G2vZ 3 | cj36cWl1x0/Lj15Ol6R5+2t120YtegW3jEqRFHii832q16c8tBsQXmANtLkFDmyT 4 | jI/SslIUEr6iXjLHslfY2b0zET5nPzNvSIzweboB7Acigtp2kHTofod2HhdkpiZQ 5 | +54fjLPVksVAMbN0tQIDAQAB 6 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /src/common/mt64.rs: -------------------------------------------------------------------------------- 1 | use rand_mt::Mt64; 2 | 3 | pub fn gen_server_secret_key(seed: u64, size: usize) -> Box<[u8]> { 4 | let mut mt = Mt64::new(seed); 5 | let mut buf = Vec::with_capacity(size as usize); 6 | 7 | for _ in 0..(size >> 3) { 8 | buf.extend_from_slice(&mt.next_u64().to_le_bytes()); 9 | } 10 | buf.into_boxed_slice() 11 | } 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ZZZ-ClientSimulator" 3 | version = "0.0.1" 4 | authors = ["Simplxs "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | reqwest = { version = "0.12.5", features = ["blocking", "json", "socks"] } 9 | serde = { version = "1.0.104", features = ["derive"] } 10 | serde_with = "3.8.2" 11 | serde_json = "1.0.48" 12 | rsa = { version = "0.9.6", features = ["sha2"] } 13 | sha2 = "0.10.8" 14 | hmac = "0.12.1" 15 | rand = "0.8.4" 16 | uuid = { version = "1.9.1", features = ["v4"]} 17 | qrcode = "0.14.0" 18 | hex = "0.4.3" 19 | base64 = "0.13" 20 | regex = "1.10.5" 21 | itertools = "0.13.0" 22 | tokio_kcp = { git = "https://github.com/Simplxss/tokio_kcp.git" } 23 | tokio = { version = "1.38.0", features = ["rt-multi-thread"] } 24 | hyper = "1.4.1" 25 | thiserror = "1.0.63" 26 | rand_mt = "4.2.2" 27 | prost = "0.13.1" 28 | 29 | [[bin]] 30 | name = "simulator" 31 | path = "src/main.rs" 32 | -------------------------------------------------------------------------------- /assert/rsakey_config/3/client_public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK5EKArRkuWEq88Z 3 | vPVqtxkkf7sOQCQ8BqrvrZF1YmcDhfB+sYC+yj4tjlQExwqGjRS0wA+Z5S0o4NKR 4 | xAKh2n717c4+BofLbxdgOv/MgeXHk9zrM6PVEeXe4bCOebMW9+0FKUCx2KMSrO/R 5 | aISe+GeVdi4EmPtF72xsTB8YcR03AgMBAAECgYB0EJ7evcBpr1hCwjCw/9ddHosY 6 | CaC8wWHrfWCLrbPRSm5tw+PzDJ9klDDkUp5Cq2TRcqUsfuI9lqlOdZkn66a6p/zh 7 | Fy6KXAi0ffJOsnDw94gjG4oTwT5OScqeLYjtJjIqm65Ftb3oMLlaEdLhA1Fs3CjI 8 | JA98rRahtAi0Ba5YWQJBAOfQGP8DRJudd3yQ16p58+Q/Fa8C5wADz4YigMvkbIz4 9 | dTAxbdnJU0DnS+89UVsIdXxRfNfWyFIsQyWV4nt5fc0CQQDAcvFwHc3az8YmByjf 10 | lsQk9CSu/Xzg9eclE7ZxPEJHxlOs3ragplvMP/qPkRxkDqFSi75iOE8uypxoUlUj 11 | YOMTAkAKO6Bu2WkU6X2VzRsIFnwSrko5wIoL8R8fD7TZy0qTaoBZ0UTFIWMAcXVj 12 | qTRHLXdqNnqpWHzdS8DnDtfBlZpdAkEAiXUQEj6XfESPiTXv8dOkAakIUpzoB15c 13 | XNU5qKOby9xSg9UHqLNqOfcwpj7FgooYm/cIYutJU2iQUssL2JspVQJBAIqiiYXF 14 | GiO8aas4ucNh+tY0sawTqbIyxnnItiAexo7fIJovTbWcktORTM1Tb/T0Qw7hs79I 15 | aXs4cquN1RtEC8w= 16 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /src/game/apis/authentication.rs: -------------------------------------------------------------------------------- 1 | use prost::Message; 2 | 3 | use crate::game::packet::Packet; 4 | use crate::game::protos::cmd_types; 5 | use crate::game::protos::proto::{PlayerGetTokenCsReq, PlayerGetTokenScRsp}; 6 | 7 | pub fn build_player_get_token_cs_req( 8 | account_uid: String, 9 | token: String, 10 | device: String, 11 | client_rand_key: String, 12 | ) -> Packet { 13 | Packet { 14 | cmd_type: cmd_types::PLAYER_GET_TOKEN_CS_REQ, 15 | head: Vec::new(), 16 | body: PlayerGetTokenCsReq { 17 | field1: 12121, 18 | token, 19 | account_uid, 20 | field5: 3909, 21 | field6: 5571, 22 | device, 23 | field11: 6567, 24 | field13: 6874, 25 | client_rand_key, 26 | } 27 | .encode_to_vec(), 28 | } 29 | } 30 | 31 | pub fn parse_player_get_token_sc_rsp(packet: Packet) -> PlayerGetTokenScRsp { 32 | PlayerGetTokenScRsp::decode(&packet.body[..]).unwrap() 33 | } 34 | -------------------------------------------------------------------------------- /src/common/hmac.rs: -------------------------------------------------------------------------------- 1 | use hmac::{Hmac, Mac}; 2 | use itertools::Itertools; 3 | use serde_json::Value; 4 | use sha2::Sha256; 5 | use std::collections::HashMap; 6 | 7 | const SIGN_KEY: &[u8] = b"8844b676f3268c082a56021d9f47a206"; 8 | 9 | pub fn sign_data(data: &T) -> String 10 | where 11 | T: serde::ser::Serialize, 12 | { 13 | // data.Serialize(); 14 | let t = serde_json::to_value(&data).unwrap(); 15 | let t1: HashMap = serde_json::from_value(t).unwrap(); 16 | let t2: HashMap = t1 17 | .iter() 18 | .map(|(k, v)| { 19 | ( 20 | k.clone(), 21 | match v { 22 | Value::String(s) => s.clone(), 23 | _ => v.to_string(), 24 | }, 25 | ) 26 | }) 27 | .collect(); 28 | 29 | let mut keys = t2.keys().sorted(); 30 | let mut s = match keys.next() { 31 | Some(key) => format!("{}={}", key, t2[key]), 32 | None => return String::new(), 33 | }; 34 | 35 | for key in keys { 36 | s.push_str(format!("&{}={}", key, t2[key]).as_str()); 37 | } 38 | 39 | type HmacSha256 = Hmac; 40 | let mut mac = HmacSha256::new_from_slice(SIGN_KEY).unwrap(); 41 | mac.update(s.as_bytes()); 42 | let result = mac.finalize(); 43 | return hex::encode(result.into_bytes()); 44 | } 45 | -------------------------------------------------------------------------------- /src/game/protos/v1_0_0/proto.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, PartialEq, ::prost::Message)] 2 | pub struct PacketHead { 3 | #[prost(uint32, tag = "1")] 4 | pub packet_id: u32, 5 | #[prost(uint32, tag = "11")] 6 | pub request_id: u32, 7 | #[prost(bool, tag = "14")] 8 | pub dneigcmldhk: bool, 9 | } 10 | 11 | #[derive(Clone, PartialEq, ::prost::Message)] 12 | pub struct PlayerGetTokenCsReq { 13 | #[prost(uint32, tag = "1")] 14 | pub field1: u32, 15 | #[prost(string, tag = "2")] 16 | pub token: ::prost::alloc::string::String, 17 | #[prost(string, tag = "4")] 18 | pub account_uid: ::prost::alloc::string::String, 19 | #[prost(uint32, tag = "5")] 20 | pub field5: u32, 21 | #[prost(uint32, tag = "6")] 22 | pub field6: u32, 23 | #[prost(string, tag = "9")] 24 | pub device: ::prost::alloc::string::String, 25 | #[prost(uint32, tag = "11")] 26 | pub field11: u32, 27 | #[prost(uint32, tag = "13")] 28 | pub field13: u32, 29 | #[prost(string, tag = "14")] 30 | pub client_rand_key: ::prost::alloc::string::String, 31 | } 32 | 33 | #[derive(Clone, PartialEq, ::prost::Message)] 34 | pub struct PlayerGetTokenScRsp { 35 | #[prost(string, tag = "2")] 36 | pub sign: ::prost::alloc::string::String, 37 | #[prost(uint32, tag = "3")] 38 | pub uid: u32, 39 | #[prost(string, tag = "4")] 40 | pub server_rand_key: ::prost::alloc::string::String, 41 | } 42 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug executable 'simulator'", 11 | "cargo": { 12 | "args": [ 13 | "build", 14 | "--bin=simulator", 15 | "--package=ZZZ-ClientSimulator" 16 | ], 17 | "filter": { 18 | "name": "simulator", 19 | "kind": "bin" 20 | } 21 | }, 22 | "args": [], 23 | "cwd": "${workspaceFolder}" 24 | }, 25 | { 26 | "type": "lldb", 27 | "request": "launch", 28 | "name": "Debug unit tests in executable 'simulator'", 29 | "cargo": { 30 | "args": [ 31 | "test", 32 | "--no-run", 33 | "--bin=simulator", 34 | "--package=ZZZ-ClientSimulator" 35 | ], 36 | "filter": { 37 | "name": "simulator", 38 | "kind": "bin" 39 | } 40 | }, 41 | "args": [], 42 | "cwd": "${workspaceFolder}" 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /src/game/packet.rs: -------------------------------------------------------------------------------- 1 | 2 | const HEAD_MAGIC: u32 = 0x01234567; 3 | const TAIL_MAGIC: u32 = 0x89abcdef; 4 | 5 | #[derive(Debug)] 6 | pub struct Packet { 7 | pub cmd_type: u16, 8 | pub head: Vec, 9 | pub body: Vec, 10 | } 11 | 12 | impl From<&[u8]> for Packet { 13 | fn from(value: &[u8]) -> Self { 14 | assert_eq!( 15 | HEAD_MAGIC, 16 | u32::from_be_bytes(value[..4].try_into().unwrap()) 17 | ); 18 | 19 | let cmd_type = u16::from_be_bytes(value[4..6].try_into().unwrap()); 20 | let head_size = u16::from_be_bytes(value[6..8].try_into().unwrap()) as usize; 21 | let body_size = u32::from_be_bytes(value[8..12].try_into().unwrap()) as usize; 22 | 23 | assert_eq!( 24 | TAIL_MAGIC, 25 | u32::from_be_bytes(value[12 + head_size + body_size..].try_into().unwrap()) 26 | ); 27 | 28 | Self { 29 | cmd_type, 30 | head: value[12..12 + head_size].to_vec(), 31 | body: value[12 + head_size..12 + head_size + body_size].to_vec(), 32 | } 33 | } 34 | } 35 | 36 | impl From for Vec { 37 | fn from(value: Packet) -> Self { 38 | let mut buf = Self::with_capacity(16 + value.head.len() + value.body.len()); 39 | 40 | buf.extend(HEAD_MAGIC.to_be_bytes()); 41 | buf.extend(value.cmd_type.to_be_bytes()); 42 | buf.extend((value.head.len() as u16).to_be_bytes()); 43 | buf.extend((value.body.len() as u32).to_be_bytes()); 44 | buf.extend(value.head); 45 | buf.extend(value.body); 46 | buf.extend(TAIL_MAGIC.to_be_bytes()); 47 | 48 | buf 49 | } 50 | } -------------------------------------------------------------------------------- /assert/rsakey_config/2/client_public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDFIlVn5/23e/if 3 | SHkTTlzimvTcqUdQUUpPgc6a/DCbO8olZMuK1fx/kS3pDb63goXN941egNVWz40X 4 | yTVQskjQcKsdvjo2JmdwRZUfNi93xA4gAJGIwt4uILAVqydJy83mMYJbv/BJXCTS 5 | +LPE1II/YFjJkI7k3DjsG4gmQWaPWV66ohNkue2K+dtAt5JKdqu5n6j2Kb4jyTcG 6 | lPrngJ+WxXpadqWJa7Qkq8Rlu9j7HhjH+daipNYDHwNgKVFrP1Ptbm/1vnm54ytO 7 | jRAYwB9GO62qCmKJ4tjYifK/xgR+kiDmR6FKC2L8DhNsoRHxGuMej6PvfI4h3gU0 8 | EaDBQhJJAgMBAAECggEAOFeux0rUBhwlnAjPqgfsnkuhjmvHWRpSvdSg40UO818s 9 | UHG1hxHP3/nzgDeQecyRR6PoQMlbsDsT3WeBmHXMP97j2VVkN9PUHo+Upl4LRRTA 10 | 4L6o2ciwTcjD6v2G9h2M1Kzz0BtUpvLyB2ZTov8F1u1HkxyA6sJSdpEL4bsxf+iP 11 | jFdV6ZJ3BOnb20mtqNk60WrDYN5qWLkDSF8YeFgzinrLWyuaErWihLvac8VQPku4 12 | 4lpGMBz2dUe/u4ri9whqGwG6wI6/NF/FjKm1OKudU/ffs5l0uT0MgROiaIZvBFaw 13 | W9aOrH1qzmfPxeS+UqVQ0ml76pbaaUJdD1JhnW/53QKBgQDr5pnbm/LB8wdNdIpo 14 | +zMyoyhNKj+ufKOCzkCosWO4Nd/PxC0yfUDYP5+dGy2CE7xNhQGbbOrew93ij9ST 15 | BfLHQuJTZhXuMxv6olZYNMjidgjwi0RDf60Ud/gmbUDMocyTrn3Q6pkQMwAD3FVU 16 | dTNF2psc0IBIUBDf5ba8b6uA3wKBgQDV7ipT5iFFGuF5GntoHeYy893dgM1ia2Oy 17 | wJ0E4F6XAZPe2dEpRI/stsdrLmeiQaB7nzUR+H7R8i6tY/SaEcYQAIehzHF0s1xa 18 | 1HzHI00+wny8xaXnPa8KHoAerblBZDss8GfhsEJm9eb04Cxpeuz3KIHejItzO+qb 19 | mY888G8J1wKBgFcuFdZPP9vlkOFTHIPHshgYrCA4aOh3L4Z76vFs/Ulqv5ftDDcI 20 | ixpgCQDqtlrIKGMNsJZcHkDNagb82LatEBgL49CmfZxWTxTFQdu/Ri5LKOqczVGU 21 | scZKv+6TmcsGULCTX/QBfye5cVv75Z0c4yIBtCll9MLEtDfKkUn6iwtJAoGBAJIe 22 | UWTqy5Ci0pxf/ShZO7FTphez8RSnGvqt2tHI2nKzzicpiVZxkQhys3S+xmQqBQ5K 23 | 6Pm0TBLkIwOlQR22xByL8BgQRvIZzBvyBKQTtaAHQSHCshVmqVb1DDdoGx/R8SU5 24 | swqQ1Fn03WImd883+gC69zFlt53mr9DFqvNJmd4TAoGAdfOgPRXJFxfNptQLukMM 25 | GX2Q7qDYZIu75UGV4APiSVMg8Ki++VQFfP5Ens7tDIPWdWwylWW83VCzW/mwSaT3 26 | QEizm5ClSlRFWXt9CWFQwDpDZ6HeNoWCwQZ927bSk15trkh530hxcxUCJC1irjeB 27 | 2us0UWrqeOtOSlECtnfxRa8= 28 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /src/common/ec2b/mod.rs: -------------------------------------------------------------------------------- 1 | // https://git.xeondev.com/NewEriduPubSec/JaneDoe-ZS/src/branch/master/nap_common/src/cryptography/ec2b/mod.rs 2 | 3 | use magic::{AES_XORPAD_TABLE, KEY_XORPAD_TABLE}; 4 | use mhy_aes::oqs_mhy128_enc_c; 5 | use thiserror::Error; 6 | 7 | mod magic; 8 | mod mhy_aes; 9 | 10 | const HEAD_MAGIC: u32 = 0x45633262; // "Ec2b" 11 | const KEY_SIZE: usize = 16; 12 | const DATA_SIZE: usize = 2048; 13 | 14 | pub struct Ec2b { 15 | key: [u8; KEY_SIZE], 16 | data: [u8; DATA_SIZE], 17 | } 18 | 19 | #[derive(Error, Debug)] 20 | pub enum DecodeError { 21 | #[error(transparent)] 22 | TryFromSliceError(#[from] std::array::TryFromSliceError), 23 | #[error("magic mismatch, expected: {HEAD_MAGIC}, got: {0}")] 24 | MagicMismatch(u32), 25 | #[error("invalid key size, expected: {KEY_SIZE}, got: {0}")] 26 | InvalidKeySize(usize), 27 | #[error("invalid data size, expected: {DATA_SIZE}, got: {0}")] 28 | InvalidDataSize(usize), 29 | } 30 | 31 | impl Ec2b { 32 | const XOR_MAGIC: u64 = 0xCEAC3B5A867837AC; 33 | 34 | pub fn read(r: &[u8]) -> Result { 35 | let magic = u32::from_be_bytes(r[..4].try_into()?); 36 | matches!(magic, HEAD_MAGIC) 37 | .then_some(()) 38 | .ok_or(DecodeError::MagicMismatch(magic))?; 39 | 40 | let key_size = u32::from_le_bytes(r[4..8].try_into()?) as usize; 41 | matches!(key_size, KEY_SIZE) 42 | .then_some(()) 43 | .ok_or(DecodeError::InvalidKeySize(key_size))?; 44 | 45 | let mut key = [0u8; KEY_SIZE]; 46 | key.copy_from_slice(&r[8..24]); 47 | 48 | let data_size = u32::from_le_bytes(r[24..28].try_into()?) as usize; 49 | matches!(data_size, DATA_SIZE) 50 | .then_some(()) 51 | .ok_or(DecodeError::InvalidDataSize(data_size))?; 52 | 53 | let mut data = [0u8; DATA_SIZE]; 54 | data.copy_from_slice(&r[28..2076]); 55 | 56 | Self::key_scramble(&mut key); 57 | (0..16).for_each(|i| key[i] ^= KEY_XORPAD_TABLE[i]); 58 | 59 | Ok(Self { key, data }) 60 | } 61 | 62 | #[must_use] 63 | pub fn derive_seed(&self) -> u64 { 64 | let val = self 65 | .data 66 | .chunks_exact(8) 67 | .map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap())) 68 | .fold(0xFFFFFFFFFFFFFFFF, |val, i| val ^ i); 69 | 70 | let key_qword_0 = u64::from_le_bytes(self.key[0..8].try_into().unwrap()); 71 | let key_qword_1 = u64::from_le_bytes(self.key[8..16].try_into().unwrap()); 72 | 73 | key_qword_1 ^ Self::XOR_MAGIC ^ val ^ key_qword_0 74 | } 75 | 76 | fn key_scramble(key: &mut [u8]) { 77 | let mut round_keys = [0u8; 176]; 78 | for round in 0..11 { 79 | for i in 0..16 { 80 | for j in 0..16 { 81 | let idx = (round << 8) + (i * 16) + j; 82 | round_keys[round * 16 + i] ^= 83 | AES_XORPAD_TABLE[1][idx] ^ AES_XORPAD_TABLE[0][idx]; 84 | } 85 | } 86 | } 87 | 88 | let mut chip = [0u8; 16]; 89 | oqs_mhy128_enc_c(key, &round_keys, &mut chip); 90 | 91 | key.copy_from_slice(&chip); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/common/rsa.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, fs, path::Path, sync::LazyLock}; 2 | 3 | use rsa::{ 4 | pkcs1v15::{Signature, VerifyingKey}, 5 | pkcs8::{DecodePrivateKey, DecodePublicKey}, 6 | sha2::Sha256, 7 | signature::Verifier, 8 | traits::PublicKeyParts, 9 | Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey, 10 | }; 11 | 12 | static RSAKEY_CONFIG: LazyLock> = LazyLock::new(|| { 13 | let mut map = HashMap::new(); 14 | fs::read_dir("assert/rsakey_config") 15 | .unwrap() 16 | .filter_map(|entry| match entry { 17 | Ok(entry) => Some(entry), 18 | Err(_) => None, 19 | }) 20 | .filter(|entry| match entry.file_type() { 21 | Ok(file_type) => file_type.is_dir(), 22 | Err(_) => false, 23 | }) 24 | .for_each(|entry| { 25 | let path = entry.path(); 26 | let rsa_ver = path.file_stem().unwrap().to_str().unwrap().parse().unwrap(); 27 | let client_public_key = fs::read_to_string(path.join("client_public_key.pem")).unwrap(); 28 | let server_private_key = 29 | fs::read_to_string(path.join("server_private_key.pem")).unwrap(); 30 | map.insert( 31 | rsa_ver, 32 | ( 33 | RsaPrivateKey::from_pkcs8_pem(&client_public_key).unwrap(), 34 | RsaPublicKey::from_public_key_pem(&server_private_key).unwrap(), 35 | ), 36 | ); 37 | }); 38 | map 39 | }); 40 | 41 | static PASSWORD_KEY: LazyLock = LazyLock::new(|| { 42 | RsaPublicKey::from_public_key_pem( 43 | &fs::read_to_string(Path::new("assert/password_key.pem")).unwrap(), 44 | ) 45 | .unwrap() 46 | }); 47 | 48 | pub fn rsa_decrypt(content: &str, rsa_ver: u32) -> Result, String> { 49 | let priv_key = match RSAKEY_CONFIG.get_key_value(&rsa_ver) { 50 | Some((_, (client_public_key, _))) => client_public_key, 51 | None => return Err(format!("rsa_ver {} not found", rsa_ver)), 52 | }; 53 | 54 | let raw = match base64::decode(content) { 55 | Ok(raw) => raw, 56 | Err(e) => return Err(format!("failed to decode base64: {}", e)), 57 | }; 58 | 59 | let mut decrypted = Vec::new(); 60 | for chunk in raw.chunks(priv_key.size()) { 61 | let dec_chunk = match priv_key.decrypt(Pkcs1v15Encrypt, &chunk) { 62 | Ok(decrypted) => decrypted, 63 | Err(e) => return Err(format!("failed to decrypt: {}", e)), 64 | }; 65 | decrypted.extend_from_slice(&dec_chunk); 66 | } 67 | 68 | return Ok(decrypted); 69 | } 70 | 71 | pub fn rsa_encrypt(content: &[u8], rsa_ver: u32) -> Result { 72 | let pub_key = match RSAKEY_CONFIG.get_key_value(&rsa_ver) { 73 | Some((_, (_, server_private_key))) => server_private_key, 74 | None => return Err(format!("rsa_ver {} not found", rsa_ver)), 75 | }; 76 | 77 | let encrypted = 78 | match pub_key.encrypt(&mut rand::thread_rng(), Pkcs1v15Encrypt, content) { 79 | Ok(encrypted) => encrypted, 80 | Err(e) => return Err(format!("failed to encrypt: {}", e)), 81 | }; 82 | 83 | return Ok(base64::encode(encrypted)); 84 | } 85 | 86 | pub fn rsa_verify_sign(content: &[u8], sign: &str, rsa_ver: u32) -> Result { 87 | let verify_key = match RSAKEY_CONFIG.get_key_value(&rsa_ver) { 88 | Some((_, (_, server_private_key))) => { 89 | VerifyingKey::::new(server_private_key.clone()) 90 | } 91 | None => return Err(format!("rsa_ver {} not found", rsa_ver)), 92 | }; 93 | 94 | let raw: Vec = match base64::decode(sign) { 95 | Ok(raw) => raw, 96 | Err(_) => return Err("failed to decode base64".to_string()), 97 | }; 98 | let sign = match Signature::try_from(raw.as_slice()) { 99 | Ok(sign) => sign, 100 | Err(_) => return Err("failed to convert to signature".to_string()), 101 | }; 102 | 103 | return Ok(verify_key.verify(content, &sign).is_ok()); 104 | } 105 | 106 | pub fn password_encrypt(password: &str) -> Result { 107 | let encrypted = match PASSWORD_KEY.encrypt( 108 | &mut rand::thread_rng(), 109 | Pkcs1v15Encrypt, 110 | password.as_bytes(), 111 | ) { 112 | Ok(encrypted) => encrypted, 113 | Err(e) => return Err(format!("failed to encrypt: {}", e)), 114 | }; 115 | 116 | return Ok(base64::encode(encrypted)); 117 | } 118 | -------------------------------------------------------------------------------- /src/game/session.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use tokio_kcp::{KcpConfig, KcpStream}; 4 | 5 | use crate::common::{ec2b::Ec2b, mt64, rsa, xor}; 6 | 7 | use super::packet::Packet; 8 | 9 | use super::protos::cmd_types; 10 | 11 | struct Player { 12 | account_uid: String, 13 | token: String, 14 | device: String, 15 | rsa_ver: u32, 16 | client_rand_key: u64, 17 | } 18 | 19 | pub struct Session { 20 | kcp: KcpStream, 21 | server_secret_key: Box<[u8]>, 22 | session_key: Option>, 23 | 24 | player: Player, 25 | } 26 | 27 | impl Session { 28 | pub async fn new( 29 | addr: SocketAddr, 30 | rsa_ver: u32, 31 | client_secret_key: &str, 32 | account_uid: &str, 33 | token: &str, 34 | device: &str, 35 | ) -> Result { 36 | let dec_client_secret_key = match base64::decode(client_secret_key) { 37 | Ok(v) => v, 38 | Err(e) => panic!("Failed to decode client secret key: {}", e), 39 | }; 40 | let ec2b = match Ec2b::read(&dec_client_secret_key) { 41 | Ok(v) => v, 42 | Err(e) => return Err(format!("Failed to decode Ec2b: {}", e)), 43 | }; 44 | 45 | Ok(Self { 46 | kcp: KcpStream::connect(&KcpConfig::default(), addr) 47 | .await 48 | .unwrap(), 49 | server_secret_key: mt64::gen_server_secret_key(ec2b.derive_seed(), 4096), 50 | session_key: None, 51 | 52 | player: Player { 53 | account_uid: account_uid.to_string(), 54 | token: token.to_string(), 55 | device: device.to_string(), 56 | rsa_ver, 57 | client_rand_key: rand::random::(), 58 | }, 59 | }) 60 | } 61 | 62 | pub async fn send(&mut self, mut packet: Packet) -> Result<(), String> { 63 | xor::xor( 64 | &mut packet.body, 65 | match packet.cmd_type { 66 | cmd_types::PLAYER_GET_TOKEN_CS_REQ => &self.server_secret_key, 67 | _ => self.session_key.as_ref().unwrap(), 68 | }, 69 | ); 70 | let payload: Vec = packet.into(); 71 | 72 | let _ = self.kcp.send(&payload).await; 73 | 74 | Ok(()) 75 | } 76 | 77 | pub async fn recv(&mut self) -> Packet { 78 | let mut buf = vec![0u8; 4096]; 79 | let n = self.kcp.recv(&mut buf).await.unwrap(); 80 | 81 | let mut packet = Packet::from(&buf[..n]); 82 | xor::xor( 83 | &mut packet.body, 84 | match packet.cmd_type { 85 | cmd_types::PLAYER_GET_TOKEN_SC_RSP => &self.server_secret_key, 86 | _ => self.session_key.as_ref().unwrap(), 87 | }, 88 | ); 89 | 90 | packet 91 | } 92 | 93 | pub async fn get_token(&mut self) -> Result<(), String> { 94 | let client_rand_key = match rsa::rsa_encrypt( 95 | &self.player.client_rand_key.to_le_bytes(), 96 | self.player.rsa_ver, 97 | ) { 98 | Ok(v) => v, 99 | Err(e) => panic!("Failed to encrypt client rand key: {}", e), 100 | }; 101 | let req = crate::game::apis::authentication::build_player_get_token_cs_req( 102 | self.player.account_uid.clone(), 103 | self.player.token.clone(), 104 | self.player.device.clone(), 105 | client_rand_key, 106 | ); 107 | self.send(req).await?; 108 | 109 | let packet = self.recv().await; 110 | let rsp = crate::game::apis::authentication::parse_player_get_token_sc_rsp(packet); 111 | 112 | let decrypted = match rsa::rsa_decrypt(&rsp.server_rand_key, self.player.rsa_ver) { 113 | Ok(v) => v, 114 | Err(e) => return Err(format!("Failed to decrypt server rand key: {}", e)), 115 | }; 116 | 117 | match rsa::rsa_verify_sign(&decrypted, &rsp.sign, self.player.rsa_ver) { 118 | Ok(true) => (), 119 | Ok(false) => return Err("Failed to verify sign".to_string()), 120 | Err(e) => return Err(format!("Failed to verify sign: {}", e)), 121 | }; 122 | 123 | let server_rand_key = u64::from_le_bytes(match decrypted[..8].try_into() { 124 | Ok(v) => v, 125 | Err(e) => return Err(format!("Failed to convert to u64: {}", e)), 126 | }); 127 | 128 | self.session_key = Some( 129 | mt64::gen_server_secret_key(self.player.client_rand_key ^ server_rand_key, 4096) 130 | .to_vec() 131 | .into_boxed_slice(), 132 | ); 133 | Ok(()) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/common/ec2b/mhy_aes.rs: -------------------------------------------------------------------------------- 1 | // https://git.xeondev.com/NewEriduPubSec/JaneDoe-ZS/src/branch/master/nap_common/src/cryptography/ec2b/mhy_aes.rs 2 | 3 | #![allow(unused)] 4 | 5 | use super::magic::{LOOKUP_G11, LOOKUP_G13, LOOKUP_G14, LOOKUP_G2, LOOKUP_G3, LOOKUP_G9, LOOKUP_RCON, LOOKUP_SBOX, LOOKUP_SBOX_INV, SHIFT_ROWS_TABLE, SHIFT_ROWS_TABLE_INV}; 6 | 7 | fn xorr(a: &mut [u8], b: &[u8], n: usize) { 8 | (0..n).for_each(|i| a[i] ^= b[i]); 9 | } 10 | 11 | fn xor_round_key(state: &mut [u8], keys: &[u8], round: usize) { 12 | xorr(state, &keys[round * 16..], 16); 13 | } 14 | 15 | fn sub_bytes(a: &mut [u8], n: usize) { 16 | (0..n).for_each(|i| a[i] = LOOKUP_SBOX[a[i] as usize]); 17 | } 18 | 19 | fn sub_bytes_inv(a: &mut [u8], n: usize) { 20 | (0..n).for_each(|i| a[i] = LOOKUP_SBOX_INV[a[i] as usize]); 21 | } 22 | 23 | fn key_schedule_core(a: &mut [u8], i: usize) { 24 | let temp = a[0]; 25 | a[0] = a[1]; 26 | a[1] = a[2]; 27 | a[2] = a[3]; 28 | a[3] = temp; 29 | sub_bytes(a, 4); 30 | a[0] ^= LOOKUP_RCON[i]; 31 | } 32 | 33 | fn oqs_aes128_load_schedule_c(key: &[u8]) -> [u8; 176] { 34 | let mut schedule = [0u8; 176]; 35 | 36 | let mut bytes = 16; 37 | let mut i = 1; 38 | let mut t = [0u8; 4]; 39 | 40 | schedule[0..16].copy_from_slice(key); 41 | 42 | while bytes < 176 { 43 | t.copy_from_slice(&schedule[bytes - 4..]); 44 | key_schedule_core(&mut t, i); 45 | i += 1; 46 | xorr(&mut schedule[bytes..], &t, 4); 47 | schedule[bytes..].copy_from_slice(&t); 48 | bytes += 4; 49 | 50 | for _ in 0..3 { 51 | t.copy_from_slice(&schedule[bytes - 4..]); 52 | xorr(&mut t, &schedule[bytes - 16..], 4); 53 | schedule[bytes..].copy_from_slice(&t); 54 | bytes += 4; 55 | } 56 | } 57 | 58 | schedule 59 | } 60 | 61 | fn shift_rows(state: &mut [u8]) { 62 | let temp = state.to_vec(); 63 | (0..16).for_each(|i| state[i] = temp[SHIFT_ROWS_TABLE[i] as usize]); 64 | } 65 | 66 | fn shift_rows_inv(state: &mut [u8]) { 67 | let temp = state.to_vec(); 68 | (0..16).for_each(|i| state[i] = temp[SHIFT_ROWS_TABLE_INV[i] as usize]); 69 | } 70 | 71 | fn mix_col(state: &mut [u8]) { 72 | let (a0, a1, a2, a3) = (state[0], state[1], state[2], state[3]); 73 | 74 | state[0] = LOOKUP_G2[a0 as usize] ^ LOOKUP_G3[a1 as usize] ^ a2 ^ a3; 75 | state[1] = LOOKUP_G2[a1 as usize] ^ LOOKUP_G3[a2 as usize] ^ a3 ^ a0; 76 | state[2] = LOOKUP_G2[a2 as usize] ^ LOOKUP_G3[a3 as usize] ^ a0 ^ a1; 77 | state[3] = LOOKUP_G2[a3 as usize] ^ LOOKUP_G3[a0 as usize] ^ a1 ^ a2; 78 | } 79 | 80 | fn mix_cols(state: &mut [u8]) { 81 | mix_col(&mut state[0..4]); 82 | mix_col(&mut state[4..8]); 83 | mix_col(&mut state[8..12]); 84 | mix_col(&mut state[12..16]); 85 | } 86 | 87 | fn mix_col_inv(state: &mut [u8]) { 88 | let (a0, a1, a2, a3) = (state[0], state[1], state[2], state[3]); 89 | 90 | state[0] = LOOKUP_G14[a0 as usize] 91 | ^ LOOKUP_G9[a3 as usize] 92 | ^ LOOKUP_G13[a2 as usize] 93 | ^ LOOKUP_G11[a1 as usize]; 94 | state[1] = LOOKUP_G14[a1 as usize] 95 | ^ LOOKUP_G9[a0 as usize] 96 | ^ LOOKUP_G13[a3 as usize] 97 | ^ LOOKUP_G11[a2 as usize]; 98 | state[2] = LOOKUP_G14[a2 as usize] 99 | ^ LOOKUP_G9[a1 as usize] 100 | ^ LOOKUP_G13[a0 as usize] 101 | ^ LOOKUP_G11[a3 as usize]; 102 | state[3] = LOOKUP_G14[a3 as usize] 103 | ^ LOOKUP_G9[a2 as usize] 104 | ^ LOOKUP_G13[a1 as usize] 105 | ^ LOOKUP_G11[a0 as usize]; 106 | } 107 | 108 | fn mix_cols_inv(state: &mut [u8]) { 109 | mix_col_inv(&mut state[0..4]); 110 | mix_col_inv(&mut state[4..8]); 111 | mix_col_inv(&mut state[8..12]); 112 | mix_col_inv(&mut state[12..16]); 113 | } 114 | 115 | fn oqs_aes128_enc_c(plaintext: &[u8], schedule: &[u8], ciphertext: &mut [u8]) { 116 | ciphertext.copy_from_slice(&plaintext[..16]); 117 | xor_round_key(ciphertext, schedule, 0); 118 | 119 | for i in 1..10 { 120 | sub_bytes(ciphertext, 16); 121 | shift_rows(ciphertext); 122 | mix_cols(ciphertext); 123 | xor_round_key(ciphertext, schedule, i); 124 | } 125 | 126 | sub_bytes(ciphertext, 16); 127 | shift_rows(ciphertext); 128 | xor_round_key(ciphertext, schedule, 10); 129 | } 130 | 131 | pub fn oqs_mhy128_enc_c(plaintext: &[u8], schedule: &[u8], ciphertext: &mut [u8]) { 132 | ciphertext.copy_from_slice(&plaintext[..16]); 133 | xor_round_key(ciphertext, schedule, 0); 134 | 135 | for i in 1..10 { 136 | sub_bytes_inv(ciphertext, 16); 137 | shift_rows_inv(ciphertext); 138 | mix_cols_inv(ciphertext); 139 | xor_round_key(ciphertext, schedule, i); 140 | } 141 | 142 | sub_bytes_inv(ciphertext, 16); 143 | shift_rows_inv(ciphertext); 144 | xor_round_key(ciphertext, schedule, 10); 145 | } 146 | 147 | fn oqs_aes128_dec_c(ciphertext: &[u8], schedule: &[u8], plaintext: &mut [u8]) { 148 | plaintext.copy_from_slice(&ciphertext[..16]); 149 | xor_round_key(plaintext, schedule, 10); 150 | shift_rows_inv(plaintext); 151 | sub_bytes_inv(plaintext, 16); 152 | 153 | for i in 0..9 { 154 | xor_round_key(plaintext, schedule, 9 - i); 155 | mix_cols_inv(plaintext); 156 | shift_rows_inv(plaintext); 157 | sub_bytes_inv(plaintext, 16); 158 | } 159 | 160 | xor_round_key(plaintext, schedule, 0); 161 | } 162 | 163 | fn oqs_mhy128_dec_c(ciphertext: &[u8], schedule: &[u8], plaintext: &mut [u8]) { 164 | plaintext.copy_from_slice(&ciphertext[..16]); 165 | xor_round_key(plaintext, schedule, 10); 166 | shift_rows(plaintext); 167 | sub_bytes(plaintext, 16); 168 | 169 | for i in 0..9 { 170 | xor_round_key(plaintext, schedule, 9 - i); 171 | mix_cols(plaintext); 172 | shift_rows(plaintext); 173 | sub_bytes(plaintext, 16); 174 | } 175 | 176 | xor_round_key(plaintext, schedule, 0); 177 | } 178 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | net::{IpAddr, Ipv4Addr, SocketAddr}, 3 | thread::sleep, 4 | time::Duration, 5 | }; 6 | 7 | use game::session; 8 | use qrcode::{render::unicode, QrCode}; 9 | 10 | mod common; 11 | mod game; 12 | mod http; 13 | 14 | const GATE_NAME: &str = "cn"; 15 | const VERSION: &str = "CNPRODWin1.0.0"; 16 | const LANGUAGE: u32 = 2; 17 | const CHANNEL_ID: u32 = 1; 18 | const SUB_CHANNEL_ID: u32 = 1; 19 | const PLATFORM: u32 = 3; 20 | 21 | const BIZ: &str = "nap_cn"; 22 | const DISPATCH_SEED: &str = "195fdb867197c041"; 23 | const RSA_VER: u32 = 3; 24 | 25 | const DEVICE: &str = "Macbook Pro"; 26 | 27 | #[tokio::main] 28 | async fn main() { 29 | let mut sdk = http::sdk::Sdk::new( 30 | Option::Some(|qrcode_url: &str| { 31 | let qrcode = QrCode::new(qrcode_url).unwrap(); 32 | let image = qrcode 33 | .render::() 34 | .dark_color(unicode::Dense1x2::Light) 35 | .light_color(unicode::Dense1x2::Dark) 36 | .build(); 37 | println!("{}", image); 38 | }), 39 | Option::Some(|| { 40 | let mut captcha = String::new(); 41 | std::io::stdin() 42 | .read_line(&mut captcha) 43 | .expect("error: unable to read user input"); 44 | return captcha.trim().to_string(); 45 | }), 46 | Option::Some(|challenge: &str, gt: &str| { 47 | println!("challenge: {}", challenge); 48 | println!("gt: {}", gt); 49 | let mut validate = String::new(); 50 | std::io::stdin() 51 | .read_line(&mut validate) 52 | .expect("error: unable to read user input"); 53 | validate = validate.trim().to_string(); 54 | return (format!("{}|jordan", validate), validate); 55 | }), 56 | ); 57 | 58 | let mut login_type: String = String::new(); 59 | std::io::stdin() 60 | .read_line(&mut login_type) 61 | .expect("error: unable to read user input"); 62 | let login_type: i32 = login_type.trim().parse().expect("Invalid login type"); 63 | match login_type { 64 | 0 => { 65 | let mut token = String::new(); 66 | std::io::stdin() 67 | .read_line(&mut token) 68 | .expect("error: unable to read user input"); 69 | sdk.load_token(token.trim()).expect("Load token failed"); 70 | } 71 | 1 => { 72 | sdk.qr_login().await.expect("QR login failed"); 73 | } 74 | 2 => { 75 | let (mut account, mut password) = (String::new(), String::new()); 76 | std::io::stdin() 77 | .read_line(&mut account) 78 | .expect("error: unable to read user input"); 79 | std::io::stdin() 80 | .read_line(&mut password) 81 | .expect("error: unable to read user input"); 82 | sdk.password_login(account.trim(), password.trim()) 83 | .await 84 | .expect("Password login failed"); 85 | } 86 | 3 => { 87 | let (mut area_code, mut phone) = (String::new(), String::new()); 88 | std::io::stdin() 89 | .read_line(&mut area_code) 90 | .expect("error: unable to read user input"); 91 | std::io::stdin() 92 | .read_line(&mut phone) 93 | .expect("error: unable to read user input"); 94 | sdk.mobile_login(area_code.trim(), phone.trim()) 95 | .await 96 | .expect("Captcha login failed"); 97 | } 98 | _ => panic!("Invalid login type"), 99 | } 100 | println!("{}", sdk.save_token().expect("Save token failed")); 101 | 102 | let (account_uid, combo_token) = sdk.login_combo().await.expect("Game login failed"); 103 | 104 | let dispatch_info = http::gate::get_regions( 105 | GATE_NAME, 106 | VERSION, 107 | LANGUAGE, 108 | CHANNEL_ID, 109 | SUB_CHANNEL_ID, 110 | PLATFORM, 111 | ) 112 | .await 113 | .expect("Failed to get regions"); 114 | for region in dispatch_info.region_list { 115 | println!("{}: {}", region.title, region.retcode); 116 | if region.biz == BIZ { 117 | let region_info = http::gate::get_region( 118 | ®ion.dispatch_url, 119 | VERSION, 120 | RSA_VER, 121 | LANGUAGE, 122 | PLATFORM, 123 | DISPATCH_SEED, 124 | CHANNEL_ID, 125 | SUB_CHANNEL_ID, 126 | ) 127 | .await 128 | .expect("Failed to get region"); 129 | 130 | println!("{}: {}", region_info.title, region_info.retcode); 131 | if region_info.retcode == 0 { 132 | let gateway = region_info.gateway.unwrap(); 133 | println!("{}: {}", gateway.ip, gateway.port); 134 | let client_secret_key = region_info.client_secret_key.unwrap(); 135 | 136 | let addr = SocketAddr::new( 137 | IpAddr::V4(gateway.ip.parse::().unwrap()), 138 | gateway.port, 139 | ); 140 | 141 | let mut session = match session::Session::new( 142 | addr, 143 | RSA_VER, 144 | &client_secret_key, 145 | &account_uid, 146 | &combo_token, 147 | DEVICE, 148 | ) 149 | .await 150 | { 151 | Ok(v) => v, 152 | Err(e) => panic!("Failed to create session: {}", e), 153 | }; 154 | 155 | let _ = session.get_token().await; 156 | 157 | break; 158 | } 159 | } 160 | } 161 | 162 | sleep(Duration::from_secs(60)); 163 | } 164 | -------------------------------------------------------------------------------- /src/http/gate.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::common::rsa; 4 | use std::collections::HashMap; 5 | 6 | #[derive(serde::Deserialize)] 7 | pub struct RegionSimpleInfo { 8 | pub area: i32, 9 | pub biz: String, 10 | pub dispatch_url: String, 11 | pub env: i32, 12 | pub is_recommend: bool, 13 | pub name: String, 14 | pub retcode: i32, 15 | pub title: String, 16 | } 17 | 18 | #[derive(serde::Deserialize)] 19 | pub struct DispatchInfo { 20 | pub region_list: Vec, 21 | pub retcode: i32, 22 | } 23 | 24 | pub async fn get_regions( 25 | dispatch_name: &str, 26 | version: &str, 27 | language: u32, 28 | channel_id: u32, 29 | sub_channel_id: u32, 30 | platform: u32, 31 | ) -> Result { 32 | let mut domain = HashMap::new(); 33 | domain.insert("cn", "https://globaldp-prod-cn01.juequling.com/"); 34 | domain.insert("os", ""); 35 | 36 | let mut params = HashMap::new(); 37 | params.insert("version", version.to_string()); 38 | params.insert("language", language.to_string()); 39 | params.insert("channel_id", channel_id.to_string()); 40 | params.insert("sub_channel_id", sub_channel_id.to_string()); 41 | params.insert("platform", platform.to_string()); 42 | 43 | let url = match reqwest::Url::parse_with_params( 44 | format!("{}{}", domain[dispatch_name], "query_dispatch").as_str(), 45 | ¶ms, 46 | ) { 47 | Ok(url) => url, 48 | Err(e) => return Err(format!("Failed to parse url: {}", e)), 49 | }; 50 | let res = match reqwest::get(url).await { 51 | Ok(res) => res, 52 | Err(e) => return Err(format!("Failed to send request: {}", e)), 53 | }; 54 | 55 | return match res.json::().await { 56 | Ok(json) => Ok(json), 57 | Err(e) => Err(format!("Failed to parse json: {}", e)), 58 | }; 59 | } 60 | 61 | #[derive(serde::Deserialize)] 62 | pub struct DesignData { 63 | pub base_url: String, 64 | pub data_revision: String, 65 | pub md5_files: String, 66 | } 67 | 68 | #[derive(serde::Deserialize)] 69 | pub struct GameRes { 70 | pub audio_revision: String, 71 | pub base_url: String, 72 | pub branch: String, 73 | pub md5_files: String, 74 | pub res_revision: String, 75 | } 76 | 77 | #[derive(serde::Deserialize)] 78 | pub struct SilenceData { 79 | pub base_url: String, 80 | pub md5_files: String, 81 | pub silence_revision: String, 82 | } 83 | 84 | #[derive(serde::Deserialize)] 85 | pub struct CdnConfExt { 86 | pub design_data: DesignData, 87 | pub game_res: GameRes, 88 | pub silence_data: SilenceData, 89 | } 90 | 91 | #[derive(serde::Deserialize)] 92 | pub struct Gateway { 93 | pub ip: String, 94 | pub port: u16, 95 | } 96 | 97 | #[derive(serde::Deserialize)] 98 | pub struct FuncSwitch { 99 | #[serde(rename = "Close_Medium_Package_Download")] 100 | pub close_medium_package_download: i32, 101 | #[serde(rename = "Disable_Audio_Download")] 102 | pub disable_audio_download: i32, 103 | #[serde(rename = "Disable_Frequent_attempts")] 104 | pub disable_frequent_attempts: i32, 105 | #[serde(rename = "Hide_Download_complete_resources")] 106 | pub hide_download_complete_resources: i32, 107 | #[serde(rename = "Hide_Download_resources_popups")] 108 | pub hide_download_resources_popups: i32, 109 | #[serde(rename = "Hide_download_progress")] 110 | pub hide_download_progress: i32, 111 | #[serde(rename = "Medium_Package_Play")] 112 | pub medium_package_play: i32, 113 | #[serde(rename = "Play_The_Music")] 114 | pub play_the_music: i32, 115 | #[serde(rename = "disableAnimAllocatorOpt")] 116 | pub disable_anim_allocator_opt: i32, 117 | #[serde(rename = "disableAsyncSRPSubmit")] 118 | pub disable_async_srp_submit: i32, 119 | #[serde(rename = "disableAsyncUploadJob")] 120 | pub disable_async_upload_job: i32, 121 | #[serde(rename = "disableExecuteAsync")] 122 | pub disable_execute_async: i32, 123 | #[serde(rename = "disableLoadSceneParallel")] 124 | pub disable_load_scene_parallel: i32, 125 | #[serde(rename = "disableMetalPSOCreateAsync")] 126 | pub disable_metal_pso_create_async: i32, 127 | #[serde(rename = "disableObjectInstanceCache")] 128 | pub disable_object_instance_cache: i32, 129 | #[serde(rename = "disableSRPHelper")] 130 | pub disable_srp_helper: i32, 131 | #[serde(rename = "disableSRPInstancing")] 132 | pub disable_srp_instancing: i32, 133 | #[serde(rename = "disableSkinMeshStrip")] 134 | pub disable_skin_mesh_strip: i32, 135 | #[serde(rename = "disableStepPreloadMonster")] 136 | pub disable_step_preload_monster: i32, 137 | #[serde(rename = "disableTexStreamingVisbilityOpt")] 138 | pub disable_tex_streaming_visbility_opt: i32, 139 | #[serde(rename = "disableiOSGPUBufferOpt")] 140 | pub disable_ios_gpu_buffer_opt: i32, 141 | #[serde(rename = "disableiOSShaderHibernation")] 142 | pub disable_ios_shader_hibernation: i32, 143 | #[serde(rename = "enableGachaMobileConsole")] 144 | pub enable_gacha_mobile_console: i32, 145 | #[serde(rename = "enableNoticeMobileConsole")] 146 | pub enable_notice_mobile_console: i32, 147 | #[serde(rename = "enableOperationLog")] 148 | pub enable_operation_log: i32, 149 | #[serde(rename = "enableiOSShaderWarmupOnStartup")] 150 | pub enable_ios_shader_warmup_on_startup: i32, 151 | #[serde(rename = "isKcp")] 152 | pub is_kcp: i32, 153 | pub open_hotfix_popups: i32, 154 | } 155 | 156 | #[derive(serde::Deserialize)] 157 | pub struct RegionExt { 158 | pub exchange_url: String, 159 | pub feedback_url: String, 160 | pub func_switch: FuncSwitch, 161 | #[serde(rename = "mtrNap")] 162 | pub mtr_nap: String, 163 | #[serde(rename = "mtrSdk")] 164 | pub mtr_sdk: String, 165 | pub pgc_webview_method: i32, 166 | #[serde(rename = "urlCheckNap")] 167 | pub url_check_nap: String, 168 | #[serde(rename = "urlCheckSdk")] 169 | pub url_check_sdk: String, 170 | } 171 | 172 | #[derive(serde::Deserialize)] 173 | pub struct RegionInfo { 174 | pub cdn_conf_ext: Option, 175 | pub client_secret_key: Option, 176 | pub env: i32, 177 | pub gateway: Option, 178 | pub msg: Option, 179 | pub region_ext: Option, 180 | pub region_name: String, 181 | pub retcode: i32, 182 | pub stop_begin_time: Option, 183 | pub stop_end_time: Option, 184 | pub stop_jump_url: Option, 185 | pub title: String, 186 | } 187 | 188 | #[derive(serde::Deserialize)] 189 | struct QueryGateway { 190 | content: String, 191 | sign: String, 192 | } 193 | 194 | pub async fn get_region( 195 | dispatch_url: &str, 196 | version: &str, 197 | rsa_ver: u32, 198 | language: u32, 199 | platform: u32, 200 | dispatch_seed: &str, 201 | channel_id: u32, 202 | sub_channel_id: u32, 203 | ) -> Result { 204 | let mut params = HashMap::new(); 205 | params.insert("version", version.to_string()); 206 | params.insert("rsa_ver", rsa_ver.to_string()); 207 | params.insert("language", language.to_string()); 208 | params.insert("platform", platform.to_string()); 209 | params.insert("seed", dispatch_seed.to_string()); 210 | params.insert("channel_id", channel_id.to_string()); 211 | params.insert("sub_channel_id", sub_channel_id.to_string()); 212 | 213 | let url = match reqwest::Url::parse_with_params(dispatch_url, ¶ms) { 214 | Ok(url) => url, 215 | Err(e) => return Err(format!("Failed to parse url: {}", e)), 216 | }; 217 | let res = match reqwest::get(url).await { 218 | Ok(res) => res, 219 | Err(e) => return Err(format!("Failed to send request: {}", e)), 220 | }; 221 | 222 | let json = match res.json::().await { 223 | Ok(json) => json, 224 | Err(e) => return Err(format!("Failed to parse QueryGateway: {}", e)), 225 | }; 226 | 227 | let decrypted = match rsa::rsa_decrypt(&json.content, rsa_ver) { 228 | Ok(decrypted) => decrypted, 229 | Err(e) => return Err(format!("Failed to decrypt content: {}", e)), 230 | }; 231 | 232 | match rsa::rsa_verify_sign(&decrypted, &json.sign, rsa_ver) { 233 | Ok(true) => (), 234 | Ok(false) => return Err("Failed to verify sign".to_string()), 235 | Err(e) => return Err(format!("Failed to verify sign: {}", e)), 236 | }; 237 | 238 | let content = match String::from_utf8(decrypted) { 239 | Ok(s) => s, 240 | Err(e) => return Err(format!("failed to convert to utf8: {}", e)), 241 | }; 242 | 243 | return match serde_json::from_str::(&content) { 244 | Ok(region_info) => Ok(region_info), 245 | Err(e) => Err(format!("Failed to parse RegionInfo: {}", e)), 246 | }; 247 | } 248 | -------------------------------------------------------------------------------- /src/http/sdk.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use rand::Rng; 4 | use regex::Regex; 5 | use std::{thread::sleep, time::Duration}; 6 | 7 | const SDK_DOMAIN: &str = "https://nap-sdk.mihoyo.com/"; 8 | const GAME_API_DOMAIN: &str = "https://gameapi-account.mihoyo.com/"; 9 | 10 | struct Device { 11 | device_fp: String, 12 | device_id: String, 13 | device_model: String, 14 | device_name: String, 15 | lifecycle_id: String, 16 | } 17 | 18 | #[derive(serde::Serialize, serde::Deserialize)] 19 | struct AccountData { 20 | uid: String, 21 | token: String, 22 | } 23 | 24 | pub struct Sdk { 25 | device: Device, 26 | headers: reqwest::header::HeaderMap, 27 | 28 | account: Option, 29 | 30 | // callback function 31 | qrcode_callback: Option ()>, 32 | captcha_callback: Option String>, 33 | geetest_callback: Option (String, String)>, 34 | } 35 | 36 | #[derive(serde::Deserialize)] 37 | struct Response { 38 | retcode: i32, 39 | message: String, 40 | data: Option, 41 | } 42 | 43 | #[derive(serde::Serialize)] 44 | struct FetchQrcodeRequest { 45 | app_id: String, 46 | device: String, 47 | } 48 | 49 | #[derive(serde::Deserialize)] 50 | struct FetchQrcodeResponse { 51 | url: String, 52 | } 53 | 54 | #[derive(serde::Deserialize)] 55 | struct Raw { 56 | token: String, 57 | is_bbs: String, 58 | uid: String, 59 | mid: String, 60 | is_v2_token: bool, 61 | } 62 | 63 | #[derive(serde::Deserialize)] 64 | struct Payload { 65 | proto: String, 66 | raw: String, 67 | ext: String, 68 | } 69 | 70 | #[derive(serde::Serialize)] 71 | struct QueryQrcodeStatusRequest { 72 | app_id: String, 73 | device: String, 74 | ticket: String, 75 | } 76 | 77 | #[derive(serde::Deserialize)] 78 | struct QueryQrcodeStatusResponse { 79 | stat: String, 80 | payload: Payload, 81 | } 82 | 83 | #[derive(serde::Deserialize)] 84 | struct Geetest { 85 | challenge: String, 86 | gt: String, 87 | new_captcha: i32, 88 | success: i32, 89 | } 90 | 91 | #[serde_with::skip_serializing_none] 92 | #[derive(serde::Serialize)] 93 | struct CheckRiskyRequest { 94 | action_type: String, 95 | api_name: String, 96 | username: Option, 97 | mobile: Option, 98 | } 99 | 100 | #[derive(serde::Deserialize)] 101 | struct CheckRiskyResponse { 102 | id: String, 103 | action: String, 104 | geetest: Option, 105 | } 106 | 107 | #[derive(serde::Serialize)] 108 | struct PasswordLoginRequest { 109 | account: String, 110 | password: String, 111 | is_crypto: bool, 112 | } 113 | 114 | #[derive(serde::Deserialize)] 115 | struct PasswordLoginResponse { 116 | account: Account, 117 | device_grant_required: bool, 118 | safe_moblie_required: bool, 119 | realperson_required: bool, 120 | reactivate_required: bool, 121 | realname_operation: String, 122 | } 123 | 124 | #[derive(serde::Serialize)] 125 | struct SendCaptchaRequest { 126 | mobile: String, 127 | area: String, 128 | } 129 | 130 | #[derive(serde::Deserialize)] 131 | struct SendCaptchaResponse { 132 | action: String, 133 | } 134 | 135 | #[derive(serde::Serialize)] 136 | struct SubmitCaptchaRequest { 137 | mobile: String, 138 | captcha: String, 139 | action: String, 140 | area: String, 141 | } 142 | 143 | #[derive(serde::Deserialize)] 144 | struct Account { 145 | uid: String, 146 | name: String, 147 | email: String, 148 | mobile: String, 149 | is_email_verify: String, 150 | realname: String, 151 | identity_card: String, 152 | token: String, // game_token 153 | safe_mobile: String, 154 | facebook_name: String, 155 | google_name: String, 156 | twitter_name: String, 157 | game_center_name: String, 158 | apple_name: String, 159 | sony_name: String, 160 | tap_name: String, 161 | country: String, 162 | reactivate_ticket: String, 163 | area_code: String, 164 | device_grant_ticket: String, 165 | steam_name: String, 166 | unmasked_email: String, 167 | unmasked_email_type: i32, 168 | cx_name: String, 169 | } 170 | 171 | #[derive(serde::Deserialize)] 172 | struct SubmitCaptchaResponse { 173 | account: Account, 174 | realperson_required: bool, 175 | realname_operation: String, 176 | reactivate_required: bool, 177 | } 178 | 179 | #[derive(serde::Serialize)] 180 | struct AuthData { 181 | uid: String, 182 | guest: bool, 183 | token: String, 184 | } 185 | 186 | #[serde_with::skip_serializing_none] 187 | #[derive(serde::Serialize)] 188 | struct LoginGameRequest { 189 | data: String, 190 | app_id: i32, 191 | channel_id: i32, 192 | device: String, 193 | sign: Option, 194 | } 195 | 196 | #[derive(serde::Deserialize)] 197 | struct LoginGameResponse { 198 | combo_id: String, 199 | open_id: String, 200 | combo_token: String, 201 | data: String, 202 | heartbeat: bool, 203 | account_type: i32, 204 | fatigue_remind: Option<()>, 205 | } 206 | 207 | fn rand_hex_string(rng: &mut R, len: usize) -> String { 208 | const HEX_CHARS: [char; 16] = [ 209 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 210 | ]; 211 | let mut s = String::new(); 212 | for _ in 0..len { 213 | s.push(HEX_CHARS[rng.gen_range(0..16)]); 214 | } 215 | return s; 216 | } 217 | 218 | impl Sdk { 219 | pub fn new( 220 | qrcode_callback: Option, 221 | captcha_callback: Option String>, 222 | geetest_callback: Option (String, String)>, 223 | ) -> Self { 224 | let mut rng = rand::thread_rng(); 225 | let device = Device { 226 | device_fp: rand_hex_string(&mut rng, 13), 227 | device_id: rand_hex_string(&mut rng, 53), 228 | device_model: "iMac".to_string(), 229 | device_name: "Simulator".to_string(), 230 | lifecycle_id: uuid::Uuid::new_v4().to_string(), 231 | }; 232 | 233 | let mut headers = reqwest::header::HeaderMap::new(); 234 | headers.insert( 235 | reqwest::header::USER_AGENT, 236 | reqwest::header::HeaderValue::from_static( 237 | "UnityPlayer/2019.4.40f1 (UnityWebRequest/1.0, libcurl/7.80.0-DEV)", 238 | ), 239 | ); 240 | headers.insert( 241 | reqwest::header::ACCEPT, 242 | reqwest::header::HeaderValue::from_static("*/*"), 243 | ); 244 | headers.insert( 245 | reqwest::header::ACCEPT_ENCODING, 246 | reqwest::header::HeaderValue::from_static("deflate, gzip"), 247 | ); 248 | headers.insert( 249 | "x-rpc-client_type", 250 | reqwest::header::HeaderValue::from_static("3"), 251 | ); 252 | headers.insert( 253 | "x-rpc-sys_version", 254 | reqwest::header::HeaderValue::from_static("Windows 10"), 255 | ); 256 | headers.insert( 257 | "x-rpc-device_id", 258 | reqwest::header::HeaderValue::from_str(&device.device_id).unwrap(), 259 | ); 260 | headers.insert( 261 | "x-rpc-device_model", 262 | reqwest::header::HeaderValue::from_str(&device.device_model).unwrap(), 263 | ); 264 | headers.insert( 265 | "x-rpc-device_name", 266 | reqwest::header::HeaderValue::from_str(&device.device_name).unwrap(), 267 | ); 268 | headers.insert( 269 | "x-rpc-mdk_version", 270 | reqwest::header::HeaderValue::from_static("2.23.0.0"), 271 | ); 272 | headers.insert( 273 | "x-rpc-channel_version", 274 | reqwest::header::HeaderValue::from_static("2.23.0.0"), 275 | ); 276 | headers.insert( 277 | "x-rpc-channel_id", 278 | reqwest::header::HeaderValue::from_static("1"), 279 | ); 280 | headers.insert( 281 | "x-rpc-sub_channel_id", 282 | reqwest::header::HeaderValue::from_static("1"), 283 | ); 284 | headers.insert( 285 | "x-rpc-language", 286 | reqwest::header::HeaderValue::from_static("zh-cn"), 287 | ); 288 | headers.insert( 289 | "x-rpc-game_biz", 290 | reqwest::header::HeaderValue::from_static("nap_cn"), 291 | ); 292 | headers.insert( 293 | "x-rpc-combo_version", 294 | reqwest::header::HeaderValue::from_static("2.23.0"), 295 | ); 296 | headers.insert( 297 | "x-rpc-payment_version", 298 | reqwest::header::HeaderValue::from_static("2.23.0"), 299 | ); 300 | headers.insert( 301 | "x-rpc-goods_third_party", 302 | reqwest::header::HeaderValue::from_static("unsupported"), 303 | ); 304 | headers.insert( 305 | "x-rpc-device_fp", 306 | reqwest::header::HeaderValue::from_str(&device.device_fp).unwrap(), 307 | ); 308 | headers.insert( 309 | "x-rpc-lifecycle_id", 310 | reqwest::header::HeaderValue::from_str(&device.lifecycle_id).unwrap(), 311 | ); 312 | headers.insert( 313 | "X-Unity-Version", 314 | reqwest::header::HeaderValue::from_static("2019.4.40f1"), 315 | ); 316 | 317 | Sdk { 318 | device, 319 | headers, 320 | account: Option::None, 321 | qrcode_callback, 322 | captcha_callback, 323 | geetest_callback, 324 | } 325 | } 326 | 327 | async fn fetch_qrcode(&self) -> Result { 328 | let data = FetchQrcodeRequest { 329 | app_id: "12".to_string(), 330 | device: self.device.device_id.clone(), 331 | }; 332 | 333 | let res = match reqwest::Client::new() 334 | .post(format!("{}{}", SDK_DOMAIN, "nap_cn/combo/panda/qrcode/fetch").as_str()) 335 | .headers(self.headers.clone()) 336 | .json(&data) 337 | .send() 338 | .await 339 | { 340 | Ok(res) => res, 341 | Err(e) => return Err(format!("Failed to send request: {}", e)), 342 | }; 343 | 344 | let json = match res.json::>().await { 345 | Ok(json) => json, 346 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 347 | }; 348 | 349 | if json.retcode != 0 { 350 | return Err(format!( 351 | "Failed to fetch qrcode, retcode: {}, message: {}", 352 | json.retcode, json.message 353 | )); 354 | } 355 | 356 | return Ok(json.data.unwrap().url); 357 | } 358 | 359 | async fn query_qrcode_status(&self, ticket: &str) -> Result { 360 | let data = QueryQrcodeStatusRequest { 361 | app_id: "12".to_string(), 362 | device: self.device.device_id.clone(), 363 | ticket: ticket.to_string(), 364 | }; 365 | 366 | let res = match reqwest::Client::new() 367 | .post(format!("{}{}", SDK_DOMAIN, "nap_cn/combo/panda/qrcode/query").as_str()) 368 | .headers(self.headers.clone()) 369 | .json(&data) 370 | .send() 371 | .await 372 | { 373 | Ok(res) => res, 374 | Err(e) => return Err(format!("Failed to send request: {}", e)), 375 | }; 376 | 377 | let json = match res.json::>().await { 378 | Ok(json) => json, 379 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 380 | }; 381 | 382 | if json.retcode != 0 { 383 | return Err(format!( 384 | "Failed to query qrcode, retcode: {}, message: {}", 385 | json.retcode, json.message 386 | )); 387 | } 388 | 389 | return Ok(json.data.unwrap()); 390 | } 391 | 392 | pub async fn qr_login(&mut self) -> Result<(), String> { 393 | let qrcode_url = self.fetch_qrcode().await.expect("Failed to fetch qrcode"); 394 | (self.qrcode_callback.expect("qrcode callback is null"))(&qrcode_url); 395 | 396 | let re = Regex::new(r"&ticket=([^&]*)").unwrap(); 397 | let ticket = re.captures(&qrcode_url).unwrap().get(1).unwrap().as_str(); 398 | 399 | loop { 400 | let result = self 401 | .query_qrcode_status(ticket) 402 | .await 403 | .expect("Failed to check qrcode status"); 404 | match result.stat.as_str() { 405 | "Init" => {} 406 | "Scanned" => {} 407 | "Confirmed" => { 408 | let raw = serde_json::from_str::(&result.payload.raw).unwrap(); 409 | self.account = Option::Some(AccountData { 410 | uid: raw.uid, 411 | token: raw.token, //stoken 412 | }); 413 | return Ok(()); 414 | } 415 | _ => return Err(format!("Unknown status: {}", result.stat)), 416 | } 417 | sleep(Duration::from_secs(1)); 418 | } 419 | } 420 | 421 | async fn check_risky( 422 | &self, 423 | action_type: &str, 424 | api_name: &str, 425 | username: Option<&str>, 426 | mobile: Option<&str>, 427 | ) -> Result { 428 | let data = CheckRiskyRequest { 429 | action_type: action_type.to_string(), 430 | api_name: api_name.to_string(), 431 | username: username.and_then(|s| Option::Some(s.to_string())), 432 | mobile: mobile.and_then(|s| Option::Some(s.to_string())), 433 | }; 434 | 435 | let res = match reqwest::Client::new() 436 | .post(format!("{}{}", GAME_API_DOMAIN, "account/risky/api/check").as_str()) 437 | .headers(self.headers.clone()) 438 | .json(&data) 439 | .send() 440 | .await 441 | { 442 | Ok(res) => res, 443 | Err(e) => return Err(format!("Failed to send request: {}", e)), 444 | }; 445 | 446 | let json = match res.json::>().await { 447 | Ok(json) => json, 448 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 449 | }; 450 | 451 | if json.retcode != 0 { 452 | return Err(format!( 453 | "Failed to check risky, retcode: {}, message: {}", 454 | json.retcode, json.message 455 | )); 456 | } 457 | 458 | let data = json.data.unwrap(); 459 | let (mut challenge, mut seccode, mut validate) = 460 | (String::new(), String::new(), String::new()); 461 | match data.action.as_str() { 462 | "ACTION_NONE" => {} 463 | "ACTION_GEETEST" => { 464 | let geetest = data.geetest.unwrap(); 465 | challenge = geetest.challenge; 466 | (seccode, validate) = (self.geetest_callback.expect("geetest callback is null"))( 467 | challenge.as_str(), 468 | geetest.gt.as_str(), 469 | ); 470 | } 471 | _ => { 472 | return Err(format!( 473 | "Failed to check risky, action: {}, id: {}", 474 | data.action, data.id 475 | )); 476 | } 477 | } 478 | return Ok(format!( 479 | "id={};c={};s={};v={}", 480 | data.id, challenge, seccode, validate 481 | )); 482 | } 483 | 484 | pub async fn password_login(&mut self, account: &str, password: &str) -> Result<(), String> { 485 | const ACTION_TYPE: &str = "login"; 486 | const LOGIN_API_NAME: &str = "/shield/api/login"; 487 | let risky = match self 488 | .check_risky( 489 | ACTION_TYPE, 490 | LOGIN_API_NAME, 491 | Option::Some(account), 492 | Option::None, 493 | ) 494 | .await 495 | { 496 | Ok(risky) => risky, 497 | Err(e) => return Err(e), 498 | }; 499 | 500 | let mut headers = self.headers.clone(); 501 | headers.insert( 502 | "x-rpc-risky", 503 | reqwest::header::HeaderValue::from_str(&risky).unwrap(), 504 | ); 505 | 506 | let data = PasswordLoginRequest { 507 | account: account.to_string(), 508 | password: crate::common::rsa::password_encrypt(password).unwrap(), 509 | is_crypto: true, 510 | }; 511 | 512 | let res = match reqwest::Client::new() 513 | .post(format!("{}{}{}", SDK_DOMAIN, "nap_cn/mdk", LOGIN_API_NAME).as_str()) 514 | .headers(headers) 515 | .json(&data) 516 | .send() 517 | .await 518 | { 519 | Ok(res) => res, 520 | Err(e) => return Err(format!("Failed to send request: {}", e)), 521 | }; 522 | 523 | let json = match res.json::>().await { 524 | Ok(json) => json, 525 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 526 | }; 527 | 528 | if json.retcode != 0 { 529 | return Err(format!( 530 | "Failed to login, retcode: {}, message: {}", 531 | json.retcode, json.message 532 | )); 533 | } 534 | 535 | let d = json.data.unwrap(); 536 | 537 | self.account = Option::Some(AccountData { 538 | uid: d.account.uid, 539 | token: d.account.token, 540 | }); 541 | 542 | return Ok(()); 543 | } 544 | 545 | async fn send_captcha(&self, area: &str, mobile: &str) -> Result<(), String> { 546 | const ACTION_TYPE: &str = "login"; 547 | const SEND_CAPTCHA_API_NAME: &str = "/shield/api/loginCaptcha"; 548 | let risky = match self 549 | .check_risky( 550 | ACTION_TYPE, 551 | SEND_CAPTCHA_API_NAME, 552 | Option::None, 553 | Option::Some(mobile), 554 | ) 555 | .await 556 | { 557 | Ok(risky) => risky, 558 | Err(e) => return Err(e), 559 | }; 560 | 561 | let mut headers = self.headers.clone(); 562 | headers.insert( 563 | "x-rpc-risky", 564 | reqwest::header::HeaderValue::from_str(&risky).unwrap(), 565 | ); 566 | 567 | let data = SendCaptchaRequest { 568 | mobile: mobile.to_string(), 569 | area: area.to_string(), 570 | }; 571 | 572 | let res = match reqwest::Client::new() 573 | .post(format!("{}{}{}", SDK_DOMAIN, "nap_cn/mdk", SEND_CAPTCHA_API_NAME).as_str()) 574 | .headers(headers) 575 | .json(&data) 576 | .send() 577 | .await 578 | { 579 | Ok(res) => res, 580 | Err(e) => return Err(format!("Failed to send request: {}", e)), 581 | }; 582 | 583 | let json = match res.json::>().await { 584 | Ok(json) => json, 585 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 586 | }; 587 | 588 | if json.retcode != 0 { 589 | return Err(format!( 590 | "Failed to send captcha, retcode: {}, message: {}", 591 | json.retcode, json.message 592 | )); 593 | } 594 | 595 | return Ok(()); 596 | } 597 | 598 | async fn submit_captcha( 599 | &self, 600 | area: &str, 601 | mobile: &str, 602 | captcha: &str, 603 | ) -> Result { 604 | let data = SubmitCaptchaRequest { 605 | mobile: mobile.to_string(), 606 | captcha: captcha.to_string(), 607 | action: "Login".to_string(), 608 | area: area.to_string(), 609 | }; 610 | 611 | let res = match reqwest::Client::new() 612 | .post(format!("{}{}", SDK_DOMAIN, "nap_cn/mdk/shield/api/loginCaptcha").as_str()) 613 | .headers(self.headers.clone()) 614 | .json(&data) 615 | .send() 616 | .await 617 | { 618 | Ok(res) => res, 619 | Err(e) => return Err(format!("Failed to send request: {}", e)), 620 | }; 621 | 622 | let json = match res.json::>().await { 623 | Ok(json) => json, 624 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 625 | }; 626 | 627 | if json.retcode != 0 { 628 | return Err(format!( 629 | "Failed to submit captcha, retcode: {}, message: {}", 630 | json.retcode, json.message 631 | )); 632 | } 633 | return Ok(json.data.unwrap()); 634 | } 635 | 636 | pub async fn mobile_login(&mut self, area: &str, mobile: &str) -> Result<(), String> { 637 | self.send_captcha(area, mobile).await?; 638 | 639 | let captcha = (self.captcha_callback.expect("captcha callback is null"))(); 640 | 641 | let d = self.submit_captcha(area, mobile, &captcha).await?; 642 | self.account = Option::Some(AccountData { 643 | uid: d.account.uid, 644 | token: d.account.token, 645 | }); 646 | 647 | return Ok(()); 648 | } 649 | 650 | pub fn save_token(&self) -> Result { 651 | if self.account.is_none() { 652 | return Err("Account is not logged in".to_string()); 653 | } 654 | let account = self.account.as_ref().unwrap(); 655 | let data = AccountData { 656 | uid: account.uid.clone(), 657 | token: account.token.clone(), 658 | }; 659 | return Ok(serde_json::to_string(&data).unwrap()); 660 | } 661 | 662 | pub fn load_token(&mut self, data: &str) -> Result<(), String> { 663 | let account = match serde_json::from_str::(data) { 664 | Ok(account) => account, 665 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 666 | }; 667 | self.account = Option::Some(account); 668 | return Ok(()); 669 | } 670 | 671 | pub async fn login_combo(&self) -> Result<(String, String), String> { 672 | if self.account.is_none() { 673 | return Err("Account is not logged in".to_string()); 674 | } 675 | let account = self.account.as_ref().unwrap(); 676 | let auth_data = AuthData { 677 | uid: account.uid.clone(), 678 | guest: false, 679 | token: account.token.clone(), // stoken_v2 or game_token 680 | }; 681 | let inr_data = serde_json::to_string(&auth_data).unwrap(); 682 | 683 | let mut data = LoginGameRequest { 684 | data: inr_data, 685 | app_id: 12, 686 | channel_id: 1, 687 | device: self.device.device_id.clone(), 688 | sign: Option::None, 689 | }; 690 | 691 | data.sign = Option::Some(crate::common::hmac::sign_data(&data)); 692 | 693 | let res = match reqwest::Client::new() 694 | .post(format!("{}{}", SDK_DOMAIN, "nap_cn/combo/granter/login/v2/login").as_str()) 695 | .headers(self.headers.clone()) 696 | .json(&data) 697 | .send() 698 | .await 699 | { 700 | Ok(res) => res, 701 | Err(e) => return Err(format!("Failed to send request: {}", e)), 702 | }; 703 | 704 | let json = match res.json::>().await { 705 | Ok(json) => json, 706 | Err(e) => return Err(format!("Failed to parse json: {}", e)), 707 | }; 708 | 709 | if json.retcode != 0 { 710 | return Err(format!( 711 | "Failed to get combo token, retcode: {}, message: {}", 712 | json.retcode, json.message 713 | )); 714 | } 715 | 716 | let data = json.data.unwrap(); 717 | 718 | return Ok((data.open_id, data.combo_token)); 719 | } 720 | } 721 | -------------------------------------------------------------------------------- /src/common/ec2b/magic.rs: -------------------------------------------------------------------------------- 1 | // https://git.xeondev.com/NewEriduPubSec/JaneDoe-ZS/src/branch/master/nap_common/src/cryptography/ec2b/magic.rs 2 | 3 | #![allow(unused)] 4 | 5 | pub const SHIFT_ROWS_TABLE: [u8; 16] = [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11]; 6 | pub const SHIFT_ROWS_TABLE_INV: [u8; 16] = [0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3]; 7 | pub const LOOKUP_RCON: [u8; 16] = [ 8 | 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 9 | ]; 10 | pub const LOOKUP_SBOX: [u8; 256] = [ 11 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 12 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 13 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 14 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 15 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 16 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 17 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 18 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 19 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 20 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 21 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 22 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 23 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 24 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 25 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 26 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, 27 | ]; 28 | pub const LOOKUP_SBOX_INV: [u8; 256] = [ 29 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 30 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 31 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 32 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 33 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 34 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 35 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 36 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 37 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 38 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 39 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 40 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 41 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 42 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 43 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 44 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, 45 | ]; 46 | pub const LOOKUP_G2: [u8; 256] = [ 47 | 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 48 | 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 49 | 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 50 | 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 51 | 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 52 | 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 53 | 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 54 | 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 55 | 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, 56 | 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, 57 | 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 58 | 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, 59 | 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, 60 | 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 61 | 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, 62 | 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5, 63 | ]; 64 | pub const LOOKUP_G3: [u8; 256] = [ 65 | 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 66 | 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 67 | 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, 68 | 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, 69 | 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 70 | 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, 71 | 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, 72 | 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 73 | 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, 74 | 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, 75 | 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 76 | 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, 77 | 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, 78 | 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 79 | 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, 80 | 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a, 81 | ]; 82 | pub const LOOKUP_G9: [u8; 256] = [ 83 | 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 84 | 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 85 | 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 86 | 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, 87 | 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 88 | 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, 89 | 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, 90 | 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 91 | 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, 92 | 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, 93 | 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 94 | 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, 95 | 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, 96 | 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 97 | 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, 98 | 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46, 99 | ]; 100 | pub const LOOKUP_G11: [u8; 256] = [ 101 | 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 102 | 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 103 | 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, 104 | 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, 105 | 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 106 | 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, 107 | 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, 108 | 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 109 | 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, 110 | 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, 111 | 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 112 | 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, 113 | 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, 114 | 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 115 | 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, 116 | 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3, 117 | ]; 118 | pub const LOOKUP_G13: [u8; 256] = [ 119 | 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 120 | 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 121 | 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, 122 | 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, 123 | 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 124 | 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, 125 | 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, 126 | 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 127 | 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, 128 | 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, 129 | 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 130 | 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, 131 | 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, 132 | 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 133 | 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, 134 | 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97, 135 | ]; 136 | pub const LOOKUP_G14: [u8; 256] = [ 137 | 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 138 | 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 139 | 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, 140 | 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, 141 | 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 142 | 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, 143 | 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, 144 | 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 145 | 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, 146 | 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, 147 | 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 148 | 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, 149 | 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, 150 | 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 151 | 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, 152 | 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d, 153 | ]; 154 | pub const KEY_XORPAD_TABLE: [u8; 16] = [ 155 | 0xA2, 0x25, 0x25, 0x99, 0xB7, 0x62, 0xF4, 0x39, 0x28, 0xE1, 0xB7, 0x73, 0x91, 0x05, 0x25, 0x87, 156 | ]; 157 | pub const AES_XORPAD_TABLE: [[u8; 2816]; 2] = [ 158 | [ 159 | 0xDE, 0xAD, 0xCA, 0xFE, 0xFA, 0xCE, 0xB0, 0x0C, 0xDE, 0xAD, 0xCA, 0xFE, 0xFA, 0xCE, 0xB0, 160 | 0x0C, 0x3A, 0xE6, 0xDE, 0x9C, 0x81, 0xBA, 0x7C, 0xC6, 0x12, 0x1B, 0xAF, 0xD2, 0x8A, 0xBA, 161 | 0xF5, 0xE6, 0x41, 0xDF, 0x71, 0xBA, 0x37, 0x11, 0x50, 0xF3, 0xF3, 0x62, 0x6E, 0x04, 0xF1, 162 | 0x14, 0xFC, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x7B, 0x52, 0x7C, 163 | 0x19, 0x98, 0x35, 0x96, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 164 | 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 165 | 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 166 | 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 167 | 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 168 | 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 169 | 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 170 | 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 171 | 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 172 | 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 173 | 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 174 | 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 175 | 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 176 | 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 177 | 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 178 | 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 179 | 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 180 | 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 181 | 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 182 | 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 183 | 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 184 | 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 185 | 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 186 | 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 187 | 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 188 | 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 189 | 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 190 | 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 191 | 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 192 | 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 193 | 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 194 | 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 195 | 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 196 | 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 197 | 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 198 | 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 199 | 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 200 | 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 201 | 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 202 | 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 203 | 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 204 | 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 205 | 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 206 | 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 207 | 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 208 | 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 209 | 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 210 | 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 211 | 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 212 | 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 213 | 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 214 | 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 215 | 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 216 | 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 217 | 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 218 | 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 219 | 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 220 | 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 221 | 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 222 | 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 223 | 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 224 | 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 225 | 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 226 | 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 227 | 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 228 | 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 229 | 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 230 | 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 231 | 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 232 | 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 233 | 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 234 | 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 235 | 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 236 | 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 237 | 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 238 | 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 239 | 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 240 | 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 241 | 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 242 | 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 243 | 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 244 | 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 245 | 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 246 | 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 247 | 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 248 | 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 249 | 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 250 | 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 251 | 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 252 | 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 253 | 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 254 | 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 255 | 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 256 | 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 257 | 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 258 | 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 259 | 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 260 | 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 261 | 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 262 | 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 263 | 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 264 | 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 265 | 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 266 | 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 267 | 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 268 | 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 269 | 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 270 | 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 271 | 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 272 | 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 273 | 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 274 | 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 275 | 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 276 | 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 277 | 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 278 | 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 279 | 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 280 | 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 281 | 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 282 | 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 283 | 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 284 | 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 285 | 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 286 | 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 287 | 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 288 | 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 289 | 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 290 | 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 291 | 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 292 | 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 293 | 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 294 | 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 295 | 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 296 | 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 297 | 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 298 | 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 299 | 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 300 | 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 301 | 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 302 | 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 303 | 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 304 | 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 305 | 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 306 | 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 307 | 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 308 | 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 309 | 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 310 | 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 311 | 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 312 | 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 313 | 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 314 | 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 315 | 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 316 | 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 317 | 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 318 | 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 319 | 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 320 | 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 321 | 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 322 | 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 323 | 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 324 | 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 325 | 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 326 | 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 327 | 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 328 | 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 329 | 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 330 | 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 331 | 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 332 | 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 333 | 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 334 | 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 335 | 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 336 | 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 337 | 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 338 | 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 0x18, 0x18, 0xE0, 0xAC, 339 | 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 0xB5, 0x0E, 0xB6, 0x3E, 340 | 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 0xD0, 0x69, 0x81, 0x00, 341 | 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 0x82, 0x47, 0x6A, 0xB8, 342 | 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 0x1F, 0x8E, 0xFA, 0x3C, 0x73, 0x62, 0x6A, 0x92, 343 | 0x18, 0x18, 0xE0, 0xAC, 0x9E, 0x71, 0x37, 0x3C, 0x48, 0xDE, 0xDC, 0xA2, 0xE8, 0xBB, 0x35, 344 | 0xB5, 0x0E, 0xB6, 0x3E, 0x71, 0x25, 0x8A, 0xF2, 0x33, 0xE0, 0xD6, 0xBE, 0xF0, 0x3A, 0x93, 345 | 0xD0, 0x69, 0x81, 0x00, 0x53, 0x7E, 0xCA, 0x4E, 0x78, 0x4B, 0xA2, 0xF7, 0xB3, 0xF1, 0x67, 346 | 0x82, 0x47, 0x6A, 0xB8, 0xAA, 0x76, 0xF9, 0xDF, 0x3B, 0xEC, 0x56, 347 | ], 348 | [ 349 | 0xC3, 0x20, 0x20, 0xB4, 0xAF, 0x0E, 0x82, 0x2E, 0xEF, 0x29, 0xFE, 0x75, 0x1D, 0xDB, 0x4B, 350 | 0x86, 0x86, 0x23, 0x28, 0x72, 0xA3, 0xF4, 0x1B, 0x4F, 0x5F, 0x0E, 0x02, 0xB1, 0xAC, 0x0D, 351 | 0xE6, 0x4F, 0x8B, 0x0B, 0x3F, 0xF3, 0x5F, 0xB5, 0x09, 0x7E, 0x3B, 0xE9, 0x93, 0x29, 0x55, 352 | 0xE1, 0xB4, 0x9B, 0xCC, 0xCE, 0x37, 0xFC, 0xAB, 0x6B, 0xA4, 0x05, 0xE6, 0xC7, 0x45, 0x34, 353 | 0xC0, 0xFF, 0x7C, 0x24, 0x89, 0x36, 0xBF, 0x17, 0xAB, 0x91, 0xCA, 0x49, 0xF2, 0x74, 0x80, 354 | 0xB6, 0x90, 0x60, 0xFF, 0xD2, 0xA9, 0xE5, 0xC9, 0x64, 0xBC, 0x38, 0x40, 0x98, 0xB3, 0xBA, 355 | 0x8F, 0x8B, 0xBA, 0x9D, 0xF3, 0xCF, 0x57, 0xBA, 0xAC, 0x18, 0xE7, 0xD3, 0x03, 0x01, 0x48, 356 | 0x29, 0x41, 0xF6, 0x2F, 0x89, 0xD4, 0x9F, 0xD7, 0xD3, 0x05, 0x71, 0x63, 0x30, 0x4E, 0xBB, 357 | 0xF7, 0xB0, 0x99, 0xFF, 0x43, 0xDA, 0x87, 0xCA, 0xA7, 0x48, 0x92, 0x9E, 0x76, 0xA6, 0xEE, 358 | 0x48, 0x1C, 0x96, 0x28, 0x8E, 0x54, 0x30, 0xD6, 0xA5, 0xD3, 0x22, 0xA2, 0x30, 0xCB, 0x6A, 359 | 0x85, 0x26, 0x69, 0xE1, 0x7C, 0xEC, 0xDC, 0xD4, 0x89, 0x2A, 0xB8, 0xAE, 0xDF, 0x12, 0x6E, 360 | 0x39, 0x8A, 0x9B, 0x48, 0x61, 0xF9, 0x4B, 0x34, 0xD0, 0xF1, 0x60, 0x87, 0xBA, 0x88, 0x86, 361 | 0x68, 0x8C, 0xBE, 0xC1, 0x9C, 0xAE, 0x30, 0xBC, 0xE6, 0x62, 0xFF, 0xEB, 0xBB, 0x88, 0x7C, 362 | 0xD2, 0xBB, 0x57, 0xB4, 0x02, 0x82, 0x06, 0x72, 0xD2, 0x94, 0x60, 0x86, 0x4A, 0x29, 0xF0, 363 | 0xEA, 0xD3, 0x88, 0x92, 0xF1, 0x22, 0xD1, 0x5C, 0x88, 0x65, 0xE6, 0xFB, 0xEE, 0x28, 0x79, 364 | 0x86, 0x68, 0x7D, 0xA6, 0x5A, 0xBF, 0xBD, 0x7D, 0x15, 0xEF, 0x05, 0xF6, 0xF9, 0xE0, 0x11, 365 | 0xD6, 0x30, 0x94, 0xF2, 0x6C, 0x3D, 0x0A, 0xDB, 0xC5, 0x0E, 0xDC, 0xF2, 0xFD, 0x1F, 0x61, 366 | 0x91, 0x5D, 0x80, 0x69, 0xA3, 0xDB, 0x35, 0x98, 0x4E, 0x4A, 0xC1, 0x49, 0x76, 0xAB, 0xC0, 367 | 0x67, 0x36, 0x3F, 0xA4, 0xC6, 0xE8, 0xCA, 0x25, 0x44, 0x63, 0x23, 0xB5, 0xC8, 0xBB, 0x3A, 368 | 0xAC, 0xA1, 0x09, 0xC3, 0x10, 0x57, 0xA5, 0x5B, 0x3B, 0x33, 0x21, 0xCD, 0x3C, 0x88, 0xAE, 369 | 0x1E, 0x8F, 0xC1, 0xD6, 0xFB, 0x94, 0x61, 0x38, 0xAB, 0xF1, 0x9C, 0x06, 0xCB, 0x89, 0x58, 370 | 0x9A, 0xF4, 0xF4, 0x33, 0x80, 0x66, 0x13, 0xC0, 0xFD, 0xE2, 0x16, 0xE0, 0x89, 0x65, 0xE2, 371 | 0xC1, 0xA6, 0xE3, 0x74, 0xD2, 0x5F, 0xA0, 0x76, 0xAD, 0xF5, 0x6B, 0x4F, 0xE0, 0xF7, 0x52, 372 | 0xB0, 0xB1, 0x48, 0xDD, 0xEE, 0xB6, 0x01, 0x9A, 0x90, 0x91, 0x18, 0xEC, 0xCB, 0xCB, 0xAD, 373 | 0x04, 0xB6, 0x73, 0xCF, 0x7F, 0xF3, 0xAC, 0xBE, 0xEC, 0x91, 0x44, 0x56, 0x81, 0xB8, 0x74, 374 | 0xAE, 0x28, 0x5D, 0xC7, 0x5C, 0xAB, 0x8B, 0x56, 0x21, 0x32, 0x91, 0xB9, 0x9E, 0x70, 0xF6, 375 | 0x9B, 0xAC, 0x50, 0x0B, 0x2E, 0x4B, 0x8B, 0xA2, 0xA5, 0x24, 0x5B, 0x91, 0xDF, 0x24, 0xA7, 376 | 0xB0, 0x79, 0xA7, 0x16, 0x54, 0x44, 0x2E, 0xBC, 0x48, 0xCD, 0x87, 0xBA, 0xAF, 0xD4, 0xB9, 377 | 0x1C, 0x0F, 0xAA, 0xFA, 0x3A, 0x3F, 0x3A, 0x3D, 0x68, 0x5A, 0xAE, 0xAC, 0xBA, 0xBE, 0xA3, 378 | 0x92, 0x6E, 0x38, 0x8E, 0x33, 0x3E, 0x0A, 0xCC, 0xF6, 0xE3, 0x26, 0x57, 0xEC, 0x8E, 0x63, 379 | 0x31, 0x27, 0xBA, 0x20, 0x4E, 0x7F, 0x34, 0xE5, 0x19, 0xFE, 0x7F, 0xA6, 0x97, 0x90, 0xD6, 380 | 0x29, 0x1C, 0x3F, 0x8C, 0x3F, 0x81, 0x62, 0x3D, 0xF5, 0x00, 0xD4, 0xC5, 0xE2, 0xE1, 0x42, 381 | 0x42, 0x8C, 0x65, 0x8F, 0x5A, 0x66, 0x59, 0xE1, 0xDD, 0xEC, 0xDC, 0x1B, 0x4E, 0x63, 0x82, 382 | 0xFF, 0x02, 0x9D, 0x53, 0xDE, 0xBD, 0xB4, 0x80, 0xCF, 0x2B, 0xB7, 0xDE, 0x69, 0x5D, 0x1B, 383 | 0xCA, 0xFB, 0xB3, 0xF9, 0xBE, 0xD0, 0xF5, 0x79, 0x86, 0x2F, 0x0E, 0xB6, 0xA9, 0x87, 0xF4, 384 | 0x68, 0xC1, 0xBF, 0x4F, 0xB8, 0xA6, 0x2D, 0x03, 0xA9, 0x72, 0x04, 0xCA, 0x37, 0x6D, 0x1B, 385 | 0x90, 0xDD, 0xBC, 0x52, 0xAE, 0xF3, 0xFF, 0x08, 0xDD, 0x4B, 0x46, 0xD0, 0xCD, 0xB1, 0x8A, 386 | 0x35, 0x9A, 0x02, 0x64, 0x64, 0x2F, 0x57, 0xA5, 0x7B, 0x9A, 0x0D, 0x2B, 0x55, 0x11, 0x3C, 387 | 0xC0, 0x35, 0x74, 0x69, 0xD9, 0x7B, 0x43, 0x1D, 0xAC, 0xB2, 0xC2, 0x8A, 0xBE, 0x22, 0x45, 388 | 0x46, 0x76, 0xA9, 0x8A, 0x49, 0xB2, 0x5F, 0xC0, 0xB8, 0xBC, 0xCD, 0x27, 0xF8, 0x14, 0xB2, 389 | 0xA9, 0x6D, 0x5A, 0x1F, 0xA4, 0x43, 0x1E, 0x0F, 0xDB, 0xA4, 0x9E, 0x2B, 0xCA, 0xFC, 0x98, 390 | 0x7F, 0xF1, 0x18, 0x87, 0x5B, 0x11, 0x2D, 0xC5, 0xE4, 0x91, 0x20, 0xA9, 0x6A, 0x2D, 0xAC, 391 | 0xA8, 0xFA, 0x94, 0x57, 0x7F, 0x30, 0x73, 0x08, 0xE8, 0x49, 0xF0, 0xC8, 0x63, 0xDA, 0x83, 392 | 0x87, 0x2A, 0xC3, 0x31, 0x1A, 0xFC, 0xB7, 0x57, 0xB2, 0x40, 0x46, 0x09, 0x6D, 0x84, 0xB4, 393 | 0x66, 0xF1, 0x13, 0x16, 0x3A, 0x3A, 0xFB, 0xC6, 0x6E, 0xB0, 0x71, 0xB8, 0x23, 0x74, 0x22, 394 | 0x89, 0xFC, 0xBE, 0x34, 0xB3, 0x17, 0xB6, 0xC9, 0x68, 0x53, 0x64, 0x47, 0xAF, 0xCA, 0x1D, 395 | 0x5F, 0xB4, 0x74, 0xA3, 0x77, 0xB5, 0xFB, 0x77, 0xD9, 0x69, 0x2B, 0x3A, 0xAA, 0xAE, 0xE4, 396 | 0x03, 0x81, 0x6B, 0x3A, 0x35, 0x9C, 0x45, 0x50, 0x9C, 0x76, 0xCE, 0xE3, 0x7F, 0x64, 0x4B, 397 | 0x9F, 0x83, 0x7B, 0x72, 0xBC, 0x02, 0x1E, 0x94, 0x99, 0xC1, 0x1C, 0x45, 0x19, 0x1D, 0x56, 398 | 0x74, 0x73, 0xE7, 0xFC, 0x58, 0x72, 0x2D, 0xE3, 0x50, 0xA4, 0x21, 0xBE, 0x81, 0xDF, 0x80, 399 | 0xDA, 0x40, 0xDB, 0x79, 0x67, 0x0E, 0x94, 0xA3, 0x05, 0xDD, 0xF7, 0x14, 0x28, 0xD6, 0xC4, 400 | 0x2B, 0xF3, 0xCF, 0x36, 0x08, 0x84, 0xF3, 0xC8, 0x8C, 0xAD, 0xCE, 0x7F, 0x7C, 0x0F, 0xC6, 401 | 0xFE, 0x05, 0x54, 0x4B, 0x17, 0xA1, 0x83, 0x65, 0x97, 0x29, 0x01, 0x70, 0xC1, 0x16, 0xAE, 402 | 0x69, 0xA4, 0x90, 0xB9, 0xBE, 0x17, 0x05, 0x50, 0xF1, 0x65, 0x07, 0x23, 0x76, 0x64, 0x84, 403 | 0x2D, 0x40, 0x34, 0xFD, 0xDF, 0x62, 0x7E, 0x4C, 0x85, 0xD2, 0x6D, 0x17, 0xE1, 0x41, 0x12, 404 | 0xC6, 0x3E, 0xD6, 0x14, 0xB8, 0x5F, 0x8F, 0x39, 0x65, 0xC2, 0x62, 0x21, 0x06, 0x5C, 0xC9, 405 | 0xB8, 0x99, 0xA5, 0x00, 0xE3, 0x9C, 0x73, 0xAB, 0xB9, 0x76, 0x12, 0xD2, 0xFA, 0x7F, 0x7D, 406 | 0x64, 0x63, 0x9E, 0x26, 0xAA, 0x89, 0x85, 0x3A, 0xC9, 0x94, 0x04, 0x97, 0xEC, 0xFD, 0xC5, 407 | 0xA3, 0xB1, 0x7D, 0xD6, 0x07, 0x9C, 0x47, 0x30, 0x9C, 0x64, 0x97, 0x0E, 0xC6, 0xFC, 0x0B, 408 | 0xFF, 0xA7, 0xF9, 0x46, 0x5B, 0x2B, 0xDB, 0x9E, 0x1C, 0x85, 0x3A, 0x75, 0xD6, 0xEB, 0x9B, 409 | 0x15, 0x36, 0xD7, 0x1A, 0x3D, 0xFC, 0x0B, 0x75, 0x08, 0x5E, 0x32, 0x23, 0xE0, 0xA5, 0xAD, 410 | 0x0F, 0x45, 0xB3, 0x78, 0x20, 0x22, 0x24, 0x64, 0x0C, 0xCF, 0xD6, 0x3C, 0xA4, 0x48, 0xC7, 411 | 0xB3, 0x6E, 0x02, 0xE2, 0x0A, 0xAB, 0x92, 0xFC, 0x40, 0x7D, 0xF5, 0x02, 0x61, 0x56, 0xAB, 412 | 0xC5, 0x68, 0x38, 0xE0, 0x01, 0xF1, 0x94, 0x73, 0xC6, 0xFE, 0xC2, 0x34, 0x67, 0x8E, 0xB1, 413 | 0x73, 0x72, 0xD4, 0x3B, 0xFD, 0x1F, 0xE2, 0xA8, 0xED, 0x20, 0x14, 0x0A, 0x60, 0x6D, 0xD1, 414 | 0x85, 0x14, 0x05, 0x54, 0x96, 0xC6, 0x3D, 0xB5, 0x1B, 0x37, 0x56, 0x24, 0xF7, 0x7C, 0x0F, 415 | 0x55, 0xC6, 0xAA, 0x7E, 0x33, 0x2D, 0xE1, 0x97, 0x74, 0xA8, 0xDC, 0xC5, 0xA1, 0xEC, 0x8C, 416 | 0xEF, 0x28, 0x3B, 0x49, 0x8B, 0x00, 0xED, 0x8B, 0xD9, 0xE9, 0x65, 0xD5, 0x05, 0x7B, 0x6D, 417 | 0x20, 0xCA, 0x8F, 0x93, 0xB4, 0xCA, 0x36, 0x34, 0x8E, 0x16, 0x46, 0xCE, 0x02, 0x23, 0x43, 418 | 0x22, 0xF6, 0xBD, 0x10, 0xCC, 0xD0, 0xA3, 0xB0, 0x42, 0xA5, 0xAF, 0x59, 0x72, 0x97, 0x0B, 419 | 0xAE, 0x80, 0x8D, 0x19, 0xD0, 0x1D, 0x7D, 0x30, 0x4E, 0x5B, 0x46, 0xC0, 0xC2, 0x5C, 0x40, 420 | 0xFC, 0xF3, 0xEF, 0x05, 0x84, 0xE8, 0x0C, 0x80, 0xD7, 0x37, 0xA1, 0x6F, 0xC1, 0x8C, 0xE0, 421 | 0xBA, 0xA1, 0x88, 0x7B, 0xE7, 0x20, 0xBF, 0x18, 0x02, 0x40, 0x9F, 0x6F, 0x23, 0x11, 0x78, 422 | 0x07, 0xD0, 0x92, 0x87, 0x2D, 0xB5, 0xE0, 0xE9, 0xE9, 0xAA, 0x32, 0x88, 0x57, 0xF8, 0x9B, 423 | 0x01, 0x93, 0x2D, 0x07, 0x77, 0x68, 0x86, 0xAD, 0x06, 0xDE, 0x57, 0xA9, 0xA4, 0x96, 0x33, 424 | 0x42, 0xF8, 0xFB, 0x23, 0x1F, 0x99, 0xB6, 0x62, 0x93, 0x6B, 0x12, 0xBE, 0x72, 0x9F, 0x96, 425 | 0x1A, 0xDA, 0x05, 0x60, 0xF1, 0xD5, 0x40, 0x9F, 0x75, 0xF3, 0x1D, 0xBE, 0xD7, 0x87, 0x5D, 426 | 0x3A, 0x55, 0xF0, 0x9B, 0xBF, 0xE8, 0xB9, 0x72, 0xC2, 0xDD, 0x4D, 0x27, 0xF6, 0xA9, 0x37, 427 | 0x96, 0x7E, 0x6E, 0x6E, 0x64, 0x37, 0x4E, 0x2E, 0x3F, 0xFD, 0x3C, 0xF4, 0xA6, 0xF5, 0x22, 428 | 0xA8, 0x43, 0xF4, 0x13, 0x21, 0xB5, 0x4E, 0xA8, 0x6D, 0x50, 0x0A, 0xB3, 0xFE, 0x9F, 0x5C, 429 | 0xE7, 0x1A, 0xCF, 0x36, 0x42, 0x30, 0x1C, 0x88, 0x7F, 0x29, 0xE9, 0xCD, 0x96, 0xF2, 0x6A, 430 | 0x52, 0xB2, 0x25, 0x87, 0x63, 0xDC, 0xFC, 0x72, 0xE4, 0xF8, 0x5E, 0xB1, 0x97, 0xB4, 0x1E, 431 | 0x08, 0x90, 0x68, 0x10, 0x73, 0x7F, 0x94, 0x61, 0x48, 0x49, 0x36, 0x9B, 0x7D, 0xBD, 0xDF, 432 | 0xCD, 0xB1, 0xA3, 0x7D, 0xFB, 0xDD, 0x97, 0x8A, 0x0D, 0xFC, 0x9A, 0xB8, 0xA9, 0x33, 0xB5, 433 | 0x4E, 0x50, 0x3D, 0x60, 0x90, 0xEB, 0xAB, 0xB8, 0xCB, 0x6E, 0x32, 0xE4, 0x6B, 0xB0, 0x3F, 434 | 0x57, 0xB8, 0xA4, 0x6A, 0x7C, 0x00, 0x66, 0x39, 0xB1, 0x22, 0xE2, 0x04, 0x26, 0xA1, 0x5A, 435 | 0x17, 0xAA, 0x80, 0xB6, 0xC0, 0xF6, 0xCF, 0x7A, 0xF8, 0x60, 0xE9, 0x52, 0xB8, 0x0E, 0x08, 436 | 0xC0, 0xD5, 0x1F, 0xAB, 0x61, 0x62, 0x1A, 0x83, 0xD1, 0x92, 0xE1, 0x4D, 0x6D, 0xDF, 0x27, 437 | 0x0E, 0xFF, 0xF9, 0xA3, 0x36, 0xFF, 0x73, 0xEF, 0x1D, 0xAB, 0xAC, 0xBF, 0xA7, 0xB3, 0x29, 438 | 0xD2, 0xB2, 0x37, 0xAB, 0x08, 0x7D, 0xB6, 0x7E, 0x0D, 0x25, 0xAA, 0x49, 0x29, 0x9F, 0x61, 439 | 0x52, 0x44, 0x19, 0x1C, 0x51, 0x95, 0x74, 0xB9, 0x3D, 0xDD, 0x95, 0x2C, 0x4F, 0x30, 0x56, 440 | 0xC9, 0xEF, 0x3D, 0x87, 0x90, 0x1E, 0xF8, 0x69, 0xFF, 0x37, 0x06, 0x27, 0xDB, 0x72, 0x82, 441 | 0x2C, 0xDE, 0xB8, 0x39, 0x0B, 0x78, 0xB1, 0x1F, 0x37, 0x54, 0xBF, 0x21, 0x32, 0x87, 0xB4, 442 | 0xD9, 0x49, 0x2D, 0x29, 0x19, 0x43, 0x01, 0xD4, 0xC0, 0xA3, 0xFF, 0x09, 0x6F, 0x69, 0xC8, 443 | 0x5D, 0x35, 0x1D, 0x10, 0x09, 0x91, 0xB6, 0x12, 0xEC, 0x04, 0xA6, 0x61, 0xEF, 0x73, 0xC7, 444 | 0x4C, 0x04, 0x8E, 0x3E, 0xAE, 0xD7, 0xC2, 0x84, 0x48, 0xAB, 0x99, 0x96, 0x75, 0xD8, 0xAD, 445 | 0xA7, 0x5B, 0xDE, 0x72, 0x44, 0x96, 0xC5, 0xB3, 0xEB, 0x8E, 0xED, 0xD6, 0x69, 0x81, 0xE6, 446 | 0x07, 0x3A, 0x15, 0x0D, 0x66, 0x5F, 0x36, 0xA9, 0xAB, 0x53, 0x82, 0x47, 0x98, 0x27, 0xF2, 447 | 0x16, 0x95, 0x05, 0x0B, 0xAE, 0xF1, 0x04, 0x92, 0x80, 0x20, 0xA4, 0x9B, 0x43, 0x66, 0x70, 448 | 0x7F, 0x45, 0x0B, 0x4B, 0x85, 0x95, 0x10, 0x09, 0xC8, 0xD9, 0xF9, 0x5D, 0x40, 0x6D, 0x07, 449 | 0x69, 0x18, 0xF3, 0xD6, 0x98, 0x61, 0x25, 0x8E, 0xA1, 0xE2, 0x24, 0xBD, 0xF0, 0xFA, 0x89, 450 | 0xD8, 0x68, 0xB2, 0x03, 0x81, 0x63, 0xF9, 0x42, 0xD4, 0x1A, 0xD9, 0x4D, 0xCD, 0x30, 0x36, 451 | 0x2D, 0xB1, 0x63, 0xFC, 0xA3, 0x2B, 0xA7, 0x07, 0x50, 0xBC, 0x67, 0xAB, 0x7D, 0x33, 0x1D, 452 | 0xEC, 0x62, 0xFE, 0xD2, 0x65, 0xAA, 0xBA, 0x37, 0xC9, 0x7F, 0x67, 0x26, 0x9D, 0x8A, 0x8B, 453 | 0x63, 0x0B, 0xE0, 0x30, 0x65, 0x07, 0x8C, 0xF3, 0xD1, 0xCF, 0x0D, 0xB4, 0x1E, 0xF3, 0x29, 454 | 0xBE, 0x43, 0x1F, 0x34, 0x1E, 0x52, 0x02, 0xA7, 0x8D, 0x30, 0x2E, 0x3E, 0x39, 0x00, 0xB6, 455 | 0x7B, 0x5C, 0x29, 0x39, 0xC0, 0x0D, 0xAB, 0xA0, 0x6D, 0x77, 0x3C, 0xB2, 0x18, 0x42, 0x57, 456 | 0x63, 0xDA, 0x9E, 0xF5, 0xE0, 0x42, 0x43, 0xF6, 0x50, 0xFD, 0x71, 0x9B, 0x30, 0xE0, 0x92, 457 | 0x8B, 0xD1, 0xE1, 0xC4, 0x96, 0xC9, 0xF5, 0x14, 0xB6, 0xF7, 0xA5, 0x10, 0x77, 0xF4, 0xF9, 458 | 0xAC, 0xDC, 0x45, 0xE1, 0x3C, 0xD6, 0x0B, 0xA5, 0xE2, 0x58, 0x01, 0x19, 0x39, 0x14, 0x68, 459 | 0x96, 0xC0, 0xCE, 0xA9, 0xDE, 0x84, 0x22, 0x59, 0x87, 0x70, 0xFD, 0x8A, 0x71, 0x64, 0x79, 460 | 0x16, 0x37, 0x80, 0x83, 0xFD, 0x9C, 0x73, 0xE6, 0x9C, 0x8B, 0xCD, 0xC0, 0x69, 0x66, 0x90, 461 | 0x45, 0x0A, 0xC9, 0x81, 0x4A, 0xDA, 0x26, 0xDA, 0xA1, 0x70, 0x03, 0x6C, 0x36, 0x9D, 0xAD, 462 | 0xD7, 0xE2, 0x1F, 0x27, 0xBE, 0xBB, 0xEC, 0x63, 0xD9, 0xC2, 0x2A, 0x56, 0x4D, 0x63, 0xCD, 463 | 0x92, 0xEE, 0xAF, 0xCA, 0xD0, 0x11, 0x35, 0x2F, 0x1D, 0xF1, 0x96, 0xD1, 0xAA, 0xDC, 0xF6, 464 | 0x14, 0x3F, 0xA0, 0xEE, 0x90, 0x83, 0x9F, 0x42, 0x40, 0xE6, 0x2C, 0x10, 0x23, 0x00, 0x23, 465 | 0x18, 0x8C, 0xA1, 0x26, 0x4B, 0x22, 0xE1, 0x36, 0x07, 0x55, 0xCB, 0xC3, 0xD2, 0xDD, 0x12, 466 | 0x58, 0x19, 0x75, 0x03, 0xC6, 0xD8, 0x2E, 0xCE, 0x87, 0x1C, 0xC3, 0x15, 0x44, 0x2A, 0x30, 467 | 0x00, 0x52, 0x39, 0x31, 0x13, 0xF4, 0x25, 0x75, 0x74, 0x15, 0x6C, 0xC5, 0xC1, 0xD2, 0x33, 468 | 0x75, 0xC2, 0x41, 0x22, 0x28, 0x95, 0xDF, 0x97, 0x6C, 0x31, 0xF8, 0x35, 0xA6, 0x54, 0x29, 469 | 0x5C, 0xF4, 0x20, 0x97, 0x69, 0xE5, 0x46, 0xFF, 0x34, 0x24, 0x73, 0x12, 0xB8, 0x61, 0x25, 470 | 0x46, 0xB3, 0x8F, 0xBA, 0x3C, 0xFA, 0x06, 0xFF, 0x3F, 0x66, 0x9D, 0x22, 0x55, 0x46, 0x2F, 471 | 0xFF, 0x44, 0xDB, 0x25, 0x29, 0xE0, 0x16, 0x6E, 0xEC, 0x87, 0x97, 0x92, 0x37, 0x23, 0x0E, 472 | 0x52, 0x4E, 0xBB, 0x10, 0xBB, 0x1C, 0x73, 0x75, 0xD1, 0x31, 0xC3, 0xAD, 0xFE, 0xB8, 0x12, 473 | 0x50, 0xA0, 0x69, 0x91, 0x36, 0xEA, 0x5F, 0x0D, 0xEC, 0x1A, 0x23, 0x4A, 0x7D, 0x94, 0x84, 474 | 0xC8, 0x4A, 0x58, 0x6A, 0xA1, 0xA3, 0x75, 0xCA, 0x85, 0xE7, 0x96, 0x91, 0x07, 0x05, 0x3A, 475 | 0x57, 0x61, 0x6A, 0x6F, 0xF1, 0xEF, 0xF7, 0xB3, 0xB1, 0x09, 0xB8, 0x91, 0xA8, 0xF9, 0x57, 476 | 0xB8, 0x63, 0x95, 0xFF, 0xB4, 0x1C, 0x96, 0xE7, 0xE5, 0xEC, 0x06, 0x3A, 0x11, 0xE6, 0x81, 477 | 0xAB, 0x23, 0xE4, 0x5E, 0x5A, 0xB6, 0x6B, 0x69, 0x62, 0x6F, 0x9D, 0xC4, 0x08, 0x6F, 0xA6, 478 | 0xBE, 0x4D, 0x09, 0x12, 0x77, 0xCA, 0xDD, 0xB5, 0x2D, 0x66, 0xCB, 0x4F, 0x4F, 0x11, 0xF2, 479 | 0x3A, 0x1A, 0x97, 0x1F, 0xFE, 0x50, 0x2F, 0x19, 0x32, 0x05, 0x45, 0xA0, 0x50, 0x60, 0x58, 480 | 0x40, 0x40, 0x3D, 0xF6, 0xC3, 0x6F, 0x07, 0xC8, 0x26, 0x26, 0x0E, 0x42, 0x22, 0x96, 0x6D, 481 | 0xFE, 0x95, 0x53, 0x70, 0xDC, 0x92, 0x12, 0x63, 0xFD, 0xA3, 0x7D, 0x6E, 0x44, 0xCD, 0x11, 482 | 0x2C, 0x51, 0x6F, 0xBC, 0x50, 0xFC, 0x1C, 0xC8, 0x3A, 0x28, 0xF5, 0x39, 0xF8, 0x8C, 0x60, 483 | 0x5D, 0xA5, 0x4A, 0xFA, 0xAB, 0x04, 0x7F, 0x34, 0x91, 0x53, 0xE7, 0x6C, 0x56, 0xC6, 0x14, 484 | 0xE4, 0xCC, 0xE4, 0xBB, 0x6E, 0x47, 0x7A, 0x46, 0x6B, 0xE2, 0x88, 0xA0, 0xBD, 0xBD, 0xCC, 485 | 0x51, 0xF3, 0x37, 0x4B, 0xB3, 0xA0, 0x19, 0x92, 0x48, 0x35, 0xBB, 0xBC, 0x79, 0x78, 0xFF, 486 | 0x49, 0xC1, 0x2B, 0x93, 0xDF, 0x75, 0xA7, 0xFB, 0x94, 0x89, 0xAF, 0x50, 0x5E, 0x2D, 0xE1, 487 | 0x78, 0x60, 0x0C, 0xDF, 0xF8, 0x7C, 0xFD, 0xCD, 0x2D, 0xE2, 0xFF, 0xD3, 0xA3, 0x4A, 0x48, 488 | 0x0D, 0x40, 0x8F, 0x03, 0x4F, 0x2C, 0xBD, 0xFA, 0x2E, 0x16, 0xC3, 0xD4, 0xFD, 0x0B, 0xB3, 489 | 0xBD, 0x4F, 0x30, 0xAD, 0xD0, 0xAE, 0xCA, 0x77, 0x9D, 0xDD, 0x3D, 0xA3, 0x66, 0xD0, 0xC1, 490 | 0x6D, 0xCC, 0x3B, 0x56, 0x81, 0x5D, 0x80, 0x07, 0xD8, 0x84, 0x46, 0x71, 0x40, 0x57, 0xB3, 491 | 0x44, 0x85, 0x63, 0x4E, 0x17, 0x2C, 0xB0, 0x21, 0x98, 0x43, 0x42, 0x04, 0x18, 0x84, 0xFA, 492 | 0xB1, 0xD7, 0xC5, 0x5C, 0xCA, 0x25, 0x8B, 0x1A, 0x7A, 0x50, 0x60, 0x68, 0x4A, 0x30, 0xEA, 493 | 0xE6, 0xDE, 0x19, 0xBB, 0x9F, 0x47, 0xEF, 0xDB, 0xC5, 0x81, 0x72, 0xF0, 0x8D, 0xBA, 0x74, 494 | 0x3A, 0xD1, 0xD5, 0xC6, 0xD1, 0xE0, 0xAE, 0x28, 0x2A, 0x65, 0xE5, 0x0B, 0x09, 0xFA, 0xEA, 495 | 0x5B, 0xA6, 0xDB, 0x38, 0xD8, 0x67, 0xC0, 0xBE, 0xA1, 0x12, 0x1C, 0x03, 0xB1, 0x81, 0xB8, 496 | 0x95, 0xDD, 0x78, 0xF8, 0x16, 0x6E, 0xAB, 0xBB, 0xAA, 0x33, 0x54, 0x0E, 0x39, 0x83, 0x24, 497 | 0x17, 0xB3, 0x0B, 0x3C, 0xA1, 0x62, 0x21, 0xB2, 0xA0, 0xF8, 0x49, 0xAB, 0x8B, 0x80, 0xC6, 498 | 0x3D, 0xF1, 0x2E, 0x18, 0x44, 0x74, 0x5F, 0x98, 0x92, 0x33, 0xFB, 0xB2, 0x52, 0x6B, 0x97, 499 | 0xE9, 0x48, 0x12, 0x91, 0x32, 0x50, 0x21, 0x75, 0x74, 0x69, 0x88, 0x54, 0xC6, 0xF3, 0xC9, 500 | 0x37, 0x3C, 0xB3, 0x89, 0xAB, 0x33, 0x1F, 0x79, 0x57, 0xF7, 0xE4, 0xB5, 0x87, 0x0C, 0xA4, 501 | 0x99, 0x48, 0x89, 0x63, 0x5F, 0x72, 0xA1, 0xBC, 0xFF, 0xFE, 0xF8, 0xB3, 0xF1, 0x00, 0xE4, 502 | 0xD4, 0x01, 0x9B, 0xB7, 0x2E, 0x4F, 0xA0, 0x90, 0xE4, 0x9B, 0x6A, 0xA8, 0xBA, 0xE1, 0xD3, 503 | 0xD5, 0xBC, 0xEB, 0xC5, 0xB2, 0x89, 0xB4, 0xE9, 0x4D, 0x3F, 0x4C, 0xFA, 0x8C, 0xCB, 0xCD, 504 | 0x22, 0x08, 0xB8, 0xC7, 0xB3, 0xA3, 0xED, 0x6B, 0xAC, 0xF3, 0x2D, 0x98, 0x70, 0x41, 0x47, 505 | 0x85, 0xE8, 0x6E, 0x31, 0x0A, 0xC2, 0x3E, 0x51, 0x39, 0x55, 0xF8, 0x4A, 0xE9, 0x48, 0x64, 506 | 0x01, 0xDB, 0x8D, 0xE3, 0xAF, 0xA4, 0xB9, 0xD8, 0x19, 0xCA, 0x86, 0xCA, 0xA1, 0x6C, 0x1C, 507 | 0x12, 0x3D, 0xA1, 0x02, 0x23, 0x1D, 0x29, 0x5D, 0x94, 0x04, 0xC6, 0x51, 0x01, 0x40, 0x0B, 508 | 0xB3, 0x69, 0x25, 0x45, 0xEF, 0x43, 0x81, 0x4F, 0x97, 0x57, 0x0D, 0xA1, 0xA5, 0xC9, 0x9D, 509 | 0xE6, 0x56, 0xB9, 0x38, 0x93, 0xA1, 0x78, 0xC5, 0xBF, 0x75, 0xFE, 0x81, 0x6A, 0x35, 0x64, 510 | 0x89, 0x64, 0x43, 0x75, 0xFD, 0x29, 0x63, 0xD1, 0x15, 0xAB, 0x43, 0x60, 0x65, 0xDC, 0x98, 511 | 0xD5, 0xC7, 0x6E, 0xF9, 0xB2, 0x38, 0xFB, 0x6E, 0xB0, 0x34, 0x9C, 0xA3, 0x73, 0x61, 0xF5, 512 | 0x51, 0xFF, 0x1F, 0xCE, 0xB0, 0x08, 0x83, 0x29, 0xB3, 0x82, 0x07, 0xFA, 0xC4, 0xE5, 0x21, 513 | 0xD3, 0xA0, 0xD4, 0xC0, 0xF8, 0x1A, 0x65, 0x9B, 0x35, 0x7A, 0xE3, 0x32, 0xA5, 0x4D, 0x77, 514 | 0x1F, 0x23, 0x19, 0xCC, 0xE1, 0xB3, 0x50, 0x0D, 0xE8, 0x2F, 0x8B, 0x18, 0x89, 0x61, 0xCB, 515 | 0x22, 0xBA, 0xE0, 0x4A, 0xA2, 0x7F, 0xA5, 0x1B, 0x45, 0x59, 0x33, 0xC4, 0x73, 0xDF, 0x42, 516 | 0xC6, 0x00, 0x11, 0x37, 0xF2, 0x3C, 0x1B, 0xF4, 0x26, 0xD1, 0x6D, 0x93, 0xC1, 0x94, 0xD2, 517 | 0x60, 0xE5, 0xF3, 0x91, 0x66, 0x92, 0x3C, 0x65, 0x27, 0xC1, 0x83, 0x13, 0x76, 0x5A, 0x88, 518 | 0xEC, 0xB2, 0x59, 0x95, 0x18, 0x81, 0x2E, 0x94, 0x96, 0x53, 0x17, 0xB6, 0xFD, 0x8C, 0xCC, 519 | 0xBE, 0x8D, 0x36, 0xB3, 0xC8, 0xF2, 0xB2, 0xBE, 0x0F, 0x12, 0x99, 0xFF, 0xFA, 0xF9, 0x18, 520 | 0xAB, 0x30, 0xFA, 0xB1, 0x5B, 0xF2, 0xEE, 0xCA, 0x6E, 0xA1, 0xD9, 0xCE, 0xCC, 0x60, 0xA0, 521 | 0x4D, 0xFD, 0x7C, 0xAD, 0x4D, 0x50, 0xB6, 0x88, 0x0D, 0x88, 0x3B, 0x28, 0x7F, 0xA1, 0x28, 522 | 0x41, 0x0A, 0x43, 0xAD, 0xCC, 0x08, 0x14, 0xF3, 0xF2, 0x43, 0xE7, 0xCF, 0x6A, 0x5C, 0x11, 523 | 0xD0, 0x6D, 0x99, 0xC8, 0x4F, 0xB1, 0x14, 0x06, 0xBC, 0x68, 0x6D, 0xBE, 0xCD, 0xD7, 0x58, 524 | 0xA2, 0x17, 0xF5, 0x9E, 0xFD, 0xDA, 0xFA, 0xBF, 0x73, 0x57, 0x4A, 0xF8, 0xF3, 0xA9, 0x94, 525 | 0xB3, 0x01, 0xE9, 0xA3, 0xDA, 0xEA, 0xC1, 0x40, 0x33, 0xAA, 0x3F, 0xE6, 0x0D, 0x6A, 0xE2, 526 | 0xF3, 0x74, 0xE8, 0x1B, 0x3C, 0x2B, 0x25, 0x44, 0x8E, 0x1C, 0x36, 0xBE, 0xA9, 0x27, 0x6E, 527 | 0x6A, 0x48, 0x8E, 0x2F, 0x2C, 0x9D, 0x71, 0x66, 0x23, 0x7C, 0x7A, 0x74, 0x93, 0x46, 0x2D, 528 | 0xCA, 0x6B, 0xC6, 0x33, 0xDA, 0x1E, 0x1E, 0x44, 0x07, 0xFD, 0x89, 0x5D, 0x30, 0x02, 0x4C, 529 | 0xB1, 0x73, 0xC0, 0x91, 0xEB, 0xA5, 0x61, 0x89, 0xA4, 0x04, 0xFD, 0xD5, 0x5F, 0x54, 0x59, 530 | 0x81, 0xC3, 0x2A, 0x13, 0x89, 0xDA, 0x68, 0xB6, 0x3A, 0x9C, 0x70, 0x6F, 0x48, 0xB4, 0x3C, 531 | 0xF8, 0x9B, 0xF8, 0xF2, 0x59, 0xBF, 0xF4, 0x8D, 0x06, 0x58, 0xEA, 0xA2, 0xA6, 0xB4, 0x70, 532 | 0x08, 0x80, 0x2B, 0x50, 0x13, 0x36, 0x79, 0x17, 0x0B, 0x94, 0x0E, 0x4D, 0xF5, 0xC8, 0x14, 533 | 0xB9, 0x02, 0x7D, 0xEE, 0x6B, 0xBD, 0x10, 0xB4, 0x85, 0x74, 0xA1, 0xB9, 0x84, 0x67, 0xC6, 534 | 0x2C, 0xDB, 0xDA, 0x55, 0x54, 0x16, 0xDA, 0x02, 0xB6, 0xDA, 0x2A, 0x9B, 0x51, 0xD6, 0xDC, 535 | 0x87, 0x80, 0xC1, 0xB8, 0x6F, 0x0C, 0xEF, 0x4B, 0xD1, 0x1A, 0x9F, 0x36, 0x2E, 0x9C, 0x7E, 536 | 0x5F, 0x17, 0xE2, 0xC1, 0x82, 0x0C, 0x42, 0x0D, 0x15, 0x18, 0xCA, 537 | ], 538 | ]; 539 | --------------------------------------------------------------------------------