Compare commits

...

9 commits

Author SHA1 Message Date
d59d78664a Make confirmation_id args consistent 2023-06-24 17:43:17 -04:00
c3102882a9 Use log crate to filter verbose messages 2023-06-24 17:42:09 -04:00
860c0ebcac Fix path to keys.json in tests 2023-06-24 17:23:49 -04:00
89bf419067 Use official rust-openssl repo
The change I need is merged, but not released
2023-06-24 17:14:33 -04:00
fe08910831 Restructure into a workspace 2023-06-24 17:12:11 -04:00
589f0bb52b Clean up verbose logging 2023-06-24 16:54:58 -04:00
9029d35a6b Small improvements to CLI 2023-06-24 16:31:23 -04:00
2bed0f88d1 Clean up xpkey 2023-06-24 16:30:13 -04:00
8510eb367d Move clap types to their own module 2023-06-24 16:04:57 -04:00
18 changed files with 923 additions and 374 deletions

148
Cargo.lock generated
View file

@ -19,15 +19,15 @@ dependencies = [
[[package]]
name = "anstyle"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
@ -38,7 +38,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -48,7 +48,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -86,9 +86,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.3.4"
version = "4.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed"
checksum = "d9394150f5b4273a1763355bd1c2ec54cc5a2593f790587bcd6b2c947cfa9211"
dependencies = [
"clap_builder",
"clap_derive",
@ -97,9 +97,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.3.4"
version = "4.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636"
checksum = "9a78fbdd3cc2914ddf37ba444114bc7765bbdcb55ec9cbe6fa054f0137400717"
dependencies = [
"anstream",
"anstyle",
@ -140,7 +140,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -188,7 +188,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -200,7 +200,7 @@ dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -221,6 +221,12 @@ version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "log"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "once_cell"
version = "1.18.0"
@ -230,7 +236,7 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl"
version = "0.10.55"
source = "git+https://github.com/anpage/rust-openssl.git#a50639888f80f0a935ec621c328d761428aff32a"
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
dependencies = [
"bitflags",
"cfg-if",
@ -244,7 +250,7 @@ dependencies = [
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "git+https://github.com/anpage/rust-openssl.git#a50639888f80f0a935ec621c328d761428aff32a"
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
dependencies = [
"proc-macro2",
"quote",
@ -254,7 +260,7 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.90"
source = "git+https://github.com/anpage/rust-openssl.git#a50639888f80f0a935ec621c328d761428aff32a"
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
dependencies = [
"cc",
"libc",
@ -270,9 +276,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "proc-macro2"
version = "1.0.60"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
checksum = "363a6f739a0c0addeaf6ed75150b95743aa18643a3c6f40409ed7b6db3a6911f"
dependencies = [
"unicode-ident",
]
@ -297,7 +303,7 @@ dependencies = [
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -328,15 +334,25 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.97"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a"
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "simple_logger"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2230cd5c29b815c9b699fb610b49a5ed65588f3509d9f0108be3a885da629333"
dependencies = [
"log",
"windows-sys 0.42.0",
]
[[package]]
name = "strsim"
version = "0.10.0"
@ -345,9 +361,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.18"
version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
checksum = "1182caafaab7018eaea9b404afa8184c0baf42a04d5e10ae4f4843c2029c8aab"
dependencies = [
"proc-macro2",
"quote",
@ -380,9 +396,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"bitreader",
"clap",
"openssl",
"serde",
"serde_json",
"thiserror",
]
@ -405,6 +419,21 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@ -420,53 +449,108 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "xpkey"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"log",
"serde",
"serde_json",
"simple_logger",
"umskt",
]

View file

@ -1,23 +1,6 @@
[package]
name = "umskt"
version = "0.1.0"
edition = "2021"
crate-type = ["lib"]
[workspace]
[[bin]]
name = "xpkey"
[profile.release]
strip = true
opt-level = "z"
lto = true
codegen-units = 1
[dependencies]
anyhow = "1.0.71"
bitreader = "0.3.7"
clap = { version = "4.3.4", features = ["derive"] }
openssl = { git = "https://github.com/anpage/rust-openssl.git" }
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0.40"
members = [
"umskt",
"xpkey",
]

View file

@ -1,36 +0,0 @@
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Keys {
#[serde(rename = "Products")]
pub products: HashMap<String, Product>,
#[serde(rename = "BINK")]
pub bink: HashMap<String, Bink>,
}
#[derive(Serialize, Deserialize)]
pub struct Product {
#[serde(rename = "BINK")]
pub bink: Vec<String>,
}
#[derive(Serialize, Deserialize)]
pub struct Bink {
pub p: String,
pub a: String,
pub b: String,
pub g: Point,
#[serde(rename = "pub")]
pub public: Point,
pub n: String,
#[serde(rename = "priv")]
pub private: String,
}
#[derive(Serialize, Deserialize)]
pub struct Point {
pub x: String,
pub y: String,
}

View file

@ -1,280 +0,0 @@
mod keys;
use std::{fs::File, io::BufReader, path::Path};
use anyhow::{anyhow, Result};
use clap::{Args, Parser, Subcommand};
use keys::{Bink, Keys};
use serde_json::{from_reader, from_str};
use umskt::{
bink1998, bink2002, confid,
crypto::{EllipticCurve, PrivateKey},
};
#[derive(Parser, Debug)]
#[command(author, about, version, long_about = None)]
struct Cli {
/// Enable verbose output
#[arg(short, long)]
verbose: bool,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Clone, Debug)]
enum Commands {
/// Show which products/binks can be loaded
List(ListArgs),
/// Generate new product keys
Generate(GenerateArgs),
/// Validate a product key
Validate(ValidateArgs),
/// Generate a phone activation Confirmation ID from an Installation ID
#[command(name = "confid")]
ConfirmationId(ConfirmationIdArgs),
}
#[derive(Args, Clone, Debug)]
struct ListArgs {
/// Specify which keys file to load
#[arg(short = 'f', long = "file")]
keys_path: Option<String>,
}
#[derive(Args, Clone, Debug)]
struct GenerateArgs {
/// Specify which BINK identifier to load
#[arg(short, long, default_value = "2E")]
binkid: String,
/// Specify which Channel Identifier to use
#[arg(short = 'c', long = "channel", default_value = "640")]
channel_id: u32,
/// Number of keys to generate
#[arg(short = 'n', long = "number", default_value = "1")]
num_keys: u64,
/// Specify which keys file to load
#[arg(short = 'f', long = "file")]
keys_path: Option<String>,
}
#[derive(Args, Clone, Debug)]
struct ValidateArgs {
/// Specify which BINK identifier to load
#[arg(short, long, default_value = "2E")]
binkid: String,
/// Specify which keys file to load
#[arg(short = 'f', long = "file")]
keys_path: Option<String>,
/// Product key to validate signature
key_to_check: String,
}
#[derive(Args, Clone, Debug)]
struct ConfirmationIdArgs {
/// Installation ID used to generate confirmation ID
instid: String,
}
fn main() -> Result<()> {
let args = Cli::parse();
match &args.command {
Commands::List(list_args) => {
let keys = load_keys(list_args.keys_path.as_ref(), args.verbose)?;
for (key, value) in keys.products.iter() {
println!("{}: {:?}", key, value.bink);
}
println!("\n\n** Please note: any BINK ID other than 2E is considered experimental at this time **\n");
}
Commands::Generate(generate_args) => {
if generate_args.channel_id > 999 {
return Err(anyhow!("Channel ID must be 3 digits or fewer"));
}
let keys = load_keys(generate_args.keys_path.as_ref(), args.verbose)?;
generate(
&keys,
&generate_args.binkid,
generate_args.channel_id,
generate_args.num_keys,
args.verbose,
)?;
}
Commands::Validate(validate_args) => {
let keys = load_keys(validate_args.keys_path.as_ref(), args.verbose)?;
validate(
&keys,
&validate_args.binkid,
&validate_args.key_to_check,
args.verbose,
)?;
}
Commands::ConfirmationId(confirmation_id_args) => {
confirmation_id(&confirmation_id_args.instid)?;
}
}
Ok(())
}
fn load_keys<P: AsRef<Path> + std::fmt::Display>(path: Option<P>, verbose: bool) -> Result<Keys> {
let keys = {
if let Some(path) = path {
if verbose {
println!("Loading keys file {}", path);
}
let file = File::open(&path)?;
let reader = BufReader::new(file);
let keys: Keys = from_reader(reader)?;
if verbose {
println!("Loaded keys from {} successfully", path);
}
keys
} else {
from_str(std::include_str!("../../../keys.json"))?
}
};
Ok(keys)
}
fn generate(keys: &Keys, bink_id: &str, channel_id: u32, count: u64, verbose: bool) -> Result<()> {
let bink_id = bink_id.to_ascii_uppercase();
let bink = &keys.bink[&bink_id];
// We cannot produce a valid key without knowing the private key k. The reason for this is that
// we need the result of the function K(x; y) = kG(x; y).
let private_key = &bink.private;
// We can, however, validate any given key using the available public key: {p, a, b, G, K}.
// genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm.
let gen_order = &bink.n;
let curve = initialize_curve(bink, &bink_id, verbose)?;
if verbose {
println!(" n: {gen_order}");
println!(" k: {private_key}");
println!();
}
let private_key = PrivateKey::new(gen_order, private_key)?;
if u32::from_str_radix(&bink_id, 16)? < 0x40 {
bink1998_generate(&curve, &private_key, channel_id, count, verbose)?;
} else {
bink2002_generate(&curve, &private_key, channel_id, count, verbose)?;
}
Ok(())
}
fn validate(keys: &Keys, bink_id: &str, key: &str, verbose: bool) -> Result<()> {
let bink_id = bink_id.to_ascii_uppercase();
let bink = &keys.bink[&bink_id];
let curve = initialize_curve(bink, &bink_id, verbose)?;
if u32::from_str_radix(&bink_id, 16)? < 0x40 {
bink1998_validate(&curve, key, verbose)?;
} else {
bink2002_validate(&curve, key, verbose)?;
}
Ok(())
}
fn initialize_curve(bink: &Bink, bink_id: &str, verbose: bool) -> Result<EllipticCurve> {
let p = &bink.p;
let a = &bink.a;
let b = &bink.b;
let gx = &bink.g.x;
let gy = &bink.g.y;
let kx = &bink.public.x;
let ky = &bink.public.y;
if verbose {
println!("-----------------------------------------------------------");
println!(
"Loaded the following elliptic curve parameters: BINK[{}]",
bink_id
);
println!("-----------------------------------------------------------");
println!(" P: {p}");
println!(" a: {a}");
println!(" b: {b}");
println!("Gx: {gx}");
println!("Gy: {gy}");
println!("Kx: {kx}");
println!("Ky: {ky}");
}
EllipticCurve::new(p, a, b, gx, gy, kx, ky)
}
fn bink1998_generate(
curve: &EllipticCurve,
private_key: &PrivateKey,
channel_id: u32,
count: u64,
verbose: bool,
) -> Result<()> {
for _ in 0..count {
let product_key = bink1998::ProductKey::new(curve, private_key, channel_id, None, None)?;
if verbose {
println!("{:?}", product_key);
}
println!("{product_key}");
}
Ok(())
}
fn bink2002_generate(
curve: &EllipticCurve,
private_key: &PrivateKey,
channel_id: u32,
count: u64,
verbose: bool,
) -> Result<()> {
for _ in 0..count {
let product_key = bink2002::ProductKey::new(curve, private_key, channel_id, None, None)?;
if verbose {
println!("{:?}", product_key);
}
println!("{product_key}");
}
Ok(())
}
fn bink1998_validate(curve: &EllipticCurve, key: &str, verbose: bool) -> Result<()> {
let product_key = bink1998::ProductKey::from_key(curve, key)?;
if verbose {
println!("{:?}", product_key);
}
println!("{product_key}");
println!("Key validated successfully!");
Ok(())
}
fn bink2002_validate(curve: &EllipticCurve, key: &str, verbose: bool) -> Result<()> {
let product_key = bink2002::ProductKey::from_key(curve, key)?;
if verbose {
println!("{:?}", product_key);
}
println!("{product_key}");
println!("Key validated successfully!");
Ok(())
}
fn confirmation_id(installation_id: &str) -> Result<()> {
let confirmation_id = confid::generate(installation_id)?;
println!("Confirmation ID: {confirmation_id}");
Ok(())
}

472
umskt/Cargo.lock generated Normal file
View file

@ -0,0 +1,472 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
[[package]]
name = "anstyle-parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitreader"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f10043e4864d975e7f197f993ec4018636ad93946724b2571c4474d51845869b"
dependencies = [
"cfg-if",
]
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636"
dependencies = [
"anstream",
"anstyle",
"bitflags",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "errno"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]]
name = "is-terminal"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "itoa"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "libc"
version = "0.2.146"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl"
version = "0.10.55"
source = "git+https://github.com/anpage/rust-openssl.git#a50639888f80f0a935ec621c328d761428aff32a"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "git+https://github.com/anpage/rust-openssl.git#a50639888f80f0a935ec621c328d761428aff32a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-sys"
version = "0.9.90"
source = "git+https://github.com/anpage/rust-openssl.git#a50639888f80f0a935ec621c328d761428aff32a"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "pkg-config"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "proc-macro2"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustix"
version = "0.37.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "serde"
version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "umskt"
version = "0.1.0"
dependencies = [
"anyhow",
"bitreader",
"clap",
"openssl",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "unicode-ident"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"

13
umskt/Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "umskt"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.71"
bitreader = "0.3.7"
openssl = { git = "https://github.com/sfackler/rust-openssl" }
thiserror = "1.0.40"
[dev-dependencies]
serde_json = "1.0"

View file

@ -274,7 +274,7 @@ mod tests {
let bink_id = "2E";
// Load keys.json
let path = "keys.json";
let path = "../keys.json";
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
let keys: serde_json::Value = from_reader(reader).unwrap();

View file

@ -344,7 +344,7 @@ mod tests {
let bink_id = "54";
// Load keys.json
let path = "keys.json";
let path = "../keys.json";
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
let keys: serde_json::Value = from_reader(reader).unwrap();

View file

@ -59,9 +59,7 @@ mod tests {
fn test_base24() {
let input = "JTW3TJ7PFJ7V9CCMX84V9PFT8";
let unbase24 = super::base24_decode(input).unwrap();
println!("{:?}", unbase24);
let base24 = super::base24_encode(&unbase24).unwrap();
println!("{}", base24);
assert_eq!(input, base24);
}
}

20
xpkey/Cargo.toml Normal file
View file

@ -0,0 +1,20 @@
[package]
name = "xpkey"
version = "0.1.0"
edition = "2021"
[profile.release]
strip = true
opt-level = "z"
lto = true
codegen-units = 1
[dependencies]
umskt = { path = "../umskt" }
anyhow = "1.0.71"
clap = { version = "4.3.4", features = ["derive"] }
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0"
log = "0.4.19"
simple_logger = { version = "4.2.0", default-features = false }

75
xpkey/src/cli.rs Normal file
View file

@ -0,0 +1,75 @@
use clap::{Args, Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(author, about, version, long_about = None)]
pub struct Cli {
/// Enable verbose output
#[arg(short, long)]
pub verbose: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand, Clone, Debug)]
pub enum Commands {
/// Show which products/binks can be loaded
#[command(visible_alias = "l")]
List(ListArgs),
/// Generate new product keys
#[command(visible_alias = "g")]
Generate(GenerateArgs),
/// Validate a product key
#[command(visible_alias = "v")]
Validate(ValidateArgs),
/// Generate a phone activation Confirmation ID from an Installation ID
#[command(name = "confid", visible_alias = "c")]
ConfirmationId(ConfirmationIdArgs),
}
#[derive(Args, Clone, Debug)]
pub struct ListArgs {
/// Optional path to load a keys.json file
#[arg(short, long = "keys")]
pub keys_path: Option<String>,
}
#[derive(Args, Clone, Debug)]
pub struct GenerateArgs {
/// Which BINK identifier to use
#[arg(short, long = "bink", default_value = "2E")]
pub bink_id: String,
/// Channel Identifier to use
#[arg(short, long = "channel", default_value = "640")]
pub channel_id: u32,
/// Number of keys to generate
#[arg(short = 'n', long = "number", default_value = "1")]
pub count: u64,
/// Optional path to load a keys.json file
#[arg(short, long = "keys")]
pub keys_path: Option<String>,
}
#[derive(Args, Clone, Debug)]
pub struct ValidateArgs {
/// Which BINK identifier to use
#[arg(short, long = "bink", default_value = "2E")]
pub bink_id: String,
/// Optional path to load a keys.json file
#[arg(short, long = "keys")]
pub keys_path: Option<String>,
/// The Product key to validate, with or without hyphens
pub key_to_check: String,
}
#[derive(Args, Clone, Debug)]
pub struct ConfirmationIdArgs {
/// The Installation ID used to generate the Confirmation ID
#[arg(name = "INSTALLATION_ID")]
pub instid: String,
}

71
xpkey/src/keys.rs Normal file
View file

@ -0,0 +1,71 @@
use std::{collections::HashMap, fmt::Display, fs::File, io::BufReader, path::Path};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use serde_json::{from_reader, from_str};
pub fn load_keys<P: AsRef<Path> + std::fmt::Display>(path: Option<P>) -> Result<Keys> {
let keys = {
if let Some(path) = path {
let file = File::open(&path)?;
let reader = BufReader::new(file);
let keys: Keys = from_reader(reader)?;
log::info!("Loaded keys from {}", path);
keys
} else {
from_str(std::include_str!("../../keys.json"))?
}
};
Ok(keys)
}
#[derive(Serialize, Deserialize)]
pub struct Keys {
#[serde(rename = "Products")]
pub products: HashMap<String, Product>,
#[serde(rename = "BINK")]
pub bink: HashMap<String, Bink>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Product {
#[serde(rename = "BINK")]
pub bink: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Bink {
pub p: String,
pub a: String,
pub b: String,
pub g: Point,
#[serde(rename = "pub")]
pub public: Point,
pub n: String,
#[serde(rename = "priv")]
pub private: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Point {
pub x: String,
pub y: String,
}
impl Display for Bink {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, " P: {}", self.p)?;
writeln!(f, " a: {}", self.a)?;
writeln!(f, " b: {}", self.b)?;
writeln!(f, "Gx: {}", self.g.x)?;
writeln!(f, "Gy: {}", self.g.y)?;
writeln!(f, "Kx: {}", self.public.x)?;
writeln!(f, "Ky: {}", self.public.y)?;
writeln!(f, " n: {}", self.n)?;
writeln!(f, " k: {}", self.private)?;
Ok(())
}
}

149
xpkey/src/main.rs Normal file
View file

@ -0,0 +1,149 @@
mod cli;
mod keys;
use anyhow::{bail, Result};
use clap::Parser;
use keys::Bink;
use umskt::{
bink1998, bink2002, confid,
crypto::{EllipticCurve, PrivateKey},
};
use crate::{cli::*, keys::load_keys};
fn main() -> Result<()> {
let args = Cli::parse();
if args.verbose {
simple_logger::init_with_level(log::Level::Info)?;
} else {
simple_logger::init_with_level(log::Level::Warn)?;
}
match &args.command {
Commands::List(args) => list(args),
Commands::Generate(args) => generate(args),
Commands::Validate(args) => validate(args),
Commands::ConfirmationId(args) => confirmation_id(args),
}
}
fn list(args: &ListArgs) -> Result<()> {
let keys = load_keys(args.keys_path.as_ref())?;
for (key, value) in keys.products.iter() {
println!("{}: {:?}", key, value.bink);
}
println!("\n\n** Please note: any BINK ID other than 2E is considered experimental at this time **\n");
Ok(())
}
fn generate(args: &GenerateArgs) -> Result<()> {
if args.channel_id > 999 {
bail!("Channel ID must be 3 digits or fewer");
}
let keys = load_keys(args.keys_path.as_ref())?;
let bink_id = args.bink_id.to_ascii_uppercase();
let bink = &keys.bink[&bink_id];
// gen_order is the order of the generator G, a value we have to reverse -> Schoof's Algorithm.
let gen_order = &bink.n;
// We cannot produce a valid key without knowing the private key k. The reason for this is that
// we need the result of the function K(x; y) = kG(x; y).
let private_key = &bink.private;
let curve = initialize_curve(bink, &bink_id)?;
let private_key = PrivateKey::new(gen_order, private_key)?;
if u32::from_str_radix(&bink_id, 16)? < 0x40 {
bink1998_generate(&curve, &private_key, args.channel_id, args.count)?;
} else {
bink2002_generate(&curve, &private_key, args.channel_id, args.count)?;
}
Ok(())
}
fn validate(args: &ValidateArgs) -> Result<()> {
// We can validate any given key using the available public key: {p, a, b, G, K}.
// No private key or gen_order is required.
let keys = load_keys(args.keys_path.as_ref())?;
let bink_id = args.bink_id.to_ascii_uppercase();
let bink = &keys.bink[&bink_id];
let curve = initialize_curve(bink, &bink_id)?;
if u32::from_str_radix(&bink_id, 16)? < 0x40 {
bink1998_validate(&curve, &args.key_to_check)?;
} else {
bink2002_validate(&curve, &args.key_to_check)?;
}
Ok(())
}
fn initialize_curve(bink: &Bink, bink_id: &str) -> Result<EllipticCurve> {
let p = &bink.p;
let a = &bink.a;
let b = &bink.b;
let gx = &bink.g.x;
let gy = &bink.g.y;
let kx = &bink.public.x;
let ky = &bink.public.y;
log::info!("Elliptic curve parameters for BINK ID {bink_id}:\n{bink}");
EllipticCurve::new(p, a, b, gx, gy, kx, ky)
}
fn bink1998_generate(
curve: &EllipticCurve,
private_key: &PrivateKey,
channel_id: u32,
count: u64,
) -> Result<()> {
for _ in 0..count {
let product_key = bink1998::ProductKey::new(curve, private_key, channel_id, None, None)?;
log::info!("{:?}", product_key);
println!("{product_key}");
}
Ok(())
}
fn bink2002_generate(
curve: &EllipticCurve,
private_key: &PrivateKey,
channel_id: u32,
count: u64,
) -> Result<()> {
for _ in 0..count {
let product_key = bink2002::ProductKey::new(curve, private_key, channel_id, None, None)?;
log::info!("{:?}", product_key);
println!("{product_key}");
}
Ok(())
}
fn bink1998_validate(curve: &EllipticCurve, key: &str) -> Result<()> {
let product_key = bink1998::ProductKey::from_key(curve, key)?;
log::info!("{:?}", product_key);
println!("{product_key}");
println!("Key validated successfully!");
Ok(())
}
fn bink2002_validate(curve: &EllipticCurve, key: &str) -> Result<()> {
let product_key = bink2002::ProductKey::from_key(curve, key)?;
log::info!("{:?}", product_key);
println!("{product_key}");
println!("Key validated successfully!");
Ok(())
}
fn confirmation_id(args: &ConfirmationIdArgs) -> Result<()> {
let confirmation_id = confid::generate(&args.instid)?;
println!("Confirmation ID: {confirmation_id}");
Ok(())
}