1#![deny(clippy::all, clippy::nursery)]
31#![deny(nonstandard_style, rust_2018_idioms)]
32#![deny(missing_docs, missing_debug_implementations)]
33#![forbid(unsafe_code)]
34#![no_std]
35
36#[cfg(doctest)]
37doc_comment::doctest!("../README.md", readme);
38
39pub mod cb1;
40pub mod cb7;
41mod rc4;
42
43#[cfg(test)]
44mod std_alloc {
45 #[cfg(feature = "std")]
46 extern crate std as alloc;
47
48 #[cfg(not(feature = "std"))]
49 extern crate alloc;
50
51 pub use alloc::{fmt, vec, vec::Vec};
52}
53
54use cb7::{is_beefcode, Cb7};
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57enum Scheme {
58 Raw,
59 V1,
60 V7,
61}
62
63#[derive(Debug, Clone, Copy)]
65pub struct Codebreaker {
66 scheme: Scheme,
67 cb7: Cb7,
68 code_lines: usize,
69}
70
71impl Default for Codebreaker {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl Codebreaker {
79 pub const fn new() -> Self {
82 Self {
83 scheme: Scheme::Raw,
84 cb7: Cb7::new(),
85 code_lines: 0,
86 }
87 }
88
89 pub fn new_v7() -> Self {
93 Self {
94 scheme: Scheme::V7,
95 cb7: Cb7::default(),
96 code_lines: 0,
97 }
98 }
99
100 pub fn encrypt_code(&mut self, addr: u32, val: u32) -> (u32, u32) {
111 let mut code = (addr, val);
112 self.encrypt_code_mut(&mut code.0, &mut code.1);
113 code
114 }
115
116 pub fn encrypt_code_mut(&mut self, addr: &mut u32, val: &mut u32) {
128 let (oldaddr, oldval) = (*addr, *val);
129
130 if self.scheme == Scheme::V7 {
131 self.cb7.encrypt_code_mut(addr, val);
132 } else {
133 cb1::encrypt_code_mut(addr, val);
134 }
135
136 if is_beefcode(oldaddr) {
137 self.cb7.beefcode(oldaddr, oldval);
138 self.scheme = Scheme::V7;
139 }
140 }
141
142 pub fn decrypt_code(&mut self, addr: u32, val: u32) -> (u32, u32) {
166 let mut code = (addr, val);
167 self.decrypt_code_mut(&mut code.0, &mut code.1);
168 code
169 }
170
171 pub fn decrypt_code_mut(&mut self, addr: &mut u32, val: &mut u32) {
195 if self.scheme == Scheme::V7 {
196 self.cb7.decrypt_code_mut(addr, val);
197 } else {
198 cb1::decrypt_code_mut(addr, val);
199 }
200
201 if is_beefcode(*addr) {
202 self.cb7.beefcode(*addr, *val);
203 self.scheme = Scheme::V7;
204 }
205 }
206
207 pub fn auto_decrypt_code(&mut self, addr: u32, val: u32) -> (u32, u32) {
233 let mut code = (addr, val);
234 self.auto_decrypt_code_mut(&mut code.0, &mut code.1);
235 code
236 }
237
238 pub fn auto_decrypt_code_mut(&mut self, addr: &mut u32, val: &mut u32) {
241 if self.scheme != Scheme::V7 {
242 if self.code_lines == 0 {
243 self.code_lines = num_code_lines(*addr);
244 if (*addr >> 24) & 0x0e != 0 {
245 if is_beefcode(*addr) {
246 self.code_lines -= 1;
248 return;
249 }
250 self.scheme = Scheme::V1;
251 self.code_lines -= 1;
252 cb1::decrypt_code_mut(addr, val);
253 } else {
254 self.scheme = Scheme::Raw;
255 self.code_lines -= 1;
256 }
257 } else {
258 self.code_lines -= 1;
259 if self.scheme == Scheme::Raw {
260 return;
261 }
262 cb1::decrypt_code_mut(addr, val);
263 }
264 } else {
265 self.cb7.decrypt_code_mut(addr, val);
266 if self.code_lines == 0 {
267 self.code_lines = num_code_lines(*addr);
268 if self.code_lines == 1 && *addr == 0xffff_ffff {
269 self.code_lines = 0;
271 return;
272 }
273 }
274 self.code_lines -= 1;
275 }
276
277 if is_beefcode(*addr) {
278 self.cb7.beefcode(*addr, *val);
279 self.scheme = Scheme::V7;
280 self.code_lines = 1;
281 }
282 }
283}
284
285const fn num_code_lines(addr: u32) -> usize {
286 let cmd = addr >> 28;
287
288 if cmd < 3 || cmd > 6 {
289 1
290 } else if cmd == 3 {
291 if addr & 0x0040_0000 != 0 {
292 2
293 } else {
294 1
295 }
296 } else {
297 2
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304 use crate::code::Code;
305 use crate::std_alloc::{vec, Vec};
306 #[cfg(feature = "std")]
307 use pretty_assertions::assert_eq;
308
309 struct Test {
310 cb: Codebreaker,
311 decrypted: Vec<Code>,
312 encrypted: Vec<Code>,
313 }
314
315 fn tests() -> Vec<Test> {
316 vec![
317 Test {
318 cb: Codebreaker::new(),
319 decrypted: vec![
320 "2043AFCC 2411FFFF".into(),
321 "BEEFC0DE 00000000".into(),
322 "2096F5B8 000000BE".into(),
323 ],
324 encrypted: vec![
325 "2AFF014C 2411FFFF".into(),
326 "B4336FA9 4DFEFB79".into(),
327 "973E0B2A A7D4AF10".into(),
328 ],
329 },
330 Test {
331 cb: Codebreaker::new_v7(),
332 decrypted: vec![
333 "9029BEAC 0C0A9225".into(),
334 "201F6024 00000000".into(),
335 "2096F5B8 000000BE".into(),
336 ],
337 encrypted: vec![
338 "D08F3A49 00078A53".into(),
339 "3818DDE5 E72B2B16".into(),
340 "973E0B2A A7D4AF10".into(),
341 ],
342 },
343 Test {
344 cb: Codebreaker::default(),
345 decrypted: vec![
346 "9029BEAC 0C0A9225".into(),
347 "201F6024 00000000".into(),
348 "2096F5B8 000000BE".into(),
349 ],
350 encrypted: vec![
351 "9A545CC6 188CBCFB".into(),
352 "2A973DBD 00000000".into(),
353 "2A03B60A 000000BE".into(),
354 ],
355 },
356 ]
357 }
358
359 #[test]
360 fn test_encrypt_code() {
361 for t in &mut tests() {
362 for (i, &code) in t.decrypted.iter().enumerate() {
363 let result: Code = t.cb.encrypt_code(code.0, code.1).into();
364 assert_eq!(result, t.encrypted[i]);
365 }
366 }
367 }
368
369 #[test]
370 fn test_encrypt_code_mut() {
371 for t in &mut tests() {
372 for (i, code) in t.decrypted.iter_mut().enumerate() {
373 t.cb.encrypt_code_mut(&mut code.0, &mut code.1);
374 assert_eq!(*code, t.encrypted[i]);
375 }
376 }
377 }
378
379 #[test]
380 fn test_decrypt_code() {
381 for t in &mut tests() {
382 for (i, &code) in t.encrypted.iter().enumerate() {
383 let result: Code = t.cb.decrypt_code(code.0, code.1).into();
384 assert_eq!(result, t.decrypted[i]);
385 }
386 }
387 }
388
389 #[test]
390 fn test_decrypt_code_mut() {
391 for t in &mut tests() {
392 for (i, code) in t.encrypted.iter_mut().enumerate() {
393 t.cb.decrypt_code_mut(&mut code.0, &mut code.1);
394 assert_eq!(*code, t.decrypted[i]);
395 }
396 }
397 }
398
399 struct AutoTest {
400 input: Vec<Code>,
401 output: Vec<Code>,
402 }
403
404 fn auto_tests() -> Vec<AutoTest> {
405 vec![
406 AutoTest {
407 input: vec![
409 "9029BEAC 0C0A9225".into(),
410 "201F6024 00000000".into(),
411 "2096F5B8 000000BE".into(),
412 ],
413 output: vec![
414 "9029BEAC 0C0A9225".into(),
415 "201F6024 00000000".into(),
416 "2096F5B8 000000BE".into(),
417 ],
418 },
419 AutoTest {
420 input: vec![
422 "9A545CC6 188CBCFB".into(),
423 "2A973DBD 00000000".into(),
424 "2A03B60A 000000BE".into(),
425 ],
426 output: vec![
427 "9029BEAC 0C0A9225".into(),
428 "201F6024 00000000".into(),
429 "2096F5B8 000000BE".into(),
430 ],
431 },
432 AutoTest {
433 input: vec![
435 "B4336FA9 4DFEFB79".into(),
436 "D08F3A49 00078A53".into(),
437 "3818DDE5 E72B2B16".into(),
438 "973E0B2A A7D4AF10".into(),
439 ],
440 output: vec![
441 "BEEFC0DE 00000000".into(),
442 "9029BEAC 0C0A9225".into(),
443 "201F6024 00000000".into(),
444 "2096F5B8 000000BE".into(),
445 ],
446 },
447 AutoTest {
448 input: vec![
450 "9A545CC6 188CBCFB".into(),
451 "2A973DBD 00000000".into(),
452 "B4336FA9 4DFEFB79".into(),
453 "973E0B2A A7D4AF10".into(),
454 ],
455 output: vec![
456 "9029BEAC 0C0A9225".into(),
457 "201F6024 00000000".into(),
458 "BEEFC0DE 00000000".into(),
459 "2096F5B8 000000BE".into(),
460 ],
461 },
462 AutoTest {
463 input: vec![
465 "9029BEAC 0C0A9225".into(),
466 "2A973DBD 00000000".into(),
467 "B4336FA9 4DFEFB79".into(),
468 "973E0B2A A7D4AF10".into(),
469 ],
470 output: vec![
471 "9029BEAC 0C0A9225".into(),
472 "201F6024 00000000".into(),
473 "BEEFC0DE 00000000".into(),
474 "2096F5B8 000000BE".into(),
475 ],
476 },
477 ]
478 }
479
480 #[test]
481 fn test_auto_decrypt_code() {
482 for t in &mut auto_tests() {
483 let mut cb = Codebreaker::new();
484 for (i, &code) in t.input.iter().enumerate() {
485 let result: Code = cb.auto_decrypt_code(code.0, code.1).into();
486 assert_eq!(result, t.output[i]);
487 }
488 }
489 }
490
491 #[test]
492 fn test_auto_decrypt_code_mut() {
493 for t in &mut auto_tests() {
494 let mut cb = Codebreaker::new();
495 for (i, code) in t.input.iter_mut().enumerate() {
496 cb.auto_decrypt_code_mut(&mut code.0, &mut code.1);
497 assert_eq!(*code, t.output[i]);
498 }
499 }
500 }
501}
502
503#[cfg(test)]
504mod code {
505 use crate::std_alloc::{fmt, Vec};
506
507 #[derive(Copy, Clone, PartialEq, Eq)]
508 pub struct Code(pub u32, pub u32);
509
510 impl From<(u32, u32)> for Code {
511 fn from(t: (u32, u32)) -> Self {
512 Self(t.0, t.1)
513 }
514 }
515
516 impl From<&str> for Code {
517 fn from(s: &str) -> Self {
518 let t: Vec<u32> = s
519 .splitn(2, ' ')
520 .map(|v| u32::from_str_radix(v, 16).expect("invalid code format"))
521 .collect();
522
523 Self(t[0], t[1])
524 }
525 }
526
527 impl fmt::Display for Code {
529 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
530 write!(f, "{:08X} {:08X}", self.0, self.1)
531 }
532 }
533
534 impl fmt::Debug for Code {
536 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
537 write!(f, "{self}")
538 }
539 }
540}