rsp6-decoder/src/main.rs
2022-12-31 15:08:25 +00:00

104 lines
3.7 KiB
Rust

use crate::keys::IssuerKeyStore;
use crate::payload::Rsp6Ticket;
use anyhow::anyhow;
use num_bigint::BigUint;
mod keys;
mod payload;
fn base26_decode(input: &str) -> BigUint {
let mut out = BigUint::new(Vec::new());
for val in input.as_bytes().iter().rev() {
out *= 26u32;
out += *val - b'A';
}
BigUint::from_bytes_le(&out.to_bytes_be())
}
fn strip_padding(tkt: &[u8]) -> Option<&[u8]> {
if tkt.is_empty() {
return None;
}
match tkt[0] {
1 => {
// PKCS#1 v1
let tkt = &tkt[1..];
let mut iter = tkt.iter();
loop {
match iter.next()? {
0 => {
return Some(iter.as_slice());
}
255 => {}
_ => return None,
}
}
}
2 => {
// PKCS#1 v2
let tkt = &tkt[1..];
let mut iter = tkt.iter();
loop {
match iter.next()? {
0 => {
return Some(iter.as_slice());
}
_ => {}
}
}
}
_ => None,
}
}
fn main() -> anyhow::Result<()> {
let iks = IssuerKeyStore::new();
eprintln!("[+] Loaded {} public keys!", iks.keys.len());
eprintln!("[+] mmm, give me a tasty ticket on stdin please");
let ticket_str = std::io::stdin()
.lines()
.next()
.ok_or_else(|| anyhow!("that was a bit rude, give me an actual ticket"))??;
if ticket_str.len() < 16 {
return Err(anyhow!("ticket too short"));
}
if &ticket_str[0..2] != "06" {
return Err(anyhow!(
"ticket isn't a RSP6 ticket: magic was {}",
&ticket_str[0..2]
));
}
let issuer_id = &ticket_str[13..15];
let ticket_reference = format!("{}{}", issuer_id, &ticket_str[2..11]);
eprintln!("[+] RSP6 ticket, reference {}", ticket_reference);
let ticket = base26_decode(&ticket_str[15..]);
let keys = iks
.keys
.get(issuer_id)
.ok_or_else(|| anyhow!("unknown issuer ID {}", issuer_id))?;
for key in keys {
let message = ticket.modpow(&key.public_exponent, &key.modulus);
let message = message.to_bytes_be();
if let Some(unpadded) = strip_padding(&message) {
eprintln!("[+] decrypt done!");
let ticket = Rsp6Ticket::decode(unpadded, issuer_id.into(), ticket_str[11..13].into())?;
serde_json::to_writer_pretty(std::io::stdout(), &ticket)?;
return Ok(());
} else {
eprintln!("[-] failed decrypt: {:?}", message);
}
}
Err(anyhow!("no valid decryptions"))
}
#[cfg(test)]
mod test {
#[test]
fn test_base26() {
assert_eq!(
super::base26_decode("RANEBZCYPNQVMMYJBOJBONYSIYXTREYFSHTZFZEXWTVBNXJBFVOFBMXVQPZTFWVYSWYKINRXRVDCCUWUERKQZKYBPVIIAPJOOFJJXUBFGNVXGXTCFPBHXYVPEKWIURBEOYTYNZUXWVIXHAODACOQLZEQKRUNGWSJHIIWOYSNXJKVYWIGLWCIZKAHFKKAKRDUQSQBGEJMOFCSHSKXSFDDKYCFQI").to_bytes_be(),
[53, 242, 184, 141, 14, 99, 169, 215, 200, 223, 85, 250, 45, 253, 184, 100, 225, 124, 82, 70, 138, 222, 246, 185, 192, 129, 247, 218, 24, 26, 249, 112, 74, 225, 71, 139, 27, 50, 218, 11, 93, 238, 232, 163, 151, 68, 159, 146, 80, 133, 11, 45, 57, 245, 163, 117, 218, 11, 187, 246, 18, 147, 88, 171, 133, 216, 166, 47, 232, 246, 198, 170, 99, 36, 120, 114, 73, 207, 19, 218, 202, 146, 158, 223, 107, 234, 171, 172, 20, 189, 133, 246, 192, 248, 57, 111, 65, 65, 135, 64, 241, 99, 87, 107, 75, 40, 224, 223, 100, 53, 180, 212, 53, 200, 172, 117, 127, 248, 193, 0, 147, 167, 222, 81, 135, 158, 135, 137]
)
}
}