Impelement generation for bink1998
This commit is contained in:
parent
e9e7b1506f
commit
bd51609f05
3 changed files with 119 additions and 11 deletions
|
@ -1,12 +1,17 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use bitreader::BitReader;
|
use bitreader::BitReader;
|
||||||
use openssl::{
|
use openssl::{
|
||||||
bn::{BigNum, BigNumContext},
|
bn::{BigNum, BigNumContext, MsbOption},
|
||||||
ec::{EcGroup, EcPoint},
|
ec::{EcGroup, EcPoint},
|
||||||
sha::sha1,
|
sha::sha1,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{key::base24_decode, FIELD_BYTES};
|
use crate::{
|
||||||
|
key::{base24_decode, base24_encode},
|
||||||
|
FIELD_BITS, FIELD_BYTES,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SHA_MSG_LENGTH_XP: usize = 4 + 2 * FIELD_BYTES;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct ProductKey {
|
struct ProductKey {
|
||||||
|
@ -46,11 +51,11 @@ pub fn verify(
|
||||||
|
|
||||||
p.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
p.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
||||||
|
|
||||||
let mut msg_buffer: [u8; 100] = [0; 100];
|
let mut msg_buffer: [u8; SHA_MSG_LENGTH_XP] = [0; SHA_MSG_LENGTH_XP];
|
||||||
|
|
||||||
let mut x_bin = x.to_vec();
|
let mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
x_bin.reverse();
|
x_bin.reverse();
|
||||||
let mut y_bin = y.to_vec();
|
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
y_bin.reverse();
|
y_bin.reverse();
|
||||||
|
|
||||||
msg_buffer[0..4].copy_from_slice(&p_data.to_le_bytes());
|
msg_buffer[0..4].copy_from_slice(&p_data.to_le_bytes());
|
||||||
|
@ -59,7 +64,8 @@ pub fn verify(
|
||||||
|
|
||||||
let msg_digest = sha1(&msg_buffer);
|
let msg_digest = sha1(&msg_buffer);
|
||||||
|
|
||||||
let hash: u32 = u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & ((1 << 28) - 1);
|
let hash: u32 =
|
||||||
|
u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & bitmask(28) as u32;
|
||||||
|
|
||||||
Ok(hash == product_key.hash)
|
Ok(hash == product_key.hash)
|
||||||
}
|
}
|
||||||
|
@ -71,8 +77,65 @@ pub fn generate(
|
||||||
private_key: &BigNum,
|
private_key: &BigNum,
|
||||||
p_serial: u32,
|
p_serial: u32,
|
||||||
p_upgrade: bool,
|
p_upgrade: bool,
|
||||||
) -> String {
|
) -> Result<String> {
|
||||||
todo!()
|
let mut num_context = BigNumContext::new().unwrap();
|
||||||
|
|
||||||
|
let mut c = BigNum::new()?;
|
||||||
|
let mut s = BigNum::new()?;
|
||||||
|
let mut s_2 = BigNum::new()?;
|
||||||
|
let mut x = BigNum::new()?;
|
||||||
|
let mut y = BigNum::new()?;
|
||||||
|
|
||||||
|
let p_data = p_serial << 1 | p_upgrade as u32;
|
||||||
|
|
||||||
|
let p_raw = loop {
|
||||||
|
let mut r = EcPoint::new(e_curve)?;
|
||||||
|
|
||||||
|
// Generate a random number c consisting of 384 bits without any constraints.
|
||||||
|
c.rand(FIELD_BITS, MsbOption::MAYBE_ZERO, true)?;
|
||||||
|
|
||||||
|
// Pick a random derivative of the base point on the elliptic curve.
|
||||||
|
// R = cG;
|
||||||
|
r.mul(e_curve, base_point, &c, &num_context)?;
|
||||||
|
|
||||||
|
// Acquire its coordinates.
|
||||||
|
// x = R.x; y = R.y;
|
||||||
|
r.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
||||||
|
|
||||||
|
let mut msg_buffer: [u8; SHA_MSG_LENGTH_XP] = [0; SHA_MSG_LENGTH_XP];
|
||||||
|
|
||||||
|
let mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
|
x_bin.reverse();
|
||||||
|
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
|
y_bin.reverse();
|
||||||
|
|
||||||
|
msg_buffer[0..4].copy_from_slice(&p_data.to_le_bytes());
|
||||||
|
msg_buffer[4..4 + FIELD_BYTES].copy_from_slice(&x_bin);
|
||||||
|
msg_buffer[4 + FIELD_BYTES..4 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
||||||
|
|
||||||
|
let msg_digest = sha1(&msg_buffer);
|
||||||
|
|
||||||
|
let p_hash: u32 =
|
||||||
|
u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & bitmask(28) as u32;
|
||||||
|
|
||||||
|
s_2.copy_from_slice(&private_key.to_vec())?;
|
||||||
|
s_2.mul_word(p_hash)?;
|
||||||
|
|
||||||
|
s.mod_add(&s_2, &c, gen_order, &mut num_context)?;
|
||||||
|
|
||||||
|
let p_signature = u64::from_be_bytes(s.to_vec_padded(8)?.try_into().unwrap());
|
||||||
|
|
||||||
|
if p_signature <= bitmask(55) {
|
||||||
|
break pack(ProductKey {
|
||||||
|
upgrade: p_upgrade,
|
||||||
|
serial: p_serial,
|
||||||
|
hash: p_hash,
|
||||||
|
signature: p_signature,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(base24_encode(&p_raw))
|
||||||
}
|
}
|
||||||
|
|
||||||
const HASH_LENGTH_BITS: u8 = 28;
|
const HASH_LENGTH_BITS: u8 = 28;
|
||||||
|
@ -113,6 +176,10 @@ fn pack(p_key: ProductKey) -> Vec<u8> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bitmask(n: u64) -> u64 {
|
||||||
|
(1 << n) - 1
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{fs::File, io::BufReader};
|
use std::{fs::File, io::BufReader};
|
||||||
|
@ -146,6 +213,13 @@ mod tests {
|
||||||
let (e_curve, gen_point, pub_point) = initialize_elliptic_curve(p, a, b, gx, gy, kx, ky);
|
let (e_curve, gen_point, pub_point) = initialize_elliptic_curve(p, a, b, gx, gy, kx, ky);
|
||||||
|
|
||||||
assert!(super::verify(&e_curve, &gen_point, &pub_point, product_key).unwrap());
|
assert!(super::verify(&e_curve, &gen_point, &pub_point, product_key).unwrap());
|
||||||
|
assert!(!super::verify(
|
||||||
|
&e_curve,
|
||||||
|
&gen_point,
|
||||||
|
&pub_point,
|
||||||
|
"11111-R6BG2-39J83-RYKHF-W47TT"
|
||||||
|
)
|
||||||
|
.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
39
src/cli.rs
39
src/cli.rs
|
@ -3,12 +3,12 @@ use std::{fs::File, io::BufReader, path::Path};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use openssl::{
|
use openssl::{
|
||||||
bn::BigNum,
|
bn::{BigNum, MsbOption},
|
||||||
ec::{EcGroup, EcPoint},
|
ec::{EcGroup, EcPoint},
|
||||||
};
|
};
|
||||||
use serde_json::from_reader;
|
use serde_json::from_reader;
|
||||||
|
|
||||||
use crate::crypto::initialize_elliptic_curve;
|
use crate::{bink1998, crypto::initialize_elliptic_curve};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
|
@ -52,7 +52,7 @@ pub struct Options {
|
||||||
|
|
||||||
/// Specify which Channel Identifier to use
|
/// Specify which Channel Identifier to use
|
||||||
#[arg(short = 'c', long = "channel", default_value = "640")]
|
#[arg(short = 'c', long = "channel", default_value = "640")]
|
||||||
channel_id: i32,
|
channel_id: u32,
|
||||||
|
|
||||||
#[clap(skip)]
|
#[clap(skip)]
|
||||||
application_mode: Mode,
|
application_mode: Mode,
|
||||||
|
@ -190,6 +190,39 @@ impl Cli {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bink1998(&mut self) -> Result<()> {
|
fn bink1998(&mut self) -> Result<()> {
|
||||||
|
let mut n_raw = self.options.channel_id * 1_000_000; // <- change
|
||||||
|
|
||||||
|
let mut bn_rand = BigNum::new()?;
|
||||||
|
bn_rand.rand(19, MsbOption::MAYBE_ZERO, false)?;
|
||||||
|
|
||||||
|
let o_raw: u32 = u32::from_be_bytes(bn_rand.to_vec_padded(4)?.try_into().unwrap());
|
||||||
|
n_raw += o_raw % 999999;
|
||||||
|
|
||||||
|
if self.options.verbose {
|
||||||
|
println!("> PID: {n_raw:09}");
|
||||||
|
}
|
||||||
|
|
||||||
|
let private_key = &self.gen_order - &self.private_key;
|
||||||
|
|
||||||
|
let upgrade = false;
|
||||||
|
|
||||||
|
for _ in 0..self.options.num_keys {
|
||||||
|
let p_key = bink1998::generate(
|
||||||
|
&self.e_curve,
|
||||||
|
&self.gen_point,
|
||||||
|
&self.gen_order,
|
||||||
|
&private_key,
|
||||||
|
n_raw,
|
||||||
|
upgrade,
|
||||||
|
)?;
|
||||||
|
Cli::print_key(&p_key);
|
||||||
|
|
||||||
|
if bink1998::verify(&self.e_curve, &self.gen_point, &self.pub_point, &p_key)? {
|
||||||
|
self.count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Success count: {}/{}", self.count, self.options.num_keys);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ mod cli;
|
||||||
mod crypto;
|
mod crypto;
|
||||||
mod key;
|
mod key;
|
||||||
|
|
||||||
|
pub const FIELD_BITS: i32 = 384;
|
||||||
pub const FIELD_BYTES: usize = 48;
|
pub const FIELD_BYTES: usize = 48;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
|
Loading…
Add table
Reference in a new issue