├── .gitignore ├── Cargo.toml ├── src ├── main.rs ├── constants.rs └── lib.rs ├── LICENSE ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "porkchop" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["@landaire"] 6 | repository = "https://github.com/landaire/porkchop" 7 | license = "MIT" 8 | readme = "README.md" 9 | description = "Decryption utility for Yaesu ham radio firmware images" 10 | 11 | 12 | [dependencies] 13 | chrono = "0.4" 14 | byteorder = "1.4" 15 | pretty-hex = "0.2" 16 | structopt = "0.3" 17 | pelite = "0.9" 18 | thiserror = "1.0" 19 | log = "0.4" 20 | pretty_env_logger = "0.4" 21 | anyhow = "1.0" -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::io::{Write}; 3 | use std::path::PathBuf; 4 | use structopt::StructOpt; 5 | 6 | #[derive(StructOpt)] 7 | #[structopt( 8 | name = "porkchop", 9 | about = "Decryption utility for Yaesu ham radio firmware images." 10 | )] 11 | struct Opt { 12 | /// Input file 13 | #[structopt(parse(from_os_str))] 14 | input: PathBuf, 15 | 16 | /// Output file, stdout if not present 17 | #[structopt(parse(from_os_str))] 18 | output: Option, 19 | } 20 | 21 | fn main() -> anyhow::Result<()> { 22 | pretty_env_logger::init(); 23 | 24 | let opt = Opt::from_args(); 25 | let pe_data = std::fs::read(opt.input)?; 26 | 27 | let update_info = porkchop::update_info_from_pe(pe_data.as_slice())?; 28 | let decrypted_firmware = porkchop::decrypt(update_info)?; 29 | 30 | if let Some(output_file) = opt.output { 31 | std::fs::write(output_file, decrypted_firmware)?; 32 | } else { 33 | // Write to stdout 34 | let stdout = std::io::stdout(); 35 | stdout.lock().write_all(decrypted_firmware.as_slice())?; 36 | } 37 | 38 | Ok(()) 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Lander Brandt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![crates.io](https://img.shields.io/crates/v/porkchop.svg) 2 | 3 | # porkchop 4 | 5 | Decryption utility for Yaesu ham radio firmware images. 6 | 7 | ## Background 8 | 9 | Yaesu provides a firmware update utility for their ham radios that contains an encrypted firmware image. This utility reimplements the decryption algorithm found in the update utility and emits a decrypted image. 10 | 11 | A more in-depth blog post about how the encryption works can be found [on my blog](https://landaire.net/reversing-yaesu-firmware-encryption/). 12 | 13 | ## Building 14 | 15 | To build/run you'll need a recent Rust toolchain installed. See [this guide](https://www.rust-lang.org/tools/install) to get started. 16 | 17 | ``` 18 | git clone https://github.com/landaire/porkchop.git 19 | cd porkchop 20 | # To build 21 | cargo build --release 22 | # To run 23 | cargo run --release -- 24 | ``` 25 | 26 | You can optionally install it direct from crates.io: 27 | 28 | ``` 29 | cargo install porkchop 30 | ``` 31 | 32 | ## Usage 33 | 34 | ``` 35 | porkchop 0.1.0 36 | Decryption utility for Yaesu ham radio firmware images. 37 | 38 | USAGE: 39 | porkchop [output] 40 | 41 | FLAGS: 42 | -h, --help Prints help information 43 | -V, --version Prints version information 44 | 45 | ARGS: 46 | Input file 47 | Output file, stdout if not present 48 | ``` 49 | 50 | Example: 51 | 52 | ``` 53 | porkchop firmware_update_utility.exe firmware.bin 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "ansi_term" 16 | version = "0.12.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 19 | dependencies = [ 20 | "winapi", 21 | ] 22 | 23 | [[package]] 24 | name = "anyhow" 25 | version = "1.0.52" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" 28 | 29 | [[package]] 30 | name = "atty" 31 | version = "0.2.14" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 34 | dependencies = [ 35 | "hermit-abi", 36 | "libc", 37 | "winapi", 38 | ] 39 | 40 | [[package]] 41 | name = "autocfg" 42 | version = "1.0.1" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 45 | 46 | [[package]] 47 | name = "bitflags" 48 | version = "1.3.2" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 51 | 52 | [[package]] 53 | name = "byteorder" 54 | version = "1.4.3" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 57 | 58 | [[package]] 59 | name = "cfg-if" 60 | version = "1.0.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 63 | 64 | [[package]] 65 | name = "chrono" 66 | version = "0.4.19" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 69 | dependencies = [ 70 | "libc", 71 | "num-integer", 72 | "num-traits", 73 | "time", 74 | "winapi", 75 | ] 76 | 77 | [[package]] 78 | name = "clap" 79 | version = "2.34.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 82 | dependencies = [ 83 | "ansi_term", 84 | "atty", 85 | "bitflags", 86 | "strsim", 87 | "textwrap", 88 | "unicode-width", 89 | "vec_map", 90 | ] 91 | 92 | [[package]] 93 | name = "dataview" 94 | version = "0.1.2" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "47a802a2cad0ff4dfc4f3110da174b7a6928c315cae523e88638cfb72941b4d5" 97 | dependencies = [ 98 | "derive_pod", 99 | ] 100 | 101 | [[package]] 102 | name = "derive_pod" 103 | version = "0.1.1" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "2e2d4527fc8a6ad5cdb22622bed719d47f5e47f2e7b53cb821e1c933f62f3eca" 106 | 107 | [[package]] 108 | name = "env_logger" 109 | version = "0.7.1" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 112 | dependencies = [ 113 | "atty", 114 | "humantime", 115 | "log", 116 | "regex", 117 | "termcolor", 118 | ] 119 | 120 | [[package]] 121 | name = "heck" 122 | version = "0.3.3" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 125 | dependencies = [ 126 | "unicode-segmentation", 127 | ] 128 | 129 | [[package]] 130 | name = "hermit-abi" 131 | version = "0.1.19" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 134 | dependencies = [ 135 | "libc", 136 | ] 137 | 138 | [[package]] 139 | name = "humantime" 140 | version = "1.3.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 143 | dependencies = [ 144 | "quick-error", 145 | ] 146 | 147 | [[package]] 148 | name = "lazy_static" 149 | version = "1.4.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 152 | 153 | [[package]] 154 | name = "libc" 155 | version = "0.2.112" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 158 | 159 | [[package]] 160 | name = "log" 161 | version = "0.4.14" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 164 | dependencies = [ 165 | "cfg-if", 166 | ] 167 | 168 | [[package]] 169 | name = "memchr" 170 | version = "2.4.1" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 173 | 174 | [[package]] 175 | name = "no-std-compat" 176 | version = "0.4.1" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" 179 | 180 | [[package]] 181 | name = "num-integer" 182 | version = "0.1.44" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 185 | dependencies = [ 186 | "autocfg", 187 | "num-traits", 188 | ] 189 | 190 | [[package]] 191 | name = "num-traits" 192 | version = "0.2.14" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 195 | dependencies = [ 196 | "autocfg", 197 | ] 198 | 199 | [[package]] 200 | name = "pelite" 201 | version = "0.9.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "8c270b1a0c279bbcb4cff3d2294121731c48ee68f0435d26cf71018a853cb890" 204 | dependencies = [ 205 | "dataview", 206 | "libc", 207 | "no-std-compat", 208 | "pelite-macros", 209 | "winapi", 210 | ] 211 | 212 | [[package]] 213 | name = "pelite-macros" 214 | version = "0.1.1" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "7a7cf3f8ecebb0f4895f4892a8be0a0dc81b498f9d56735cb769dc31bf00815b" 217 | 218 | [[package]] 219 | name = "porkchop" 220 | version = "0.1.0" 221 | dependencies = [ 222 | "anyhow", 223 | "byteorder", 224 | "chrono", 225 | "log", 226 | "pelite", 227 | "pretty-hex", 228 | "pretty_env_logger", 229 | "structopt", 230 | "thiserror", 231 | ] 232 | 233 | [[package]] 234 | name = "pretty-hex" 235 | version = "0.2.1" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" 238 | 239 | [[package]] 240 | name = "pretty_env_logger" 241 | version = "0.4.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" 244 | dependencies = [ 245 | "env_logger", 246 | "log", 247 | ] 248 | 249 | [[package]] 250 | name = "proc-macro-error" 251 | version = "1.0.4" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 254 | dependencies = [ 255 | "proc-macro-error-attr", 256 | "proc-macro2", 257 | "quote", 258 | "syn", 259 | "version_check", 260 | ] 261 | 262 | [[package]] 263 | name = "proc-macro-error-attr" 264 | version = "1.0.4" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 267 | dependencies = [ 268 | "proc-macro2", 269 | "quote", 270 | "version_check", 271 | ] 272 | 273 | [[package]] 274 | name = "proc-macro2" 275 | version = "1.0.36" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 278 | dependencies = [ 279 | "unicode-xid", 280 | ] 281 | 282 | [[package]] 283 | name = "quick-error" 284 | version = "1.2.3" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 287 | 288 | [[package]] 289 | name = "quote" 290 | version = "1.0.14" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" 293 | dependencies = [ 294 | "proc-macro2", 295 | ] 296 | 297 | [[package]] 298 | name = "regex" 299 | version = "1.5.4" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 302 | dependencies = [ 303 | "aho-corasick", 304 | "memchr", 305 | "regex-syntax", 306 | ] 307 | 308 | [[package]] 309 | name = "regex-syntax" 310 | version = "0.6.25" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 313 | 314 | [[package]] 315 | name = "strsim" 316 | version = "0.8.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 319 | 320 | [[package]] 321 | name = "structopt" 322 | version = "0.3.25" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" 325 | dependencies = [ 326 | "clap", 327 | "lazy_static", 328 | "structopt-derive", 329 | ] 330 | 331 | [[package]] 332 | name = "structopt-derive" 333 | version = "0.4.18" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" 336 | dependencies = [ 337 | "heck", 338 | "proc-macro-error", 339 | "proc-macro2", 340 | "quote", 341 | "syn", 342 | ] 343 | 344 | [[package]] 345 | name = "syn" 346 | version = "1.0.84" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b" 349 | dependencies = [ 350 | "proc-macro2", 351 | "quote", 352 | "unicode-xid", 353 | ] 354 | 355 | [[package]] 356 | name = "termcolor" 357 | version = "1.1.2" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 360 | dependencies = [ 361 | "winapi-util", 362 | ] 363 | 364 | [[package]] 365 | name = "textwrap" 366 | version = "0.11.0" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 369 | dependencies = [ 370 | "unicode-width", 371 | ] 372 | 373 | [[package]] 374 | name = "thiserror" 375 | version = "1.0.30" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 378 | dependencies = [ 379 | "thiserror-impl", 380 | ] 381 | 382 | [[package]] 383 | name = "thiserror-impl" 384 | version = "1.0.30" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 387 | dependencies = [ 388 | "proc-macro2", 389 | "quote", 390 | "syn", 391 | ] 392 | 393 | [[package]] 394 | name = "time" 395 | version = "0.1.44" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 398 | dependencies = [ 399 | "libc", 400 | "wasi", 401 | "winapi", 402 | ] 403 | 404 | [[package]] 405 | name = "unicode-segmentation" 406 | version = "1.8.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 409 | 410 | [[package]] 411 | name = "unicode-width" 412 | version = "0.1.9" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 415 | 416 | [[package]] 417 | name = "unicode-xid" 418 | version = "0.2.2" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 421 | 422 | [[package]] 423 | name = "vec_map" 424 | version = "0.8.2" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 427 | 428 | [[package]] 429 | name = "version_check" 430 | version = "0.9.4" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 433 | 434 | [[package]] 435 | name = "wasi" 436 | version = "0.10.0+wasi-snapshot-preview1" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 439 | 440 | [[package]] 441 | name = "winapi" 442 | version = "0.3.9" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 445 | dependencies = [ 446 | "winapi-i686-pc-windows-gnu", 447 | "winapi-x86_64-pc-windows-gnu", 448 | ] 449 | 450 | [[package]] 451 | name = "winapi-i686-pc-windows-gnu" 452 | version = "0.4.0" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 455 | 456 | [[package]] 457 | name = "winapi-util" 458 | version = "0.1.5" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 461 | dependencies = [ 462 | "winapi", 463 | ] 464 | 465 | [[package]] 466 | name = "winapi-x86_64-pc-windows-gnu" 467 | version = "0.4.0" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 470 | -------------------------------------------------------------------------------- /src/constants.rs: -------------------------------------------------------------------------------- 1 | // These constants were taken from the FT70D firmware image. They should work 2 | // for all Yaesu radios. 3 | 4 | pub(crate) const TIMESTAMP_TABLES: [[u8; 56]; 4] = [ 5 | [ 6 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 7 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 8 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 9 | 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 10 | ], 11 | [ 12 | 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 13 | 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 14 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 15 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 | ], 17 | [ 18 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 19 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 20 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 21 | 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 22 | ], 23 | [ 24 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 25 | 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 26 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 27 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 28 | ], 29 | ]; 30 | 31 | pub(crate) const KEY_CONFIG: [u8; 64] = [ 32 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 33 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 34 | 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 35 | 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 36 | ]; 37 | 38 | pub(crate) const KEY_CONFIG2: [u8; 48] = [ 39 | 0x0E, 0x11, 0x0B, 0x18, 0x01, 0x05, 0x03, 0x1C, 0x0F, 0x06, 0x15, 0x0A, 0x17, 0x13, 0x0C, 0x04, 40 | 0x1A, 0x08, 0x10, 0x07, 0x1B, 0x14, 0x0D, 0x02, 0x29, 0x34, 0x1F, 0x25, 0x2F, 0x37, 0x1E, 0x28, 41 | 0x33, 0x2D, 0x21, 0x30, 0x2C, 0x31, 0x27, 0x38, 0x22, 0x35, 0x2E, 0x2A, 0x32, 0x24, 0x1D, 0x20, 42 | ]; 43 | 44 | pub(crate) const ENCRYPTION_CONFIG: [u8; 0x30] = [ 45 | 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x08, 0x09, 0x0A, 0x0B, 46 | 0x0C, 0x0D, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x14, 0x15, 47 | 0x16, 0x17, 0x18, 0x19, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x01, 48 | ]; 49 | 50 | pub(crate) const ENCRYPTION_CONFIG2: [u8; 0x800] = [ 51 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 52 | 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 54 | 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 55 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 56 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 57 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 58 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 59 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 60 | 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 61 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 62 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 63 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 64 | 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 65 | 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 66 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 67 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 68 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 69 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 70 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 71 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 72 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 73 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 74 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 75 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 76 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 77 | 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 78 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 79 | 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 80 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 81 | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 83 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 84 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 85 | 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 86 | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 87 | 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 88 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 89 | 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 90 | 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 91 | 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 92 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 93 | 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 94 | 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 95 | 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 96 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 97 | 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 98 | 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 99 | 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 101 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 102 | 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 103 | 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 104 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 105 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 106 | 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 107 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 108 | 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 109 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 110 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 111 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 112 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 113 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 114 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 115 | 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 116 | 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 117 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 118 | 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 119 | 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 120 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 121 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 122 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 123 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 124 | 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 125 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 126 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 127 | 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 128 | 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 129 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 130 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 131 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 132 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 133 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 134 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 135 | 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 136 | 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 137 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 138 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 139 | 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 140 | 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 141 | 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 142 | 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 143 | 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 144 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 145 | 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 146 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 147 | 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 148 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 149 | 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 150 | 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 151 | 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 152 | 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 153 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 154 | 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 155 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 156 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 157 | 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 159 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 160 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 161 | 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 162 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 163 | 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 164 | 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 165 | 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 166 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 167 | 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 168 | 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 169 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 170 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 171 | 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 172 | 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 174 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 175 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 176 | 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 177 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 178 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 179 | ]; 180 | pub(crate) const ENCRYPTION_CONFIG3: [u8; 0x20] = [ 181 | 0x10, 0x07, 0x14, 0x15, 0x1D, 0x0C, 0x1C, 0x11, 0x01, 0x0F, 0x17, 0x1A, 0x05, 0x12, 0x1F, 0x0A, 182 | 0x02, 0x08, 0x18, 0x0E, 0x20, 0x1B, 0x03, 0x09, 0x13, 0x0D, 0x1E, 0x06, 0x16, 0x0B, 0x04, 0x19, 183 | ]; 184 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::io::Cursor; 2 | 3 | use byteorder::{LittleEndian, ReadBytesExt}; 4 | use chrono::{TimeZone, Utc}; 5 | use log::*; 6 | use pelite::{ 7 | pe32::{Pe, PeFile}, 8 | resources::Name, 9 | }; 10 | use pretty_hex::*; 11 | 12 | use thiserror::Error; 13 | 14 | mod constants; 15 | 16 | #[derive(Debug, Error)] 17 | pub enum Error { 18 | #[error("input file is not a Windows PE file")] 19 | InvalidFile, 20 | #[error("could not read metadata: {0}")] 21 | InvalidMetadata(&'static str), 22 | #[error("error occurred while trying to parse input file")] 23 | Parsing(#[from] pelite::Error), 24 | #[error("error occurred while trying to find `RES_UPDATE_INFO` resource")] 25 | NoResource(#[from] pelite::resources::FindError), 26 | } 27 | 28 | /// Takes the input PE data, parses it as a 32-bit PE, and if successful returns 29 | /// the `RES_UPDATE_INFO` data. 30 | pub fn update_info_from_pe(pe_data: &[u8]) -> Result<&[u8], Error> { 31 | let pe_file = PeFile::from_bytes(pe_data)?; 32 | let resources = pe_file.resources()?; 33 | 34 | resources 35 | .find_resource(&[Name::Id(23), Name::Str("RES_UPDATE_INFO")]) 36 | .map_err(Error::from) 37 | } 38 | 39 | /// Decrypts the input `update_info` and returns its decrypted form. 40 | pub fn decrypt(update_info: &[u8]) -> Result, Error> { 41 | // First 4 bytes of the update info are a timestamp 42 | let mut decryptor = Decryptor::default(); 43 | decryptor.inflate_timestamp(u32::from_le_bytes(update_info[..4].try_into().unwrap())); 44 | 45 | // There's a blob of size 0x5c at the end of the update info that describes 46 | // the update 47 | let mut reader = Cursor::new(&update_info[0x100_004..]); 48 | let firmware_size = reader 49 | .read_u32::() 50 | .map_err(|_| Error::InvalidMetadata("firmware_size"))? as usize; 51 | eprintln!("Maybe firmware size: {:#x}", firmware_size); 52 | let firmware_size = 0x100_000; 53 | 54 | // // No idea if this is actually a string count 55 | // let maybe_string_count = reader 56 | // .read_u32::() 57 | // .map_err(|_| Error::InvalidMetadata("string_count"))?; 58 | 59 | // let mut str_buffer = Vec::with_capacity(0x100); 60 | // for _ in 0..maybe_string_count as usize { 61 | // str_buffer.clear(); 62 | // loop { 63 | // let c = reader 64 | // .read_u8() 65 | // .map_err(|_| Error::InvalidMetadata("string_table"))?; 66 | // if c == 0x0 { 67 | // break; 68 | // } 69 | 70 | // str_buffer.push(c); 71 | // } 72 | // eprintln!( 73 | // "{}", 74 | // std::str::from_utf8(str_buffer.as_slice()) 75 | // .map_err(|_| Error::InvalidMetadata("string_in_string_table"))? 76 | // ); 77 | // } 78 | 79 | Ok(decryptor.decrypt_data(&update_info[4..firmware_size + 4])) 80 | } 81 | 82 | struct Decryptor { 83 | key: [u8; 0x300], 84 | } 85 | 86 | impl Decryptor { 87 | fn set_key(&mut self, key: &[u8; 56]) { 88 | let mut scrambled_table = key.clone(); 89 | // drop the input key so we don't accidentally use it from here on out 90 | drop(key); 91 | 92 | // the program technically reads DWORDS from the KEY_CONFIG and increments 93 | // their pointer by 1 DWORD per iteration... but we only need to read out 94 | // the MSB and this simplifies things 95 | for i in 0..16 { 96 | let rounds = if constants::KEY_CONFIG[i * 4] == 2 { 97 | 2 98 | } else { 99 | 1 100 | }; 101 | 102 | for _ in 0..rounds { 103 | let mut temp_byte = scrambled_table[0]; 104 | scrambled_table.copy_within(1..=27, 0); 105 | scrambled_table[27] = temp_byte; 106 | 107 | temp_byte = scrambled_table[28]; 108 | scrambled_table.copy_within(29.., 28); 109 | scrambled_table[55] = temp_byte; 110 | } 111 | 112 | for key_config_idx in 0..48 { 113 | let scrambled_idx = (constants::KEY_CONFIG2[key_config_idx] as usize) - 1; 114 | 115 | let swaptable_idx = key_config_idx + (i * 48); 116 | self.key[swaptable_idx] = scrambled_table[scrambled_idx]; 117 | } 118 | } 119 | } 120 | 121 | fn decrypt(&mut self, outbuf: &mut [u8], is_encrypt: bool) { 122 | let mut multiplier = 0x0; 123 | let mut remaining_data = 15; 124 | let mut scratch_buffer = [0u8; 48]; 125 | let mut done = false; 126 | if !is_encrypt { 127 | multiplier = 0xF; 128 | } 129 | 130 | while !done { 131 | for i in 0..(48 / 6) { 132 | trace!(""); 133 | trace!("round {}", i); 134 | trace!("\n{} start temp:\n{:?}", i, (&scratch_buffer).hex_dump()); 135 | trace!("\ninflated data: {:?}\n", outbuf.hex_dump()); 136 | 137 | trace!("multiplier: 0x{:X}", multiplier); 138 | 139 | const BYTES_PER_ROUND: usize = 6; 140 | // We do 6 bytes per round 141 | let iidx = i * BYTES_PER_ROUND; 142 | 143 | // We read 6 bytes at a time 144 | for j in 0..BYTES_PER_ROUND { 145 | debug!("{}, {}", iidx, j); 146 | debug!("config: {:#x}", constants::ENCRYPTION_CONFIG[iidx + j]); 147 | let rhs_idx = (constants::ENCRYPTION_CONFIG[iidx + j] as usize) + 31; 148 | debug!("inflated_data idx: {:#x}", rhs_idx); 149 | let rhs = outbuf[rhs_idx]; 150 | debug!("inflated_data : {:#x}", rhs); 151 | let lhs_idx = (48 * multiplier) + iidx + j; 152 | debug!("key idx: {:#x}", lhs_idx); 153 | let lhs = self.key[lhs_idx]; 154 | debug!("key : {:#x}", lhs); 155 | let result = lhs ^ rhs; 156 | debug!("result: {:#x}", result); 157 | let result_idx = iidx + j; 158 | 159 | debug!("result idx: {:#x}", result_idx); 160 | scratch_buffer[result_idx] = result; 161 | 162 | debug!(""); 163 | } 164 | debug!("\n{} temp:\n{:?}", i, (&scratch_buffer).hex_dump()); 165 | } 166 | debug!("temp:\n{:?}", (&scratch_buffer).hex_dump()); 167 | 168 | macro_rules! combine { 169 | ($offset:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => {{ 170 | // these get subtracted by 4 since in the original code there 171 | // is a `this` pointer stored between data buffers. We don't 172 | // have that. 173 | let a = $a - 4; 174 | let b = $b - 4; 175 | let c = $c - 4; 176 | let d = $d - 4; 177 | let e = $e - 4; 178 | let f = $f - 4; 179 | 180 | debug!( 181 | "a={}, val={:#x}, shifted={:#x}", 182 | $a, 183 | scratch_buffer[a] as u32, 184 | (scratch_buffer[a] as u32 * 32) + 2 185 | ); 186 | debug!( 187 | "b={}, val={:#x}, shifted={:#x}", 188 | $b, 189 | scratch_buffer[b] as u32, 190 | (scratch_buffer[b] as u32 * 16) + 2 191 | ); 192 | debug!( 193 | "c={}, val={:#x}, shifted={:#x}", 194 | $c, 195 | scratch_buffer[c] as u32, 196 | (scratch_buffer[c] as u32 * 8 + 2) 197 | ); 198 | debug!( 199 | "d={}, val={:#x}, shifted={:#x}", 200 | $d, 201 | scratch_buffer[d] as u32, 202 | (scratch_buffer[d] as u32 * 4 + 2) 203 | ); 204 | debug!( 205 | "e={}, val={:#x}, shifted={:#x}", 206 | $e, 207 | scratch_buffer[e] as u32, 208 | (scratch_buffer[e] as u32 * 2 + 2) 209 | ); 210 | debug!( 211 | "f={}, val={:#x}, shifted={:#x}", 212 | $f, 213 | scratch_buffer[f] as u32, 214 | (scratch_buffer[f] as u32 + 2) 215 | ); 216 | let mystery_idx = ((scratch_buffer[a] as u32 * 32 + 2) 217 | | (scratch_buffer[b] as u32 * 16 + 2) 218 | | (scratch_buffer[c] as u32 * 8 + 2) 219 | | (scratch_buffer[d] as u32 * 4 + 2) 220 | | (scratch_buffer[e] as u32 * 2 + 2) 221 | | (scratch_buffer[f] as u32 + 2)) as usize; 222 | debug!("offset: {:}", $offset); 223 | debug!("full idx: {:#x}", mystery_idx + $offset); 224 | 225 | debug!("{:#X?}", &constants::ENCRYPTION_CONFIG2[$offset + mystery_idx..][..4]); 226 | 227 | let val = u32::from_le_bytes(constants::ENCRYPTION_CONFIG2[$offset + mystery_idx..][..4].try_into().unwrap()); 228 | debug!("{:#x}", val); 229 | val 230 | }}; 231 | } 232 | 233 | let temp1 = combine!(0, 4, 9, 5, 6, 7, 8); 234 | let temp2 = combine!(0x100, 10, 15, 11, 12, 13, 14); 235 | let temp3 = combine!(0x200, 16, 21, 17, 18, 19, 20); 236 | let temp4 = combine!(0x300, 22, 27, 23, 24, 25, 26); 237 | let temp5 = combine!(0x400, 28, 33, 29, 30, 31, 32); 238 | let temp6 = combine!(0x500, 34, 39, 35, 36, 37, 38); 239 | let temp7 = combine!(0x600, 40, 45, 41, 42, 43, 44); 240 | let temp8 = combine!(0x700, 46, 51, 47, 48, 49, 50); 241 | let mut temp_key_material: Vec = [ 242 | temp1.to_le_bytes(), 243 | temp2.to_le_bytes(), 244 | temp3.to_le_bytes(), 245 | temp4.to_le_bytes(), 246 | temp5.to_le_bytes(), 247 | temp6.to_le_bytes(), 248 | temp7.to_le_bytes(), 249 | temp8.to_le_bytes(), 250 | ] 251 | .iter() 252 | .flatten() 253 | .cloned() 254 | .collect(); 255 | 256 | debug!( 257 | "temp_key_material before append: {:?}", 258 | temp_key_material.hex_dump() 259 | ); 260 | temp_key_material.extend_from_slice(&scratch_buffer); 261 | debug!("temp_key_material: {:?}", temp_key_material.hex_dump()); 262 | 263 | debug!("\n\noutput:{:?}\n\n", outbuf.hex_dump()); 264 | let mut output_buffer_offset = 0; 265 | if remaining_data == 0 { 266 | for _i in 0..8 { 267 | debug!("\n\noutput BEFORE:{:?}\n\n", outbuf.hex_dump()); 268 | 269 | outbuf[output_buffer_offset + 0] ^= temp_key_material 270 | [constants::ENCRYPTION_CONFIG3[output_buffer_offset] as usize - 1]; 271 | outbuf[output_buffer_offset + 1] ^= temp_key_material 272 | [constants::ENCRYPTION_CONFIG3[output_buffer_offset + 1] as usize - 1]; 273 | outbuf[output_buffer_offset + 2] ^= temp_key_material 274 | [constants::ENCRYPTION_CONFIG3[output_buffer_offset + 2] as usize - 1]; 275 | outbuf[output_buffer_offset + 3] ^= temp_key_material 276 | [constants::ENCRYPTION_CONFIG3[output_buffer_offset + 3] as usize - 1]; 277 | output_buffer_offset += 4; 278 | 279 | debug!("\n\noutput AFTER:{:?}\n\n", outbuf.hex_dump()); 280 | } 281 | } else { 282 | for i in 0..8 { 283 | debug!(""); 284 | debug!("round: {}", i); 285 | for (first, second) in (0x1c..=0x1f).zip(0..4) { 286 | debug!("\n\noutput BEFORE:{:?}\n\n", outbuf.hex_dump()); 287 | debug!("swapping {:#x} with {:#x}", first, second); 288 | 289 | let original_byte_idx = first + output_buffer_offset + 4; 290 | 291 | debug!("original byte index: {:#x}", original_byte_idx); 292 | let original_byte = outbuf[original_byte_idx]; 293 | debug!("original byte: {:#x}", original_byte); 294 | 295 | let constant = 296 | constants::ENCRYPTION_CONFIG3[output_buffer_offset + second] as usize; 297 | 298 | debug!("curr byte: {:#x}", outbuf[output_buffer_offset + second]); 299 | debug!("constant: {:#x}", constant); 300 | debug!("xor rhs: {:#x}", temp_key_material[constant - 1]); 301 | debug!( 302 | "{:#x} ^ {:#x}", 303 | outbuf[output_buffer_offset + second], 304 | temp_key_material[constant - 1] 305 | ); 306 | 307 | let new_byte = 308 | outbuf[output_buffer_offset + second] ^ temp_key_material[constant - 1]; 309 | 310 | debug!("new byte: {:#x}", new_byte); 311 | 312 | let new_idx = original_byte_idx; 313 | debug!("new byte goes to {:#X}", new_idx); 314 | debug!("old byte goes to {:#X}", output_buffer_offset + second); 315 | outbuf[new_idx] = new_byte; 316 | outbuf[output_buffer_offset + second] = original_byte; 317 | 318 | debug!("\n\noutput AFTER:{:?}\n\n", outbuf.hex_dump()); 319 | debug!(""); 320 | } 321 | 322 | output_buffer_offset += 4; 323 | 324 | debug!(""); 325 | } 326 | } 327 | 328 | done = remaining_data == 0; 329 | remaining_data -= 1; 330 | if is_encrypt { 331 | multiplier += 1; 332 | } else { 333 | multiplier = multiplier.saturating_sub(1); 334 | } 335 | } 336 | } 337 | 338 | pub fn inflate_timestamp(&mut self, timestamp: u32) { 339 | // Convert the timestamp to a string 340 | let date = Utc.timestamp(timestamp as i64, 0); 341 | let formatted_date = date.format("%Y%m%d%H%M%S").to_string(); 342 | let mut outbuf = [0u8; 64]; 343 | 344 | // There are 4 different rounds for setting up the timestamp key 345 | let mut date_bytes = formatted_date.as_bytes().iter().cloned(); 346 | let mut curr_byte = date_bytes.next().unwrap(); 347 | for swap_table in 0..4 { 348 | self.set_key(&constants::TIMESTAMP_TABLES[swap_table]); 349 | for byte_idx in 0..8 { 350 | for bit_idx in 0..8 { 351 | let bit_value = (curr_byte >> (7 - bit_idx)) & 1; 352 | let outbuf_idx = (byte_idx * 8) + bit_idx; 353 | outbuf[outbuf_idx] = bit_value ^ outbuf[outbuf_idx]; 354 | } 355 | 356 | if let Some(next) = date_bytes.next() { 357 | curr_byte = next; 358 | } else { 359 | curr_byte = 0x0; 360 | } 361 | } 362 | 363 | self.decrypt(&mut outbuf, true); 364 | } 365 | 366 | self.set_key(&outbuf[..56].try_into().unwrap()); 367 | } 368 | 369 | pub fn decrypt_data(&mut self, encrypted_data: &[u8]) -> Vec { 370 | let mut decrypted = vec![0u8; encrypted_data.len()]; 371 | let mut inflated: [u8; 64] = [0u8; 64]; 372 | 373 | let mut output_idx = 0; 374 | let mut remaining_data = encrypted_data.len(); 375 | loop { 376 | let mut block_size = std::cmp::min(8, remaining_data); 377 | remaining_data = remaining_data.saturating_sub(block_size); 378 | //println!("{:#x}", remaining_data); 379 | for i in 0..block_size { 380 | let encrypted_bytes = encrypted_data[i + output_idx]; 381 | let bit_idx = i * 8; 382 | inflated[bit_idx] = encrypted_bytes >> 7; 383 | inflated[bit_idx + 1] = (encrypted_bytes >> 6) & 1; 384 | inflated[bit_idx + 2] = (encrypted_bytes >> 5) & 1; 385 | inflated[bit_idx + 3] = (encrypted_bytes >> 4) & 1; 386 | inflated[bit_idx + 4] = (encrypted_bytes >> 3) & 1; 387 | inflated[bit_idx + 5] = (encrypted_bytes >> 2) & 1; 388 | inflated[bit_idx + 6] = (encrypted_bytes >> 1) & 1; 389 | inflated[bit_idx + 7] = encrypted_bytes & 0x1; 390 | } 391 | 392 | self.decrypt(&mut inflated, false); 393 | 394 | let mut curr_inflated_idx = 0; 395 | while block_size > 0 { 396 | block_size -= 1; 397 | 398 | let inflated = &mut inflated[curr_inflated_idx * 8..]; 399 | // we need to reassemble 8 bits 400 | for shift in 0..8 { 401 | decrypted[output_idx] |= inflated[7 - shift] << shift; 402 | } 403 | 404 | // println!("{:#X}", deobfuscated[output_idx]); 405 | output_idx += 1; 406 | curr_inflated_idx += 1; 407 | } 408 | 409 | if remaining_data == 0 { 410 | return decrypted; 411 | } 412 | } 413 | } 414 | } 415 | 416 | impl Default for Decryptor { 417 | fn default() -> Decryptor { 418 | Self { key: [0u8; 0x300] } 419 | } 420 | } 421 | --------------------------------------------------------------------------------