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 bitreader::BitReader;
|
||||
use openssl::{
|
||||
bn::{BigNum, BigNumContext},
|
||||
bn::{BigNum, BigNumContext, MsbOption},
|
||||
ec::{EcGroup, EcPoint},
|
||||
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)]
|
||||
struct ProductKey {
|
||||
|
@ -46,11 +51,11 @@ pub fn verify(
|
|||
|
||||
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();
|
||||
let mut y_bin = y.to_vec();
|
||||
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());
|
||||
|
@ -59,7 +64,8 @@ pub fn verify(
|
|||
|
||||
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)
|
||||
}
|
||||
|
@ -71,8 +77,65 @@ pub fn generate(
|
|||
private_key: &BigNum,
|
||||
p_serial: u32,
|
||||
p_upgrade: bool,
|
||||
) -> String {
|
||||
todo!()
|
||||
) -> Result<String> {
|
||||
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;
|
||||
|
@ -113,6 +176,10 @@ fn pack(p_key: ProductKey) -> Vec<u8> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn bitmask(n: u64) -> u64 {
|
||||
(1 << n) - 1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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);
|
||||
|
||||
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]
|
||||
|
|
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 clap::Parser;
|
||||
use openssl::{
|
||||
bn::BigNum,
|
||||
bn::{BigNum, MsbOption},
|
||||
ec::{EcGroup, EcPoint},
|
||||
};
|
||||
use serde_json::from_reader;
|
||||
|
||||
use crate::crypto::initialize_elliptic_curve;
|
||||
use crate::{bink1998, crypto::initialize_elliptic_curve};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Mode {
|
||||
|
@ -52,7 +52,7 @@ pub struct Options {
|
|||
|
||||
/// Specify which Channel Identifier to use
|
||||
#[arg(short = 'c', long = "channel", default_value = "640")]
|
||||
channel_id: i32,
|
||||
channel_id: u32,
|
||||
|
||||
#[clap(skip)]
|
||||
application_mode: Mode,
|
||||
|
@ -190,6 +190,39 @@ impl Cli {
|
|||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ mod cli;
|
|||
mod crypto;
|
||||
mod key;
|
||||
|
||||
pub const FIELD_BITS: i32 = 384;
|
||||
pub const FIELD_BYTES: usize = 48;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
|
Loading…
Add table
Reference in a new issue