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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
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]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -84,15 +72,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"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]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.79"
|
version = "1.0.79"
|
||||||
|
@ -153,63 +132,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
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]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -232,47 +154,19 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ff"
|
name = "foreign-types"
|
||||||
version = "0.13.0"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core",
|
"foreign-types-shared",
|
||||||
"subtle",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "foreign-types-shared"
|
||||||
version = "0.14.7"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
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",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
@ -333,37 +227,6 @@ version = "0.4.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
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]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.18.0"
|
version = "1.18.0"
|
||||||
|
@ -371,10 +234,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "openssl"
|
||||||
version = "0.2.17"
|
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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
|
@ -394,36 +292,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"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]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.37.20"
|
version = "0.37.20"
|
||||||
|
@ -475,17 +343,6 @@ dependencies = [
|
||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "simple_logger"
|
name = "simple_logger"
|
||||||
version = "4.2.0"
|
version = "4.2.0"
|
||||||
|
@ -502,12 +359,6 @@ version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "subtle"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.21"
|
version = "2.0.21"
|
||||||
|
@ -539,25 +390,14 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "umskt"
|
name = "umskt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitreader",
|
"bitreader",
|
||||||
"elliptic-curve",
|
"openssl",
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"rand",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha1",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -574,16 +414,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "vcpkg"
|
||||||
version = "0.9.4"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
|
@ -720,9 +554,3 @@ dependencies = [
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
"umskt",
|
"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]
|
[workspace]
|
||||||
resolver = "2"
|
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"umskt",
|
"umskt",
|
||||||
|
|
|
@ -6,12 +6,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.71"
|
anyhow = "1.0.71"
|
||||||
bitreader = "0.3.7"
|
bitreader = "0.3.7"
|
||||||
elliptic-curve = "0.13.5"
|
openssl = { git = "https://github.com/sfackler/rust-openssl" }
|
||||||
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"
|
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.40"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
use std::{
|
use std::fmt::{Display, Formatter};
|
||||||
cmp::Ordering,
|
|
||||||
fmt::{Display, Formatter},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use bitreader::BitReader;
|
use bitreader::BitReader;
|
||||||
use num_bigint::{BigInt, BigUint, RandomBits};
|
use openssl::{
|
||||||
use num_integer::Integer;
|
bn::{BigNum, BigNumContext, MsbOption},
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
ec::{EcGroup, EcPoint},
|
||||||
use rand::Rng;
|
sha::sha1,
|
||||||
use sha1::{Digest, Sha1};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
crypto::{EllipticCurve, PrivateKey},
|
crypto::{EllipticCurve, PrivateKey},
|
||||||
key::{base24_decode, base24_encode, strip_key},
|
key::{base24_decode, base24_encode, strip_key},
|
||||||
math::bitmask,
|
math::bitmask,
|
||||||
weierstrass_curve::{Point, WeierstrassCurve},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const FIELD_BITS: u64 = 384;
|
const FIELD_BITS: i32 = 384;
|
||||||
const FIELD_BYTES: usize = 48;
|
const FIELD_BYTES: usize = 48;
|
||||||
const SHA_MSG_LENGTH: usize = 4 + 2 * FIELD_BYTES;
|
const SHA_MSG_LENGTH: usize = 4 + 2 * FIELD_BYTES;
|
||||||
|
|
||||||
|
@ -48,24 +44,22 @@ impl ProductKey {
|
||||||
let sequence = match sequence {
|
let sequence = match sequence {
|
||||||
Some(serial) => serial,
|
Some(serial) => serial,
|
||||||
None => {
|
None => {
|
||||||
let mut rng = rand::thread_rng();
|
let mut bn_rand = BigNum::new()?;
|
||||||
let random: BigInt = rng.sample(RandomBits::new(32));
|
bn_rand.rand(19, MsbOption::MAYBE_ZERO, false)?;
|
||||||
let raw = u32::from_be_bytes(random.to_bytes_be().1[0..4].try_into().unwrap());
|
let o_raw = u32::from_be_bytes(bn_rand.to_vec_padded(4)?.try_into().unwrap());
|
||||||
raw % 999999
|
o_raw % 999999
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default to upgrade=false
|
// Default to upgrade=false
|
||||||
let upgrade = upgrade.unwrap_or(false);
|
let upgrade = upgrade.unwrap_or(false);
|
||||||
|
|
||||||
let private = &private_key.gen_order - &private_key.private_key;
|
|
||||||
|
|
||||||
// Generate a new random key
|
// Generate a new random key
|
||||||
let product_key = Self::generate(
|
let product_key = Self::generate(
|
||||||
&curve.curve,
|
&curve.curve,
|
||||||
&curve.gen_point,
|
&curve.gen_point,
|
||||||
&private_key.gen_order,
|
&private_key.gen_order,
|
||||||
&private,
|
&private_key.private_key,
|
||||||
channel_id,
|
channel_id,
|
||||||
sequence,
|
sequence,
|
||||||
upgrade,
|
upgrade,
|
||||||
|
@ -89,75 +83,62 @@ impl ProductKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate(
|
fn generate(
|
||||||
e_curve: &WeierstrassCurve,
|
e_curve: &EcGroup,
|
||||||
base_point: &Point,
|
base_point: &EcPoint,
|
||||||
gen_order: &BigInt,
|
gen_order: &BigNum,
|
||||||
private_key: &BigInt,
|
private_key: &BigNum,
|
||||||
channel_id: u32,
|
channel_id: u32,
|
||||||
sequence: u32,
|
sequence: u32,
|
||||||
upgrade: bool,
|
upgrade: bool,
|
||||||
) -> Result<Self> {
|
) -> 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 serial = channel_id * 1_000_000 + sequence;
|
||||||
let data = serial << 1 | upgrade as u32;
|
let data = serial << 1 | upgrade as u32;
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
let product_key = loop {
|
let product_key = loop {
|
||||||
|
let mut r = EcPoint::new(e_curve)?;
|
||||||
|
|
||||||
// Generate a random number c consisting of 384 bits without any constraints.
|
// Generate a random number c consisting of 384 bits without any constraints.
|
||||||
let c: BigUint = rng.sample(RandomBits::new(FIELD_BITS));
|
c.rand(FIELD_BITS, MsbOption::MAYBE_ZERO, false)?;
|
||||||
let c: BigInt = c.into();
|
|
||||||
|
|
||||||
// Pick a random derivative of the base point on the elliptic curve.
|
// Pick a random derivative of the base point on the elliptic curve.
|
||||||
// R = cG;
|
// R = cG;
|
||||||
let r = e_curve.multiply_point(&c, base_point);
|
r.mul(e_curve, base_point, &c, &num_context)?;
|
||||||
|
|
||||||
// Acquire its coordinates.
|
// Acquire its coordinates.
|
||||||
// x = R.x; y = R.y;
|
// x = R.x; y = R.y;
|
||||||
let (x, y) = match r {
|
r.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
||||||
Point::Point { x, y } => (x, y),
|
|
||||||
Point::Infinity => bail!("Point at infinity!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||||
|
|
||||||
let x_bin = x.to_bytes_le().1;
|
let mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
let x_bin = match x_bin.len().cmp(&FIELD_BYTES) {
|
x_bin.reverse();
|
||||||
Ordering::Less => (0..FIELD_BYTES - x_bin.len())
|
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
.map(|_| 0)
|
y_bin.reverse();
|
||||||
.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,
|
|
||||||
};
|
|
||||||
|
|
||||||
msg_buffer[0..4].copy_from_slice(&data.to_le_bytes());
|
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..4 + FIELD_BYTES].copy_from_slice(&x_bin);
|
||||||
msg_buffer[4 + FIELD_BYTES..4 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
msg_buffer[4 + FIELD_BYTES..4 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
||||||
|
|
||||||
let msg_digest = {
|
let msg_digest = sha1(&msg_buffer);
|
||||||
let mut hasher = Sha1::new();
|
|
||||||
hasher.update(msg_buffer);
|
|
||||||
hasher.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
let hash: u32 =
|
let hash: u32 =
|
||||||
u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & bitmask(28) as u32;
|
u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & bitmask(28) as u32;
|
||||||
|
|
||||||
let mut ek = private_key.clone();
|
ek = (*private_key).to_owned()?;
|
||||||
ek *= hash;
|
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) {
|
if signature <= bitmask(55) {
|
||||||
break Self {
|
break Self {
|
||||||
|
@ -175,43 +156,36 @@ impl ProductKey {
|
||||||
|
|
||||||
fn verify(
|
fn verify(
|
||||||
&self,
|
&self,
|
||||||
e_curve: &WeierstrassCurve,
|
e_curve: &EcGroup,
|
||||||
base_point: &Point,
|
base_point: &EcPoint,
|
||||||
public_key: &Point,
|
public_key: &EcPoint,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let e = BigInt::from_u32(self.hash).unwrap();
|
let mut ctx = BigNumContext::new()?;
|
||||||
let s = BigInt::from_u64(self.signature).unwrap();
|
|
||||||
|
|
||||||
let t = e_curve.multiply_point(&s, base_point);
|
let e = BigNum::from_u32(self.hash)?;
|
||||||
let mut p = e_curve.multiply_point(&e, public_key);
|
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 {
|
t.mul(e_curve, base_point, &s, &ctx)?;
|
||||||
Point::Point { x, y } => (x, y),
|
p.mul(e_curve, public_key, &e, &ctx)?;
|
||||||
Point::Infinity => bail!("Point at infinity!"),
|
|
||||||
};
|
{
|
||||||
|
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 mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||||
|
|
||||||
let x_bin = x.to_bytes_le().1;
|
let mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
let x_bin = if x_bin.len() < FIELD_BYTES {
|
x_bin.reverse();
|
||||||
(0..FIELD_BYTES - x_bin.len())
|
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
.map(|_| 0)
|
y_bin.reverse();
|
||||||
.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 serial = self.channel_id * 1_000_000 + self.sequence;
|
let serial = self.channel_id * 1_000_000 + self.sequence;
|
||||||
let data = serial << 1 | self.upgrade as u32;
|
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..4 + FIELD_BYTES].copy_from_slice(&x_bin);
|
||||||
msg_buffer[4 + FIELD_BYTES..4 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
msg_buffer[4 + FIELD_BYTES..4 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
||||||
|
|
||||||
let msg_digest = {
|
let msg_digest = sha1(&msg_buffer);
|
||||||
let mut hasher = Sha1::new();
|
|
||||||
hasher.update(msg_buffer);
|
|
||||||
hasher.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
let hash: u32 =
|
let hash: u32 =
|
||||||
u32::from_le_bytes(msg_digest[0..4].try_into().unwrap()) >> 4 & bitmask(28) as 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 serde_json::from_reader;
|
||||||
|
|
||||||
use crate::{bink1998, crypto::EllipticCurve};
|
use crate::crypto::EllipticCurve;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_test() {
|
fn verify_test() {
|
||||||
|
@ -313,15 +283,16 @@ mod tests {
|
||||||
|
|
||||||
let p = bink["p"].as_str().unwrap();
|
let p = bink["p"].as_str().unwrap();
|
||||||
let a = bink["a"].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 gx = bink["g"]["x"].as_str().unwrap();
|
||||||
let gy = bink["g"]["y"].as_str().unwrap();
|
let gy = bink["g"]["y"].as_str().unwrap();
|
||||||
let kx = bink["pub"]["x"].as_str().unwrap();
|
let kx = bink["pub"]["x"].as_str().unwrap();
|
||||||
let ky = bink["pub"]["y"].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!(super::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, "11111-R6BG2-39J83-RYKHF-W47TT").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
use std::{
|
use std::fmt::{Display, Formatter};
|
||||||
cmp::Ordering,
|
|
||||||
fmt::{Display, Formatter},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use bitreader::BitReader;
|
use bitreader::BitReader;
|
||||||
use num_bigint::{BigInt, BigUint, RandomBits};
|
use openssl::{
|
||||||
use num_integer::Integer;
|
bn::{BigNum, BigNumContext, MsbOption},
|
||||||
use num_traits::ToPrimitive;
|
ec::{EcGroup, EcPoint},
|
||||||
use rand::Rng;
|
rand::rand_bytes,
|
||||||
use sha1::{Digest, Sha1};
|
sha::sha1,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
crypto::{EllipticCurve, PrivateKey},
|
crypto::{EllipticCurve, PrivateKey},
|
||||||
key::{base24_decode, base24_encode, strip_key},
|
key::{base24_decode, base24_encode, strip_key},
|
||||||
math::{bitmask, by_dword, next_sn_bits},
|
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 FIELD_BYTES: usize = 64;
|
||||||
const SHA_MSG_LENGTH: usize = 3 + 2 * FIELD_BYTES;
|
const SHA_MSG_LENGTH: usize = 3 + 2 * FIELD_BYTES;
|
||||||
|
|
||||||
|
@ -51,10 +47,9 @@ impl ProductKey {
|
||||||
let auth_info = match auth_info {
|
let auth_info = match auth_info {
|
||||||
Some(auth_info) => auth_info,
|
Some(auth_info) => auth_info,
|
||||||
None => {
|
None => {
|
||||||
let mut rng = rand::thread_rng();
|
let mut auth_info_bytes = [0_u8; 4];
|
||||||
let random: BigInt = rng.sample(RandomBits::new(32));
|
rand_bytes(&mut auth_info_bytes)?;
|
||||||
let raw = u32::from_be_bytes(random.to_bytes_be().1[0..4].try_into().unwrap());
|
u32::from_ne_bytes(auth_info_bytes) & ((1 << 10) - 1)
|
||||||
raw % (bitmask(10) as u32)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -93,50 +88,38 @@ impl ProductKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate(
|
fn generate(
|
||||||
e_curve: &WeierstrassCurve,
|
e_curve: &EcGroup,
|
||||||
base_point: &Point,
|
base_point: &EcPoint,
|
||||||
gen_order: &BigInt,
|
gen_order: &BigNum,
|
||||||
private_key: &BigInt,
|
private_key: &BigNum,
|
||||||
channel_id: u32,
|
channel_id: u32,
|
||||||
auth_info: u32,
|
auth_info: u32,
|
||||||
upgrade: bool,
|
upgrade: bool,
|
||||||
) -> Result<Self> {
|
) -> 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 mut no_square = false;
|
||||||
let key = loop {
|
let key = loop {
|
||||||
let c: BigUint = rng.sample(RandomBits::new(FIELD_BITS));
|
let mut r = EcPoint::new(e_curve)?;
|
||||||
let mut c: BigInt = c.into();
|
|
||||||
|
|
||||||
let r = e_curve.multiply_point(&c, base_point);
|
c.rand(FIELD_BITS, MsbOption::MAYBE_ZERO, false)?;
|
||||||
|
|
||||||
let (x, y) = match r {
|
r.mul(e_curve, base_point, &c, &num_context)?;
|
||||||
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 mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||||
|
|
||||||
let x_bin = x.to_bytes_le().1;
|
let mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
let x_bin = match x_bin.len().cmp(&FIELD_BYTES) {
|
x_bin.reverse();
|
||||||
Ordering::Less => (0..FIELD_BYTES - x_bin.len())
|
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
.map(|_| 0)
|
y_bin.reverse();
|
||||||
.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,
|
|
||||||
};
|
|
||||||
|
|
||||||
msg_buffer[0x00] = 0x79;
|
msg_buffer[0x00] = 0x79;
|
||||||
msg_buffer[0x01] = (data & 0x00FF) as u8;
|
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..3 + FIELD_BYTES].copy_from_slice(&x_bin);
|
||||||
msg_buffer[3 + FIELD_BYTES..3 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
msg_buffer[3 + FIELD_BYTES..3 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
||||||
|
|
||||||
let msg_digest = {
|
let msg_digest = sha1(&msg_buffer);
|
||||||
let mut hasher = Sha1::new();
|
|
||||||
hasher.update(msg_buffer);
|
|
||||||
hasher.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
let hash: u32 = by_dword(&msg_digest[0..4]) & bitmask(31) as u32;
|
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[0x09] = 0x00;
|
||||||
msg_buffer[0x0A] = 0x00;
|
msg_buffer[0x0A] = 0x00;
|
||||||
|
|
||||||
let msg_digest = {
|
let msg_digest = sha1(&msg_buffer[..=0x0A]);
|
||||||
let mut hasher = Sha1::new();
|
|
||||||
hasher.update(&msg_buffer[..=0x0A]);
|
|
||||||
hasher.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
let i_signature = next_sn_bits(by_dword(&msg_digest[4..8]) as u64, 30, 2) << 32
|
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;
|
| 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;
|
s = &s + &c;
|
||||||
|
|
||||||
match mod_sqrt(&s, gen_order) {
|
let s_2 = s.to_owned()?;
|
||||||
Some(res) => s = res,
|
if s.mod_sqrt(&s_2, gen_order, &mut num_context).is_err() {
|
||||||
None => {
|
|
||||||
no_square = true;
|
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 = &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 {
|
let product_key = Self {
|
||||||
upgrade,
|
upgrade,
|
||||||
|
@ -223,10 +201,12 @@ impl ProductKey {
|
||||||
|
|
||||||
fn verify(
|
fn verify(
|
||||||
&self,
|
&self,
|
||||||
e_curve: &WeierstrassCurve,
|
e_curve: &EcGroup,
|
||||||
base_point: &Point,
|
base_point: &EcPoint,
|
||||||
public_key: &Point,
|
public_key: &EcPoint,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
|
let mut num_context = BigNumContext::new()?;
|
||||||
|
|
||||||
let data = self.channel_id << 1 | self.upgrade as u32;
|
let data = self.channel_id << 1 | self.upgrade as u32;
|
||||||
|
|
||||||
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
let mut msg_buffer: [u8; SHA_MSG_LENGTH] = [0; SHA_MSG_LENGTH];
|
||||||
|
@ -243,47 +223,39 @@ impl ProductKey {
|
||||||
msg_buffer[0x09] = 0x00;
|
msg_buffer[0x09] = 0x00;
|
||||||
msg_buffer[0x0A] = 0x00;
|
msg_buffer[0x0A] = 0x00;
|
||||||
|
|
||||||
let msg_digest = {
|
let msg_digest = sha1(&msg_buffer[..=0x0A]);
|
||||||
let mut hasher = Sha1::new();
|
|
||||||
hasher.update(&msg_buffer[..=0x0A]);
|
|
||||||
hasher.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
let i_signature = next_sn_bits(by_dword(&msg_digest[4..8]) as u64, 30, 2) << 32
|
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;
|
| by_dword(&msg_digest[0..4]) as u64;
|
||||||
|
|
||||||
let e = BigInt::from(i_signature);
|
let e = BigNum::from_slice(&i_signature.to_be_bytes())?;
|
||||||
let s = BigInt::from(self.signature);
|
let s = BigNum::from_slice(&self.signature.to_be_bytes())?;
|
||||||
|
|
||||||
let t = e_curve.multiply_point(&s, base_point);
|
let mut x = BigNum::new()?;
|
||||||
let mut p = e_curve.multiply_point(&e, public_key);
|
let mut y = BigNum::new()?;
|
||||||
|
|
||||||
p = e_curve.add_points(&t, &p);
|
let mut p = EcPoint::new(e_curve)?;
|
||||||
p = e_curve.multiply_point(&s, &p);
|
let mut t = EcPoint::new(e_curve)?;
|
||||||
|
|
||||||
let (x, y) = match p {
|
t.mul(e_curve, base_point, &s, &num_context)?;
|
||||||
Point::Point { x, y } => (x, y),
|
p.mul(e_curve, public_key, &e, &num_context)?;
|
||||||
Point::Infinity => bail!("Point at infinity!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let x_bin = x.to_bytes_le().1;
|
{
|
||||||
let x_bin = if x_bin.len() < FIELD_BYTES {
|
let p_2 = p.to_owned(e_curve)?;
|
||||||
(0..FIELD_BYTES - x_bin.len())
|
p.add(e_curve, &t, &p_2, &mut num_context)?;
|
||||||
.map(|_| 0)
|
}
|
||||||
.chain(x_bin.into_iter())
|
|
||||||
.collect()
|
{
|
||||||
} else {
|
let p_2 = p.to_owned(e_curve)?;
|
||||||
x_bin
|
p.mul(e_curve, &p_2, &s, &num_context)?;
|
||||||
};
|
}
|
||||||
let y_bin = y.to_bytes_le().1;
|
|
||||||
let y_bin = if y_bin.len() < FIELD_BYTES {
|
p.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
||||||
(0..FIELD_BYTES - y_bin.len())
|
|
||||||
.map(|_| 0)
|
let mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
.chain(y_bin.into_iter())
|
x_bin.reverse();
|
||||||
.collect()
|
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
||||||
} else {
|
y_bin.reverse();
|
||||||
y_bin
|
|
||||||
};
|
|
||||||
|
|
||||||
msg_buffer[0x00] = 0x79;
|
msg_buffer[0x00] = 0x79;
|
||||||
msg_buffer[0x01] = (data & 0x00FF) as u8;
|
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..3 + FIELD_BYTES].copy_from_slice(&x_bin);
|
||||||
msg_buffer[3 + FIELD_BYTES..3 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
msg_buffer[3 + FIELD_BYTES..3 + FIELD_BYTES * 2].copy_from_slice(&y_bin);
|
||||||
|
|
||||||
let msg_digest = {
|
let msg_digest = sha1(&msg_buffer);
|
||||||
let mut hasher = Sha1::new();
|
|
||||||
hasher.update(msg_buffer);
|
|
||||||
hasher.finalize()
|
|
||||||
};
|
|
||||||
|
|
||||||
let hash: u32 = by_dword(&msg_digest[0..4]) & bitmask(31) as u32;
|
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 p = bink["p"].as_str().unwrap();
|
||||||
let a = bink["a"].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 gx = bink["g"]["x"].as_str().unwrap();
|
||||||
let gy = bink["g"]["y"].as_str().unwrap();
|
let gy = bink["g"]["y"].as_str().unwrap();
|
||||||
let kx = bink["pub"]["x"].as_str().unwrap();
|
let kx = bink["pub"]["x"].as_str().unwrap();
|
||||||
let ky = bink["pub"]["y"].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, product_key).is_ok());
|
||||||
assert!(super::ProductKey::from_key(&curve, "11111-YRGC8-4KYTG-C3FCC-JCFDY").is_err());
|
assert!(super::ProductKey::from_key(&curve, "11111-YRGC8-4KYTG-C3FCC-JCFDY").is_err());
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use num_bigint::BigInt;
|
use openssl::{
|
||||||
use num_traits::Num;
|
bn::{BigNum, BigNumContext},
|
||||||
|
ec::{EcGroup, EcPoint},
|
||||||
use crate::weierstrass_curve::{Point, WeierstrassCurve};
|
};
|
||||||
|
|
||||||
pub struct EllipticCurve {
|
pub struct EllipticCurve {
|
||||||
pub curve: WeierstrassCurve,
|
pub curve: EcGroup,
|
||||||
pub gen_point: Point,
|
pub gen_point: EcPoint,
|
||||||
pub pub_point: Point,
|
pub pub_point: EcPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PrivateKey {
|
pub struct PrivateKey {
|
||||||
pub gen_order: BigInt,
|
pub gen_order: BigNum,
|
||||||
pub private_key: BigInt,
|
pub private_key: BigNum,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrivateKey {
|
impl PrivateKey {
|
||||||
pub fn new(gen_order: &str, private_key: &str) -> Result<Self> {
|
pub fn new(gen_order: &str, private_key: &str) -> Result<Self> {
|
||||||
let gen_order = BigInt::from_str_radix(gen_order, 10)?;
|
let gen_order = BigNum::from_dec_str(gen_order)?;
|
||||||
let private_key = BigInt::from_str_radix(private_key, 10)?;
|
let private_key = &gen_order - &BigNum::from_dec_str(private_key)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
gen_order,
|
gen_order,
|
||||||
private_key,
|
private_key,
|
||||||
|
@ -30,29 +30,29 @@ impl EllipticCurve {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
p: &str,
|
p: &str,
|
||||||
a: &str,
|
a: &str,
|
||||||
|
b: &str,
|
||||||
generator_x: &str,
|
generator_x: &str,
|
||||||
generator_y: &str,
|
generator_y: &str,
|
||||||
public_key_x: &str,
|
public_key_x: &str,
|
||||||
public_key_y: &str,
|
public_key_y: &str,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let p = BigInt::from_str_radix(p, 10)?;
|
let mut context = BigNumContext::new()?;
|
||||||
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 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 {
|
let curve = EcGroup::from_components(p, a, b, &mut context)?;
|
||||||
x: generator_x,
|
|
||||||
y: generator_y,
|
|
||||||
};
|
|
||||||
|
|
||||||
let pub_point = Point::Point {
|
let mut gen_point = EcPoint::new(&curve)?;
|
||||||
x: public_key_x,
|
gen_point.set_affine_coordinates_gfp(&curve, &generator_x, &generator_y, &mut context)?;
|
||||||
y: public_key_y,
|
|
||||||
};
|
let mut pub_point = EcPoint::new(&curve)?;
|
||||||
|
pub_point.set_affine_coordinates_gfp(&curve, &public_key_x, &public_key_y, &mut context)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
curve,
|
curve,
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use num_bigint::{BigInt, Sign};
|
use openssl::bn::BigNum;
|
||||||
use num_integer::Integer;
|
|
||||||
use num_traits::{ToPrimitive, Zero};
|
|
||||||
|
|
||||||
const PK_LENGTH: usize = 25;
|
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))
|
.filter_map(|c| KEY_CHARSET.iter().position(|&x| x == c).map(|i| i as u8))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut y = BigInt::zero();
|
let mut y = BigNum::from_u32(0).unwrap();
|
||||||
|
|
||||||
for i in decoded_key {
|
for i in decoded_key {
|
||||||
y *= PK_LENGTH - 1;
|
y.mul_word((PK_LENGTH - 1) as u32).unwrap();
|
||||||
y += i as u32;
|
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> {
|
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();
|
let mut out: VecDeque<char> = VecDeque::new();
|
||||||
(0..=24).for_each(|_| {
|
(0..=24).for_each(|_| out.push_front(KEY_CHARSET[z.div_word(24).unwrap() as usize]));
|
||||||
let (quo, rem) = z.div_rem(&BigInt::from(24));
|
|
||||||
z = quo;
|
|
||||||
out.push_front(KEY_CHARSET[rem.to_u32().unwrap() as usize]);
|
|
||||||
});
|
|
||||||
Ok(out.iter().collect())
|
Ok(out.iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,5 +4,3 @@ pub mod confid;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
mod key;
|
mod key;
|
||||||
mod math;
|
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> {
|
fn initialize_curve(bink: &Bink, bink_id: &str) -> Result<EllipticCurve> {
|
||||||
let p = &bink.p;
|
let p = &bink.p;
|
||||||
let a = &bink.a;
|
let a = &bink.a;
|
||||||
|
let b = &bink.b;
|
||||||
let gx = &bink.g.x;
|
let gx = &bink.g.x;
|
||||||
let gy = &bink.g.y;
|
let gy = &bink.g.y;
|
||||||
let kx = &bink.public.x;
|
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}");
|
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(
|
fn bink1998_generate(
|
||||||
|
|
Loading…
Add table
Reference in a new issue