mirror of
https://git.eta.st/eta/rsp6-decoder.git
synced 2024-12-24 00:55:46 +00:00
general cleanup, json output, no cursed code
This commit is contained in:
parent
90e1c41858
commit
d4918a2b00
277
Cargo.lock
generated
277
Cargo.lock
generated
@ -14,12 +14,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "1.0.1"
|
||||
@ -32,82 +26,12 @@ dependencies = [
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
@ -124,41 +48,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"libm",
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -171,17 +68,6 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
@ -189,46 +75,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719"
|
||||
dependencies = [
|
||||
"der",
|
||||
"pkcs8",
|
||||
"spki",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.49"
|
||||
@ -253,57 +101,6 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "094052d5470cbcef561cb848a7209968c9f12dfa6d668f4bca048ac5de51099c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"digest",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"signature",
|
||||
"smallvec",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsp6-decoder"
|
||||
version = "0.1.0"
|
||||
@ -311,8 +108,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"bitvec",
|
||||
"hex",
|
||||
"rand",
|
||||
"rsa",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"time",
|
||||
@ -355,44 +151,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "1.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
@ -416,6 +174,7 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
@ -436,30 +195,12 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
@ -468,9 +209,3 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||
dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
|
||||
|
@ -9,8 +9,7 @@ edition = "2021"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
anyhow = "1.0"
|
||||
serde_json = "1.0"
|
||||
rsa = "0.7"
|
||||
rand = "0.8"
|
||||
num-bigint = "0.4"
|
||||
bitvec = "1.0"
|
||||
hex = { version = "0.4", features = ["serde"] }
|
||||
time = { version = "0.3", features = ["macros", "serde"] }
|
||||
time = { version = "0.3", features = ["macros", "serde", "serde-human-readable"] }
|
20
keys.json
20
keys.json
@ -426,16 +426,6 @@
|
||||
}
|
||||
],
|
||||
"TT": [
|
||||
{
|
||||
"is_private": false,
|
||||
"is_test": true,
|
||||
"issuer_id": "TT",
|
||||
"modulus_hex": "C8D75C530F796A893FC2FECE2AE2037A815502CFB32C2C0CF25FE0FEDDE58D5DDA86FF673C17BC1272333D4D3D14E7A71ECAF054A6DE808968CDEF40CB1A5FAF8AE248E46497611F948ACBB12996C38FB22F9427D8D932B11F78958E53EF9275EAED2153C411192CF8BC804DF7784BE07EF68ED06738C238F96ACEA5EF740C35",
|
||||
"public_exponent_hex": "10001",
|
||||
"public_key_x509": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI11xTD3lqiT/C/s4q4gN6gVUC\nz7MsLAzyX+D+3eWNXdqG/2c8F7wScjM9TT0U56ceyvBUpt6AiWjN70DLGl+viuJI\n5GSXYR+UisuxKZbDj7IvlCfY2TKxH3iVjlPvknXq7SFTxBEZLPi8gE33eEvgfvaO\n0Gc4wjj5as6l73QMNQIDAQAB\n-----END PUBLIC KEY-----",
|
||||
"valid_from": "2009-01-01 00:00:00",
|
||||
"valid_until": "2040-12-31 00:00:00"
|
||||
},
|
||||
{
|
||||
"is_private": false,
|
||||
"is_test": false,
|
||||
@ -445,6 +435,16 @@
|
||||
"public_key_x509": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXdAIcK60T3DHB7IGS4ITWDYLc\nMnAWhi6V7Qk61BzJCCpgFWMcjmuBSKFeyYVuKl4WUZ5S7cDD3yg2k1BV71Phc4KT\nJWRk8K1K48Aa483ZEMscvcCrNcGtjPCpN2s5Id7j0fwm/6NAnE3I+BOl4ybXjGOr\nqaWRINdAQ9uhFBBHrwIDAQAB\n-----END PUBLIC KEY-----",
|
||||
"valid_from": "2010-01-01 00:00:00",
|
||||
"valid_until": "2040-12-31 00:00:00"
|
||||
},
|
||||
{
|
||||
"is_private": false,
|
||||
"is_test": true,
|
||||
"issuer_id": "TT",
|
||||
"modulus_hex": "C8D75C530F796A893FC2FECE2AE2037A815502CFB32C2C0CF25FE0FEDDE58D5DDA86FF673C17BC1272333D4D3D14E7A71ECAF054A6DE808968CDEF40CB1A5FAF8AE248E46497611F948ACBB12996C38FB22F9427D8D932B11F78958E53EF9275EAED2153C411192CF8BC804DF7784BE07EF68ED06738C238F96ACEA5EF740C35",
|
||||
"public_exponent_hex": "10001",
|
||||
"public_key_x509": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI11xTD3lqiT/C/s4q4gN6gVUC\nz7MsLAzyX+D+3eWNXdqG/2c8F7wScjM9TT0U56ceyvBUpt6AiWjN70DLGl+viuJI\n5GSXYR+UisuxKZbDj7IvlCfY2TKxH3iVjlPvknXq7SFTxBEZLPi8gE33eEvgfvaO\n0Gc4wjj5as6l73QMNQIDAQAB\n-----END PUBLIC KEY-----",
|
||||
"valid_from": "2009-01-01 00:00:00",
|
||||
"valid_until": "2040-12-31 00:00:00"
|
||||
}
|
||||
],
|
||||
"TV": [
|
||||
|
@ -1,52 +0,0 @@
|
||||
pub fn slice_bool(a: &[u8], index: usize) -> bool {
|
||||
(a[index / 8] >> (7 - (index % 8))) == 1
|
||||
}
|
||||
|
||||
pub fn slice_int(a: &[u8], start_bit: usize, length_bits: usize) -> u32 {
|
||||
let i = start_bit as u32;
|
||||
let i2 = length_bits as u32;
|
||||
let mut i3: u32 = (i as u32) & 7;
|
||||
let mut i4: u32 = i3;
|
||||
let mut i5: u32 = (i as u32) >> 3;
|
||||
let mut i6: u32 = (1 << (8 - i3)) - 1;
|
||||
let mut i7: u32 = 0;
|
||||
let mut i8: u32 = 0;
|
||||
while (i2 - i7) > 0 {
|
||||
i8 |= (i6 & a[i5 as usize] as u32) << ((i4 + 24) - i7);
|
||||
i7 += 8 - i4;
|
||||
i6 = 255;
|
||||
i4 = 0;
|
||||
i5 += 1;
|
||||
}
|
||||
|
||||
i8 >> (32 - i2)
|
||||
}
|
||||
|
||||
pub fn slice_base64(a: &[u8], start_bit: usize, chars: usize) -> String {
|
||||
let mut sb = String::new();
|
||||
let mut i = start_bit as u32;
|
||||
let mut i2 = chars as u32;
|
||||
let mut i3: u32 = i & 7;
|
||||
let mut i4: u32 = i3;
|
||||
let mut i5: u32 = i >> 3;
|
||||
let mut i6: u32 = (1 << (8 - i3)) - 1;
|
||||
let mut i7: u32 = 0;
|
||||
let mut i8: u32 = 0;
|
||||
|
||||
while i2 > 0 {
|
||||
if i7 >= 6 {
|
||||
sb.push(((i8 >> 26) + 32) as u8 as char);
|
||||
i8 <<= 6;
|
||||
i7 -= 6;
|
||||
i2 -= 1;
|
||||
} else {
|
||||
i8 |= (i6 & a[i5 as usize] as u32) << ((i4 + 24) - i7);
|
||||
i7 += 8 - i4;
|
||||
i6 = 255;
|
||||
i4 = 0;
|
||||
i5 += 1
|
||||
}
|
||||
}
|
||||
|
||||
sb
|
||||
}
|
29
src/keys.rs
29
src/keys.rs
@ -1,29 +1,38 @@
|
||||
//! Decoding and using the RSA public keys needed to decrypt the ticket data.
|
||||
|
||||
use rsa::{BigUint, RsaPublicKey};
|
||||
use num_bigint::BigUint;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::collections::HashMap;
|
||||
|
||||
static KEYS_JSON: &'static str = include_str!("../keys.json");
|
||||
|
||||
fn deserialize_exponent_hex<'de, D>(deserializer: D) -> Result<u64, D::Error>
|
||||
fn deserialize_hex_as_biguint<'de, D>(deserializer: D) -> Result<BigUint, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let buf = String::deserialize(deserializer)?;
|
||||
|
||||
u64::from_str_radix(&buf, 16).map_err(serde::de::Error::custom)
|
||||
BigUint::parse_bytes(buf.as_bytes(), 16).ok_or(serde::de::Error::custom(format!(
|
||||
"failed to parse exponent hex"
|
||||
)))
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct IssuerKey {
|
||||
is_private: bool,
|
||||
is_test: bool,
|
||||
issuer_id: String,
|
||||
#[serde(rename = "modulus_hex", deserialize_with = "hex::serde::deserialize")]
|
||||
pub modulus: Vec<u8>,
|
||||
pub public_exponent_hex: String,
|
||||
public_key_x509: Option<String>,
|
||||
pub is_private: bool,
|
||||
pub is_test: bool,
|
||||
pub issuer_id: String,
|
||||
#[serde(
|
||||
rename = "modulus_hex",
|
||||
deserialize_with = "deserialize_hex_as_biguint"
|
||||
)]
|
||||
pub modulus: BigUint,
|
||||
#[serde(
|
||||
rename = "public_exponent_hex",
|
||||
deserialize_with = "deserialize_hex_as_biguint"
|
||||
)]
|
||||
pub public_exponent: BigUint,
|
||||
pub public_key_x509: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
65
src/main.rs
65
src/main.rs
@ -1,16 +1,8 @@
|
||||
use crate::cursed::{slice_base64, slice_bool, slice_int};
|
||||
use crate::keys::IssuerKeyStore;
|
||||
use crate::payload::{CapitalismDateTime, Rsp6Ticket};
|
||||
use crate::payload::Rsp6Ticket;
|
||||
use anyhow::anyhow;
|
||||
use bitvec::field::BitField;
|
||||
use bitvec::order::Msb0;
|
||||
use bitvec::view::BitView;
|
||||
use rsa::BigUint;
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
use time::PrimitiveDateTime;
|
||||
use num_bigint::BigUint;
|
||||
|
||||
mod cursed;
|
||||
mod keys;
|
||||
mod payload;
|
||||
|
||||
@ -23,27 +15,6 @@ fn base26_decode(input: &str) -> BigUint {
|
||||
BigUint::from_bytes_le(&out.to_bytes_be())
|
||||
}
|
||||
|
||||
/*
|
||||
fn base26_decode(input: &str) -> Vec<u8> {
|
||||
let mut alphabets = input
|
||||
.chars()
|
||||
.map(|x| (u32::from(x) - u32::from('A')) as u8)
|
||||
.collect::<Vec<_>>();
|
||||
let length = (((alphabets.len() * 500) + 851) - 1) / 851;
|
||||
let mut ret = vec![0u8; length];
|
||||
for c in ret.iter_mut() {
|
||||
let mut k = 0;
|
||||
for j in (0..=alphabets.len()).rev() {
|
||||
let a = (k * 26) + alphabets[j];
|
||||
alphabets[j] = a;
|
||||
k = a;
|
||||
}
|
||||
*c = k;
|
||||
}
|
||||
ret
|
||||
}
|
||||
*/
|
||||
|
||||
fn strip_padding(tkt: &[u8]) -> Option<&[u8]> {
|
||||
if tkt.is_empty() || tkt[0] != 1 {
|
||||
return None;
|
||||
@ -63,8 +34,8 @@ fn strip_padding(tkt: &[u8]) -> Option<&[u8]> {
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let iks = IssuerKeyStore::new();
|
||||
println!("[+] Loaded {} public keys!", iks.keys.len());
|
||||
println!("[+] mmm, give me a tasty ticket on stdin please");
|
||||
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()
|
||||
@ -80,33 +51,33 @@ fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
let issuer_id = &ticket_str[13..15];
|
||||
let ticket_reference = format!("{}{}", issuer_id, &ticket_str[2..11]);
|
||||
println!("[+] RSP6 ticket, reference {}", ticket_reference);
|
||||
println!("[+] Ticket issuer: {}", issuer_id);
|
||||
eprintln!("[+] RSP6 ticket, reference {}", ticket_reference);
|
||||
eprintln!("[+] Ticket issuer: {}", issuer_id);
|
||||
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 modulus = BigUint::from_bytes_be(&key.modulus);
|
||||
let exponent = BigUint::parse_bytes(key.public_exponent_hex.as_bytes(), 16)
|
||||
.ok_or_else(|| anyhow!("failed to parse exponent in key"))?;
|
||||
let message = ticket.modpow(&exponent, &modulus).to_bytes_be();
|
||||
let message = ticket
|
||||
.modpow(&key.public_exponent, &key.modulus)
|
||||
.to_bytes_be();
|
||||
if let Some(unpadded) = strip_padding(&message) {
|
||||
println!("done! {:?}", unpadded);
|
||||
let ticket_ref_inner = cursed::slice_base64(unpadded, 8, 9);
|
||||
let extra_bit = cursed::slice_base64(unpadded, 62, 1);
|
||||
eprintln!("[+] decrypt done!");
|
||||
let ticket_ref_inner = Rsp6Ticket::base64(unpadded, 8, 62);
|
||||
let extra_bit = Rsp6Ticket::base64(unpadded, 62, 68);
|
||||
let inner_data = format!("{}{}", ticket_ref_inner, extra_bit);
|
||||
let outer_data = &ticket_str[2..12];
|
||||
if inner_data != outer_data {
|
||||
eprintln!("mismatch: {} vs {}", inner_data, outer_data);
|
||||
// return Err(anyhow!("failed to validate inner and outer data"));
|
||||
eprintln!("[-] checksum mismatch: {} vs {}", inner_data, outer_data);
|
||||
} else {
|
||||
eprintln!("[+] checksum ok");
|
||||
}
|
||||
println!("[+] ticket validated!");
|
||||
println!("[+] ticket: {:#?}", Rsp6Ticket::decode(unpadded));
|
||||
let ticket = Rsp6Ticket::decode(unpadded)?;
|
||||
serde_json::to_writer_pretty(std::io::stdout(), &ticket)?;
|
||||
return Ok(());
|
||||
} else {
|
||||
println!("failed decrypt: {:?}", message);
|
||||
eprintln!("[-] failed decrypt: {:?}", message);
|
||||
}
|
||||
}
|
||||
Err(anyhow!("no valid decryptions"))
|
||||
|
@ -1,15 +1,15 @@
|
||||
//! Decoding the actual inner decrypted payload bit.
|
||||
|
||||
use crate::{slice_base64, slice_bool};
|
||||
use anyhow::anyhow;
|
||||
use bitvec::field::BitField;
|
||||
use bitvec::order::Msb0;
|
||||
use bitvec::slice::BitSlice;
|
||||
use bitvec::view::BitView;
|
||||
use serde::Serialize;
|
||||
use time::macros::datetime;
|
||||
use time::{Date, Duration, PrimitiveDateTime, Time};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Serialize)]
|
||||
pub enum CouponType {
|
||||
Single = 0,
|
||||
Season = 1,
|
||||
@ -17,7 +17,7 @@ pub enum CouponType {
|
||||
ReturnInbound = 3,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct TicketPurchaseDetails {
|
||||
pub purchase_time: PrimitiveDateTime,
|
||||
pub price_pence: u32,
|
||||
@ -25,7 +25,7 @@ pub struct TicketPurchaseDetails {
|
||||
pub days_of_validity: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct Reservation {
|
||||
pub retail_service_id: String,
|
||||
pub coach: char,
|
||||
@ -54,7 +54,7 @@ impl Reservation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct Rsp6Ticket {
|
||||
pub manually_inspect: bool,
|
||||
pub ticket_reference: String,
|
||||
@ -71,7 +71,8 @@ pub struct Rsp6Ticket {
|
||||
pub discount_code: u16,
|
||||
pub route_code: u32,
|
||||
pub start_date: Date,
|
||||
pub depart_time: Option<Time>,
|
||||
pub depart_time_flag: u8,
|
||||
pub depart_time: Time,
|
||||
pub passenger_id: Option<String>,
|
||||
pub passenger_name: Option<String>,
|
||||
pub passenger_gender: Option<u8>,
|
||||
@ -84,10 +85,13 @@ pub struct Rsp6Ticket {
|
||||
}
|
||||
|
||||
impl Rsp6Ticket {
|
||||
fn base64(tkt: &[u8], from: usize, to: usize) -> String {
|
||||
pub fn base64(tkt: &[u8], from: usize, to: usize) -> String {
|
||||
let chars = (to - from) / 6;
|
||||
assert_eq!(chars * 6, to - from);
|
||||
slice_base64(tkt, from, chars)
|
||||
tkt.view_bits::<Msb0>()[from..to]
|
||||
.chunks(6)
|
||||
.map(|x| char::from(x.load_be::<u8>() + 32))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn decode_limited_duration(dur: u8) -> Option<Duration> {
|
||||
@ -131,19 +135,19 @@ impl Rsp6Ticket {
|
||||
pub fn decode(tkt: &[u8]) -> anyhow::Result<Self> {
|
||||
let bit_tkt = tkt.view_bits::<Msb0>();
|
||||
|
||||
let manually_inspect = slice_bool(tkt, 0);
|
||||
let manually_inspect = bit_tkt[0];
|
||||
let ticket_reference = Self::base64(tkt, 8, 62);
|
||||
let checksum = Self::base64(tkt, 62, 68).chars().next().unwrap();
|
||||
let version: u8 = bit_tkt[68..72].load_be();
|
||||
|
||||
let standard_class = slice_bool(tkt, 72);
|
||||
let standard_class = bit_tkt[72];
|
||||
let lennon_ticket_type = Self::base64(tkt, 73, 91);
|
||||
let fare = Self::base64(tkt, 91, 109);
|
||||
let origin_nlc = Self::base64(tkt, 109, 133);
|
||||
let destination_nlc = Self::base64(tkt, 133, 157);
|
||||
let retailer_id = Self::base64(tkt, 157, 181);
|
||||
|
||||
let is_child = slice_bool(tkt, 181);
|
||||
let is_child = bit_tkt[181];
|
||||
let coupon_type = match bit_tkt[182..184].load_be::<u8>() {
|
||||
0 => CouponType::Single,
|
||||
1 => CouponType::Season,
|
||||
@ -158,8 +162,8 @@ impl Rsp6Ticket {
|
||||
let start_time_secs: u32 = bit_tkt[225..236].load_be();
|
||||
let start_time: PrimitiveDateTime =
|
||||
CapitalismDateTime::new(start_time_days, start_time_secs).into();
|
||||
let depart_time_flag: u8 = bit_tkt[236..238].load_be(); // FIXME
|
||||
let depart_time = Some(start_time.time());
|
||||
let depart_time_flag: u8 = bit_tkt[236..238].load_be();
|
||||
let depart_time = start_time.time();
|
||||
let start_date = start_time.date();
|
||||
|
||||
let passenger_id = Self::decode_passenger_id(bit_tkt[238..255].load_be());
|
||||
@ -170,10 +174,10 @@ impl Rsp6Ticket {
|
||||
|
||||
let restriction_code = Self::base64(tkt, 329, 347);
|
||||
let restriction_code = (!restriction_code.trim().is_empty()).then_some(restriction_code);
|
||||
let bidirectional = slice_bool(tkt, 372);
|
||||
let bidirectional = bit_tkt[372];
|
||||
let limited_duration = Self::decode_limited_duration(bit_tkt[379..383].load_be());
|
||||
|
||||
let is_full_ticket = slice_bool(tkt, 384);
|
||||
let is_full_ticket = bit_tkt[384];
|
||||
|
||||
let purchase_details = if is_full_ticket {
|
||||
let purchase_time_days: u32 = bit_tkt[390..404].load_be();
|
||||
@ -225,6 +229,7 @@ impl Rsp6Ticket {
|
||||
route_code,
|
||||
start_date,
|
||||
depart_time,
|
||||
depart_time_flag,
|
||||
passenger_id,
|
||||
passenger_name,
|
||||
passenger_gender,
|
||||
|
Loading…
x
Reference in New Issue
Block a user