Compare commits
No commits in common. "b9067599d409c569990efa97a5dfb6bd0bdd27ca" and "8dc063e4e5ab551a6e4304dd610da48a31175558" have entirely different histories.
b9067599d4
...
8dc063e4e5
11 changed files with 236 additions and 630 deletions
270
Cargo.lock
generated
270
Cargo.lock
generated
|
@ -57,18 +57,6 @@ version = "1.0.71"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base16ct"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -84,15 +72,6 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
|
@ -153,63 +132,6 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[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 = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"crypto-bigint",
|
||||
"ff",
|
||||
"generic-array",
|
||||
"group",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
|
@ -232,47 +154,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.13.0"
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"subtle",
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
@ -333,37 +227,6 @@ version = "0.4.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
|
@ -371,10 +234,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
name = "openssl"
|
||||
version = "0.10.55"
|
||||
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
|
||||
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/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.90"
|
||||
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
|
||||
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 = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
|
@ -394,36 +292,6 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[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 = "rustix"
|
||||
version = "0.37.20"
|
||||
|
@ -475,17 +343,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple_logger"
|
||||
version = "4.2.0"
|
||||
|
@ -502,12 +359,6 @@ version = "0.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.21"
|
||||
|
@ -539,25 +390,14 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "umskt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitreader",
|
||||
"elliptic-curve",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"openssl",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -574,16 +414,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
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"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
|
@ -720,9 +554,3 @@ dependencies = [
|
|||
"simple_logger",
|
||||
"umskt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
|
||||
members = [
|
||||
"umskt",
|
||||
|
|
|
@ -6,12 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
bitreader = "0.3.7"
|
||||
elliptic-curve = "0.13.5"
|
||||
num-bigint = { version = "0.4.3", features = ["rand"] }
|
||||
num-integer = "0.1.45"
|
||||
num-traits = "0.2.15"
|
||||
rand = "0.8.5"
|
||||
sha1 = "0.10.5"
|
||||
openssl = { git = "https://github.com/sfackler/rust-openssl" }
|
||||
thiserror = "1.0.40"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -1,24 +1,20 @@
|
|||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use bitreader::BitReader;
|
||||
use num_bigint::{BigInt, BigUint, RandomBits};
|
||||
use num_integer::Integer;
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use rand::Rng;
|
||||
use sha1::{Digest, Sha1};
|
||||
use openssl::{
|
||||
bn::{BigNum, BigNumContext, MsbOption},
|
||||
ec::{EcGroup, EcPoint},
|
||||
sha::sha1,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
crypto::{EllipticCurve, PrivateKey},
|
||||
key::{base24_decode, base24_encode, strip_key},
|
||||
math::bitmask,
|
||||
weierstrass_curve::{Point, WeierstrassCurve},
|
||||
};
|
||||
|
||||
const FIELD_BITS: u64 = 384;
|
||||
const FIELD_BITS: i32 = 384;
|
||||
const FIELD_BYTES: usize = 48;
|
||||
const SHA_MSG_LENGTH: usize = 4 + 2 * FIELD_BYTES;
|
||||
|
||||
|
@ -48,24 +44,22 @@ impl ProductKey {
|
|||
let sequence = match sequence {
|
||||
Some(serial) => serial,
|
||||
None => {
|
||||
let mut rng = rand::thread_rng();
|
||||
let random: BigInt = rng.sample(RandomBits::new(32));
|
||||
let raw = u32::from_be_bytes(random.to_bytes_be().1[0..4].try_into().unwrap());
|
||||
raw % 999999
|
||||
let mut bn_rand = BigNum::new()?;
|
||||
bn_rand.rand(19, MsbOption::MAYBE_ZERO, false)?;
|
||||
let o_raw = u32::from_be_bytes(bn_rand.to_vec_padded(4)?.try_into().unwrap());
|
||||
o_raw % 999999
|
||||
}
|
||||
};
|
||||
|
||||
// Default to upgrade=false
|
||||
let upgrade = upgrade.unwrap_or(false);
|
||||
|
||||
let private = &private_key.gen_order - &private_key.private_key;
|
||||
|
||||
// Generate a new random key
|
||||
let product_key = Self::generate(
|
||||
&curve.curve,
|
||||
&curve.gen_point,
|
||||
&private_key.gen_order,
|
||||
&private,
|
||||
&private_key.private_key,
|
||||
channel_id,
|
||||
sequence,
|
||||
upgrade,
|
||||
|
@ -89,75 +83,62 @@ impl ProductKey {
|
|||
}
|
||||
|
||||
fn generate(
|
||||
e_curve: &WeierstrassCurve,
|
||||
base_point: &Point,
|
||||
gen_order: &BigInt,
|
||||
private_key: &BigInt,
|
||||
e_curve: &EcGroup,
|
||||
base_point: &EcPoint,
|
||||
gen_order: &BigNum,
|
||||
private_key: &BigNum,
|
||||
channel_id: u32,
|
||||
sequence: u32,
|
||||
upgrade: bool,
|
||||
) -> Result<Self> {
|
||||
let mut num_context = BigNumContext::new().unwrap();
|
||||
|
||||
let mut c = BigNum::new()?;
|
||||
let mut s = BigNum::new()?;
|
||||
let mut x = BigNum::new()?;
|
||||
let mut y = BigNum::new()?;
|
||||
|
||||
let mut ek: BigNum;
|
||||
|
||||
let serial = channel_id * 1_000_000 + sequence;
|
||||
let data = serial << 1 | upgrade as u32;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let product_key = loop {
|
||||
let mut r = EcPoint::new(e_curve)?;
|
||||
|
||||
// Generate a random number c consisting of 384 bits without any constraints.
|
||||
let c: BigUint = rng.sample(RandomBits::new(FIELD_BITS));
|
||||
let c: BigInt = c.into();
|
||||
c.rand(FIELD_BITS, MsbOption::MAYBE_ZERO, false)?;
|
||||
|
||||
// Pick a random derivative of the base point on the elliptic curve.
|
||||
// R = cG;
|
||||
let r = e_curve.multiply_point(&c, base_point);
|
||||
r.mul(e_curve, base_point, &c, &num_context)?;
|
||||
|
||||
// Acquire its coordinates.
|
||||
// x = R.x; y = R.y;
|
||||
let (x, y) = match r {
|
||||
Point::Point { x, y } => (x, y),
|
||||
Point::Infinity => bail!("Point at infinity!"),
|
||||
};
|
||||
r.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
||||
|
||||
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||
|
||||
let x_bin = x.to_bytes_le().1;
|
||||
let x_bin = match x_bin.len().cmp(&FIELD_BYTES) {
|
||||
Ordering::Less => (0..FIELD_BYTES - x_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(x_bin.into_iter())
|
||||
.collect(),
|
||||
Ordering::Greater => continue,
|
||||
Ordering::Equal => x_bin,
|
||||
};
|
||||
let y_bin = y.to_bytes_le().1;
|
||||
let y_bin = match y_bin.len().cmp(&FIELD_BYTES) {
|
||||
Ordering::Less => (0..FIELD_BYTES - y_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(y_bin.into_iter())
|
||||
.collect(),
|
||||
Ordering::Greater => continue,
|
||||
Ordering::Equal => y_bin,
|
||||
};
|
||||
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(&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 = {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(msg_buffer);
|
||||
hasher.finalize()
|
||||
};
|
||||
let msg_digest = sha1(&msg_buffer);
|
||||
|
||||
let hash: u32 =
|
||||
u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & bitmask(28) as u32;
|
||||
|
||||
let mut ek = private_key.clone();
|
||||
ek *= hash;
|
||||
ek = (*private_key).to_owned()?;
|
||||
ek.mul_word(hash)?;
|
||||
|
||||
let s = (ek + c).mod_floor(gen_order);
|
||||
s.mod_add(&ek, &c, gen_order, &mut num_context)?;
|
||||
|
||||
let signature = s.to_u64().unwrap_or(0);
|
||||
let signature = u64::from_be_bytes(s.to_vec_padded(8)?.try_into().unwrap());
|
||||
|
||||
if signature <= bitmask(55) {
|
||||
break Self {
|
||||
|
@ -175,43 +156,36 @@ impl ProductKey {
|
|||
|
||||
fn verify(
|
||||
&self,
|
||||
e_curve: &WeierstrassCurve,
|
||||
base_point: &Point,
|
||||
public_key: &Point,
|
||||
e_curve: &EcGroup,
|
||||
base_point: &EcPoint,
|
||||
public_key: &EcPoint,
|
||||
) -> Result<bool> {
|
||||
let e = BigInt::from_u32(self.hash).unwrap();
|
||||
let s = BigInt::from_u64(self.signature).unwrap();
|
||||
let mut ctx = BigNumContext::new()?;
|
||||
|
||||
let t = e_curve.multiply_point(&s, base_point);
|
||||
let mut p = e_curve.multiply_point(&e, public_key);
|
||||
let e = BigNum::from_u32(self.hash)?;
|
||||
let s = BigNum::from_slice(&self.signature.to_be_bytes())?;
|
||||
let mut x = BigNum::new()?;
|
||||
let mut y = BigNum::new()?;
|
||||
|
||||
p = e_curve.add_points(&p, &t);
|
||||
let mut t = EcPoint::new(e_curve)?;
|
||||
let mut p = EcPoint::new(e_curve)?;
|
||||
|
||||
let (x, y) = match p {
|
||||
Point::Point { x, y } => (x, y),
|
||||
Point::Infinity => bail!("Point at infinity!"),
|
||||
};
|
||||
t.mul(e_curve, base_point, &s, &ctx)?;
|
||||
p.mul(e_curve, public_key, &e, &ctx)?;
|
||||
|
||||
{
|
||||
let p_copy = p.to_owned(e_curve)?;
|
||||
p.add(e_curve, &t, &p_copy, &mut ctx)?;
|
||||
}
|
||||
|
||||
p.affine_coordinates(e_curve, &mut x, &mut y, &mut ctx)?;
|
||||
|
||||
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||
|
||||
let x_bin = x.to_bytes_le().1;
|
||||
let x_bin = if x_bin.len() < FIELD_BYTES {
|
||||
(0..FIELD_BYTES - x_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(x_bin.into_iter())
|
||||
.collect()
|
||||
} else {
|
||||
x_bin
|
||||
};
|
||||
let y_bin = y.to_bytes_le().1;
|
||||
let y_bin = if y_bin.len() < FIELD_BYTES {
|
||||
(0..FIELD_BYTES - y_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(y_bin.into_iter())
|
||||
.collect()
|
||||
} else {
|
||||
y_bin
|
||||
};
|
||||
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();
|
||||
|
||||
let serial = self.channel_id * 1_000_000 + self.sequence;
|
||||
let data = serial << 1 | self.upgrade as u32;
|
||||
|
@ -220,11 +194,7 @@ impl ProductKey {
|
|||
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 = {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(msg_buffer);
|
||||
hasher.finalize()
|
||||
};
|
||||
let msg_digest = sha1(&msg_buffer);
|
||||
|
||||
let hash: u32 =
|
||||
u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & bitmask(28) as u32;
|
||||
|
@ -295,7 +265,7 @@ mod tests {
|
|||
|
||||
use serde_json::from_reader;
|
||||
|
||||
use crate::{bink1998, crypto::EllipticCurve};
|
||||
use crate::crypto::EllipticCurve;
|
||||
|
||||
#[test]
|
||||
fn verify_test() {
|
||||
|
@ -313,15 +283,16 @@ mod tests {
|
|||
|
||||
let p = bink["p"].as_str().unwrap();
|
||||
let a = bink["a"].as_str().unwrap();
|
||||
let b = bink["b"].as_str().unwrap();
|
||||
let gx = bink["g"]["x"].as_str().unwrap();
|
||||
let gy = bink["g"]["y"].as_str().unwrap();
|
||||
let kx = bink["pub"]["x"].as_str().unwrap();
|
||||
let ky = bink["pub"]["y"].as_str().unwrap();
|
||||
|
||||
let curve = EllipticCurve::new(p, a, gx, gy, kx, ky).unwrap();
|
||||
let curve = EllipticCurve::new(p, a, b, gx, gy, kx, ky).unwrap();
|
||||
|
||||
assert!(bink1998::ProductKey::from_key(&curve, product_key).is_ok());
|
||||
assert!(bink1998::ProductKey::from_key(&curve, "11111-R6BG2-39J83-RYKHF-W47TT").is_err());
|
||||
assert!(super::ProductKey::from_key(&curve, product_key).is_ok());
|
||||
assert!(super::ProductKey::from_key(&curve, "11111-R6BG2-39J83-RYKHF-W47TT").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use bitreader::BitReader;
|
||||
use num_bigint::{BigInt, BigUint, RandomBits};
|
||||
use num_integer::Integer;
|
||||
use num_traits::ToPrimitive;
|
||||
use rand::Rng;
|
||||
use sha1::{Digest, Sha1};
|
||||
use openssl::{
|
||||
bn::{BigNum, BigNumContext, MsbOption},
|
||||
ec::{EcGroup, EcPoint},
|
||||
rand::rand_bytes,
|
||||
sha::sha1,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
crypto::{EllipticCurve, PrivateKey},
|
||||
key::{base24_decode, base24_encode, strip_key},
|
||||
math::{bitmask, by_dword, next_sn_bits},
|
||||
msr::mod_sqrt,
|
||||
weierstrass_curve::{Point, WeierstrassCurve},
|
||||
};
|
||||
|
||||
const FIELD_BITS: u64 = 512;
|
||||
const FIELD_BITS: i32 = 512;
|
||||
const FIELD_BYTES: usize = 64;
|
||||
const SHA_MSG_LENGTH: usize = 3 + 2 * FIELD_BYTES;
|
||||
|
||||
|
@ -51,10 +47,9 @@ impl ProductKey {
|
|||
let auth_info = match auth_info {
|
||||
Some(auth_info) => auth_info,
|
||||
None => {
|
||||
let mut rng = rand::thread_rng();
|
||||
let random: BigInt = rng.sample(RandomBits::new(32));
|
||||
let raw = u32::from_be_bytes(random.to_bytes_be().1[0..4].try_into().unwrap());
|
||||
raw % (bitmask(10) as u32)
|
||||
let mut auth_info_bytes = [0_u8; 4];
|
||||
rand_bytes(&mut auth_info_bytes)?;
|
||||
u32::from_ne_bytes(auth_info_bytes) & ((1 << 10) - 1)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -93,50 +88,38 @@ impl ProductKey {
|
|||
}
|
||||
|
||||
fn generate(
|
||||
e_curve: &WeierstrassCurve,
|
||||
base_point: &Point,
|
||||
gen_order: &BigInt,
|
||||
private_key: &BigInt,
|
||||
e_curve: &EcGroup,
|
||||
base_point: &EcPoint,
|
||||
gen_order: &BigNum,
|
||||
private_key: &BigNum,
|
||||
channel_id: u32,
|
||||
auth_info: u32,
|
||||
upgrade: bool,
|
||||
) -> Result<Self> {
|
||||
let data = channel_id << 1 | upgrade as u32;
|
||||
let mut num_context = BigNumContext::new().unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut c = BigNum::new()?;
|
||||
let mut x = BigNum::new()?;
|
||||
let mut y = BigNum::new()?;
|
||||
|
||||
let data = channel_id << 1 | upgrade as u32;
|
||||
|
||||
let mut no_square = false;
|
||||
let key = loop {
|
||||
let c: BigUint = rng.sample(RandomBits::new(FIELD_BITS));
|
||||
let mut c: BigInt = c.into();
|
||||
let mut r = EcPoint::new(e_curve)?;
|
||||
|
||||
let r = e_curve.multiply_point(&c, base_point);
|
||||
c.rand(FIELD_BITS, MsbOption::MAYBE_ZERO, false)?;
|
||||
|
||||
let (x, y) = match r {
|
||||
Point::Point { x, y } => (x, y),
|
||||
Point::Infinity => bail!("Point at infinity!"),
|
||||
};
|
||||
r.mul(e_curve, base_point, &c, &num_context)?;
|
||||
|
||||
r.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
||||
|
||||
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||
|
||||
let x_bin = x.to_bytes_le().1;
|
||||
let x_bin = match x_bin.len().cmp(&FIELD_BYTES) {
|
||||
Ordering::Less => (0..FIELD_BYTES - x_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(x_bin.into_iter())
|
||||
.collect(),
|
||||
Ordering::Greater => continue,
|
||||
Ordering::Equal => x_bin,
|
||||
};
|
||||
let y_bin = y.to_bytes_le().1;
|
||||
let y_bin = match y_bin.len().cmp(&FIELD_BYTES) {
|
||||
Ordering::Less => (0..FIELD_BYTES - y_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(y_bin.into_iter())
|
||||
.collect(),
|
||||
Ordering::Greater => continue,
|
||||
Ordering::Equal => y_bin,
|
||||
};
|
||||
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[0x00] = 0x79;
|
||||
msg_buffer[0x01] = (data & 0x00FF) as u8;
|
||||
|
@ -145,11 +128,7 @@ impl ProductKey {
|
|||
msg_buffer[3..3 + FIELD_BYTES].copy_from_slice(&x_bin);
|
||||
msg_buffer[3 + FIELD_BYTES..3 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
||||
|
||||
let msg_digest = {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(msg_buffer);
|
||||
hasher.finalize()
|
||||
};
|
||||
let msg_digest = sha1(&msg_buffer);
|
||||
|
||||
let hash: u32 = by_dword(&msg_digest[0..4]) & bitmask(31) as u32;
|
||||
|
||||
|
@ -165,43 +144,42 @@ impl ProductKey {
|
|||
msg_buffer[0x09] = 0x00;
|
||||
msg_buffer[0x0A] = 0x00;
|
||||
|
||||
let msg_digest = {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(&msg_buffer[..=0x0A]);
|
||||
hasher.finalize()
|
||||
};
|
||||
let msg_digest = sha1(&msg_buffer[..=0x0A]);
|
||||
|
||||
let i_signature = next_sn_bits(by_dword(&msg_digest[4..8]) as u64, 30, 2) << 32
|
||||
| by_dword(&msg_digest[0..4]) as u64;
|
||||
|
||||
let mut e = BigInt::from(i_signature);
|
||||
let mut e = BigNum::from_slice(&i_signature.to_be_bytes())?;
|
||||
|
||||
e = (e * private_key).mod_floor(gen_order);
|
||||
let e_2 = e.to_owned()?;
|
||||
e.mod_mul(&e_2, private_key, gen_order, &mut num_context)?;
|
||||
|
||||
let mut s = e.clone();
|
||||
let mut s = e.to_owned()?;
|
||||
|
||||
s = (&s * &s).mod_floor(gen_order);
|
||||
let s_2 = s.to_owned()?;
|
||||
s.mod_sqr(&s_2, gen_order, &mut num_context)?;
|
||||
|
||||
c <<= 2;
|
||||
let c_2 = c.to_owned()?;
|
||||
c.lshift(&c_2, 2)?;
|
||||
|
||||
s = &s + &c;
|
||||
|
||||
match mod_sqrt(&s, gen_order) {
|
||||
Some(res) => s = res,
|
||||
None => {
|
||||
no_square = true;
|
||||
}
|
||||
}
|
||||
let s_2 = s.to_owned()?;
|
||||
if s.mod_sqrt(&s_2, gen_order, &mut num_context).is_err() {
|
||||
no_square = true;
|
||||
};
|
||||
|
||||
s = (s - e).mod_floor(gen_order);
|
||||
let s_2 = s.to_owned()?;
|
||||
s.mod_sub(&s_2, &e, gen_order, &mut num_context)?;
|
||||
|
||||
if s.is_odd() {
|
||||
if s.is_bit_set(0) {
|
||||
s = &s + gen_order;
|
||||
}
|
||||
|
||||
s >>= 1;
|
||||
let s_2 = s.to_owned()?;
|
||||
s.rshift1(&s_2)?;
|
||||
|
||||
let signature = s.to_u64().unwrap_or(0);
|
||||
let signature = u64::from_be_bytes(s.to_vec_padded(8)?.try_into().unwrap());
|
||||
|
||||
let product_key = Self {
|
||||
upgrade,
|
||||
|
@ -223,10 +201,12 @@ impl ProductKey {
|
|||
|
||||
fn verify(
|
||||
&self,
|
||||
e_curve: &WeierstrassCurve,
|
||||
base_point: &Point,
|
||||
public_key: &Point,
|
||||
e_curve: &EcGroup,
|
||||
base_point: &EcPoint,
|
||||
public_key: &EcPoint,
|
||||
) -> Result<bool> {
|
||||
let mut num_context = BigNumContext::new()?;
|
||||
|
||||
let data = self.channel_id << 1 | self.upgrade as u32;
|
||||
|
||||
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||
|
@ -243,47 +223,39 @@ impl ProductKey {
|
|||
msg_buffer[0x09] = 0x00;
|
||||
msg_buffer[0x0A] = 0x00;
|
||||
|
||||
let msg_digest = {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(&msg_buffer[..=0x0A]);
|
||||
hasher.finalize()
|
||||
};
|
||||
let msg_digest = sha1(&msg_buffer[..=0x0A]);
|
||||
|
||||
let i_signature = next_sn_bits(by_dword(&msg_digest[4..8]) as u64, 30, 2) << 32
|
||||
| by_dword(&msg_digest[0..4]) as u64;
|
||||
|
||||
let e = BigInt::from(i_signature);
|
||||
let s = BigInt::from(self.signature);
|
||||
let e = BigNum::from_slice(&i_signature.to_be_bytes())?;
|
||||
let s = BigNum::from_slice(&self.signature.to_be_bytes())?;
|
||||
|
||||
let t = e_curve.multiply_point(&s, base_point);
|
||||
let mut p = e_curve.multiply_point(&e, public_key);
|
||||
let mut x = BigNum::new()?;
|
||||
let mut y = BigNum::new()?;
|
||||
|
||||
p = e_curve.add_points(&t, &p);
|
||||
p = e_curve.multiply_point(&s, &p);
|
||||
let mut p = EcPoint::new(e_curve)?;
|
||||
let mut t = EcPoint::new(e_curve)?;
|
||||
|
||||
let (x, y) = match p {
|
||||
Point::Point { x, y } => (x, y),
|
||||
Point::Infinity => bail!("Point at infinity!"),
|
||||
};
|
||||
t.mul(e_curve, base_point, &s, &num_context)?;
|
||||
p.mul(e_curve, public_key, &e, &num_context)?;
|
||||
|
||||
let x_bin = x.to_bytes_le().1;
|
||||
let x_bin = if x_bin.len() < FIELD_BYTES {
|
||||
(0..FIELD_BYTES - x_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(x_bin.into_iter())
|
||||
.collect()
|
||||
} else {
|
||||
x_bin
|
||||
};
|
||||
let y_bin = y.to_bytes_le().1;
|
||||
let y_bin = if y_bin.len() < FIELD_BYTES {
|
||||
(0..FIELD_BYTES - y_bin.len())
|
||||
.map(|_| 0)
|
||||
.chain(y_bin.into_iter())
|
||||
.collect()
|
||||
} else {
|
||||
y_bin
|
||||
};
|
||||
{
|
||||
let p_2 = p.to_owned(e_curve)?;
|
||||
p.add(e_curve, &t, &p_2, &mut num_context)?;
|
||||
}
|
||||
|
||||
{
|
||||
let p_2 = p.to_owned(e_curve)?;
|
||||
p.mul(e_curve, &p_2, &s, &num_context)?;
|
||||
}
|
||||
|
||||
p.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
||||
|
||||
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[0x00] = 0x79;
|
||||
msg_buffer[0x01] = (data & 0x00FF) as u8;
|
||||
|
@ -292,11 +264,7 @@ impl ProductKey {
|
|||
msg_buffer[3..3 + FIELD_BYTES].copy_from_slice(&x_bin);
|
||||
msg_buffer[3 + FIELD_BYTES..3 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
||||
|
||||
let msg_digest = {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(msg_buffer);
|
||||
hasher.finalize()
|
||||
};
|
||||
let msg_digest = sha1(&msg_buffer);
|
||||
|
||||
let hash: u32 = by_dword(&msg_digest[0..4]) & bitmask(31) as u32;
|
||||
|
||||
|
@ -385,12 +353,13 @@ mod tests {
|
|||
|
||||
let p = bink["p"].as_str().unwrap();
|
||||
let a = bink["a"].as_str().unwrap();
|
||||
let b = bink["b"].as_str().unwrap();
|
||||
let gx = bink["g"]["x"].as_str().unwrap();
|
||||
let gy = bink["g"]["y"].as_str().unwrap();
|
||||
let kx = bink["pub"]["x"].as_str().unwrap();
|
||||
let ky = bink["pub"]["y"].as_str().unwrap();
|
||||
|
||||
let curve = EllipticCurve::new(p, a, gx, gy, kx, ky).unwrap();
|
||||
let curve = EllipticCurve::new(p, a, b, gx, gy, kx, ky).unwrap();
|
||||
|
||||
assert!(super::ProductKey::from_key(&curve, product_key).is_ok());
|
||||
assert!(super::ProductKey::from_key(&curve, "11111-YRGC8-4KYTG-C3FCC-JCFDY").is_err());
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
use anyhow::Result;
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::Num;
|
||||
|
||||
use crate::weierstrass_curve::{Point, WeierstrassCurve};
|
||||
use openssl::{
|
||||
bn::{BigNum, BigNumContext},
|
||||
ec::{EcGroup, EcPoint},
|
||||
};
|
||||
|
||||
pub struct EllipticCurve {
|
||||
pub curve: WeierstrassCurve,
|
||||
pub gen_point: Point,
|
||||
pub pub_point: Point,
|
||||
pub curve: EcGroup,
|
||||
pub gen_point: EcPoint,
|
||||
pub pub_point: EcPoint,
|
||||
}
|
||||
|
||||
pub struct PrivateKey {
|
||||
pub gen_order: BigInt,
|
||||
pub private_key: BigInt,
|
||||
pub gen_order: BigNum,
|
||||
pub private_key: BigNum,
|
||||
}
|
||||
|
||||
impl PrivateKey {
|
||||
pub fn new(gen_order: &str, private_key: &str) -> Result<Self> {
|
||||
let gen_order = BigInt::from_str_radix(gen_order, 10)?;
|
||||
let private_key = BigInt::from_str_radix(private_key, 10)?;
|
||||
let gen_order = BigNum::from_dec_str(gen_order)?;
|
||||
let private_key = &gen_order - &BigNum::from_dec_str(private_key)?;
|
||||
Ok(Self {
|
||||
gen_order,
|
||||
private_key,
|
||||
|
@ -30,29 +30,29 @@ impl EllipticCurve {
|
|||
pub fn new(
|
||||
p: &str,
|
||||
a: &str,
|
||||
b: &str,
|
||||
generator_x: &str,
|
||||
generator_y: &str,
|
||||
public_key_x: &str,
|
||||
public_key_y: &str,
|
||||
) -> Result<Self> {
|
||||
let p = BigInt::from_str_radix(p, 10)?;
|
||||
let a = BigInt::from_str_radix(a, 10)?;
|
||||
let generator_x = BigInt::from_str_radix(generator_x, 10)?;
|
||||
let generator_y = BigInt::from_str_radix(generator_y, 10)?;
|
||||
let public_key_x = BigInt::from_str_radix(public_key_x, 10)?;
|
||||
let public_key_y = BigInt::from_str_radix(public_key_y, 10)?;
|
||||
let mut context = BigNumContext::new()?;
|
||||
|
||||
let curve = WeierstrassCurve::new(a, p);
|
||||
let p = BigNum::from_dec_str(p)?;
|
||||
let a = BigNum::from_dec_str(a)?;
|
||||
let b = BigNum::from_dec_str(b)?;
|
||||
let generator_x = BigNum::from_dec_str(generator_x)?;
|
||||
let generator_y = BigNum::from_dec_str(generator_y)?;
|
||||
let public_key_x = BigNum::from_dec_str(public_key_x)?;
|
||||
let public_key_y = BigNum::from_dec_str(public_key_y)?;
|
||||
|
||||
let gen_point = Point::Point {
|
||||
x: generator_x,
|
||||
y: generator_y,
|
||||
};
|
||||
let curve = EcGroup::from_components(p, a, b, &mut context)?;
|
||||
|
||||
let pub_point = Point::Point {
|
||||
x: public_key_x,
|
||||
y: public_key_y,
|
||||
};
|
||||
let mut gen_point = EcPoint::new(&curve)?;
|
||||
gen_point.set_affine_coordinates_gfp(&curve, &generator_x, &generator_y, &mut context)?;
|
||||
|
||||
let mut pub_point = EcPoint::new(&curve)?;
|
||||
pub_point.set_affine_coordinates_gfp(&curve, &public_key_x, &public_key_y, &mut context)?;
|
||||
|
||||
Ok(Self {
|
||||
curve,
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use num_bigint::{BigInt, Sign};
|
||||
use num_integer::Integer;
|
||||
use num_traits::{ToPrimitive, Zero};
|
||||
use openssl::bn::BigNum;
|
||||
|
||||
const PK_LENGTH: usize = 25;
|
||||
|
||||
|
@ -19,24 +17,20 @@ pub(crate) fn base24_decode(cd_key: &str) -> Result<Vec<u8>> {
|
|||
.filter_map(|c| KEY_CHARSET.iter().position(|&x| x == c).map(|i| i as u8))
|
||||
.collect();
|
||||
|
||||
let mut y = BigInt::zero();
|
||||
let mut y = BigNum::from_u32(0).unwrap();
|
||||
|
||||
for i in decoded_key {
|
||||
y *= PK_LENGTH - 1;
|
||||
y += i as u32;
|
||||
y.mul_word((PK_LENGTH - 1) as u32).unwrap();
|
||||
y.add_word(i.into()).unwrap();
|
||||
}
|
||||
|
||||
Ok(y.to_bytes_be().1)
|
||||
Ok(y.to_vec())
|
||||
}
|
||||
|
||||
pub(crate) fn base24_encode(byte_seq: &[u8]) -> Result<String> {
|
||||
let mut z = BigInt::from_bytes_be(Sign::Plus, byte_seq);
|
||||
let mut z = BigNum::from_slice(byte_seq).unwrap();
|
||||
let mut out: VecDeque<char> = VecDeque::new();
|
||||
(0..=24).for_each(|_| {
|
||||
let (quo, rem) = z.div_rem(&BigInt::from(24));
|
||||
z = quo;
|
||||
out.push_front(KEY_CHARSET[rem.to_u32().unwrap() as usize]);
|
||||
});
|
||||
(0..=24).for_each(|_| out.push_front(KEY_CHARSET[z.div_word(24).unwrap() as usize]));
|
||||
Ok(out.iter().collect())
|
||||
}
|
||||
|
||||
|
|
|
@ -4,5 +4,3 @@ pub mod confid;
|
|||
pub mod crypto;
|
||||
mod key;
|
||||
mod math;
|
||||
mod msr;
|
||||
mod weierstrass_curve;
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
use num_bigint::BigInt;
|
||||
use num_traits::{One, Zero};
|
||||
|
||||
// Legendre symbol, returns 1, 0, or -1 mod p
|
||||
fn ls(a: &BigInt, p: &BigInt) -> BigInt {
|
||||
let exp = (p - BigInt::one()) / BigInt::from(2);
|
||||
a.modpow(&exp, p)
|
||||
}
|
||||
|
||||
// Tonelli-Shanks algorithm
|
||||
pub fn mod_sqrt(n: &BigInt, p: &BigInt) -> Option<BigInt> {
|
||||
if !ls(n, p).is_one() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut q = p - 1;
|
||||
let mut s = BigInt::zero();
|
||||
while (&q & &BigInt::one()).is_zero() {
|
||||
s += 1;
|
||||
q >>= 1
|
||||
}
|
||||
|
||||
if s.is_one() {
|
||||
let exp = (p + 1) / 4;
|
||||
let r1 = n.modpow(&exp, p);
|
||||
return Some(p - &r1);
|
||||
}
|
||||
|
||||
let mut z = BigInt::from(2);
|
||||
while ls(&z, p) != p - 1 {
|
||||
z += 1
|
||||
}
|
||||
let mut c = z.modpow(&q, p);
|
||||
|
||||
let mut r = n.modpow(&((&q + 1) / 2), p);
|
||||
let mut t = n.modpow(&q, p);
|
||||
let mut m = s;
|
||||
|
||||
loop {
|
||||
if t.is_one() {
|
||||
return Some(p - &r);
|
||||
}
|
||||
|
||||
let mut i = BigInt::zero();
|
||||
let mut z = t.clone();
|
||||
let mut b = c.clone();
|
||||
while !z.is_one() && i < &m - 1 {
|
||||
z = &z * &z % p;
|
||||
i += 1;
|
||||
}
|
||||
let mut e = &m - &i - 1;
|
||||
while e > BigInt::zero() {
|
||||
b = &b * &b % p;
|
||||
e -= 1;
|
||||
}
|
||||
r = &r * &b % p;
|
||||
c = &b * &b % p;
|
||||
t = &t * &c % p;
|
||||
m = i;
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
use num_bigint::BigInt;
|
||||
use num_integer::Integer;
|
||||
use num_traits::{One, Zero};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Point {
|
||||
Infinity,
|
||||
Point { x: BigInt, y: BigInt },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WeierstrassCurve {
|
||||
a: BigInt,
|
||||
p: BigInt,
|
||||
}
|
||||
|
||||
impl WeierstrassCurve {
|
||||
pub fn new(a: BigInt, p: BigInt) -> Self {
|
||||
WeierstrassCurve { a, p }
|
||||
}
|
||||
|
||||
fn mod_inverse(a: &BigInt, p: &BigInt) -> BigInt {
|
||||
let egcd = a.extended_gcd(p);
|
||||
egcd.x.mod_floor(p)
|
||||
}
|
||||
|
||||
fn double_point(&self, point: &Point) -> Point {
|
||||
match point {
|
||||
Point::Point { x, y } => {
|
||||
if y.is_zero() {
|
||||
Point::Infinity
|
||||
} else {
|
||||
let three = BigInt::from(3);
|
||||
let two = BigInt::from(2);
|
||||
|
||||
let lambda = (three * x * x + &self.a) * Self::mod_inverse(&(two * y), &self.p);
|
||||
let lamba_sqr = (&lambda * &lambda).mod_floor(&self.p);
|
||||
let x3 = (&lamba_sqr - x - x).mod_floor(&self.p);
|
||||
let y3 = (&lambda * (x - &x3) - y).mod_floor(&self.p);
|
||||
|
||||
Point::Point { x: x3, y: y3 }
|
||||
}
|
||||
}
|
||||
Point::Infinity => Point::Infinity,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_points(&self, point1: &Point, point2: &Point) -> Point {
|
||||
match (point1, point2) {
|
||||
(Point::Point { x: x1, y: y1 }, Point::Point { x: x2, y: y2 }) => {
|
||||
if point1 == point2 {
|
||||
self.double_point(point1)
|
||||
} else {
|
||||
let lambda = (y2 - y1) * Self::mod_inverse(&(x2 - x1), &self.p);
|
||||
let x3 = ((&lambda * &lambda) - x1 - x2).mod_floor(&self.p);
|
||||
let y3: BigInt = ((&lambda * (x1 - &x3)) - y1).mod_floor(&self.p);
|
||||
|
||||
Point::Point { x: x3, y: y3 }
|
||||
}
|
||||
}
|
||||
(Point::Point { x, y }, Point::Infinity) | (Point::Infinity, Point::Point { x, y }) => {
|
||||
Point::Point {
|
||||
x: x.clone(),
|
||||
y: y.clone(),
|
||||
}
|
||||
}
|
||||
(Point::Infinity, Point::Infinity) => Point::Infinity,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multiply_point(&self, s: &BigInt, point: &Point) -> Point {
|
||||
let mut res = Point::Infinity;
|
||||
let mut temp = point.clone();
|
||||
|
||||
let mut s = s.clone();
|
||||
|
||||
while s > BigInt::zero() {
|
||||
if (&s % BigInt::from(2)) == BigInt::one() {
|
||||
res = self.add_points(&res, &temp);
|
||||
}
|
||||
temp = self.double_point(&temp);
|
||||
|
||||
s >>= 1;
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
|
@ -102,6 +102,7 @@ fn validate(args: &ValidateArgs) -> Result<()> {
|
|||
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;
|
||||
|
@ -109,7 +110,7 @@ fn initialize_curve(bink: &Bink, bink_id: &str) -> Result<EllipticCurve> {
|
|||
|
||||
log::info!("Elliptic curve parameters for BINK ID {bink_id}:\n{bink}");
|
||||
|
||||
EllipticCurve::new(p, a, gx, gy, kx, ky)
|
||||
EllipticCurve::new(p, a, b, gx, gy, kx, ky)
|
||||
}
|
||||
|
||||
fn bink1998_generate(
|
||||
|
|
Loading…
Add table
Reference in a new issue