WIP: Replace OpenSSL with custom implementations
This commit is contained in:
parent
8dc063e4e5
commit
c2995d9399
9 changed files with 653 additions and 172 deletions
241
Cargo.lock
generated
241
Cargo.lock
generated
|
@ -57,6 +57,18 @@ 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"
|
||||||
|
@ -72,6 +84,15 @@ 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"
|
||||||
|
@ -132,6 +153,63 @@ 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"
|
||||||
|
@ -153,6 +231,16 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -168,6 +256,39 @@ 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 = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
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",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -227,6 +348,37 @@ 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"
|
||||||
|
@ -236,7 +388,7 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.55"
|
version = "0.10.55"
|
||||||
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
|
source = "git+https://github.com/sfackler/rust-openssl#8909d3e20682f2f3a3928b53a7cc1ebb118cf19d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@ -250,7 +402,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-macros"
|
name = "openssl-macros"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
|
source = "git+https://github.com/sfackler/rust-openssl#8909d3e20682f2f3a3928b53a7cc1ebb118cf19d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -260,7 +412,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.90"
|
version = "0.9.90"
|
||||||
source = "git+https://github.com/sfackler/rust-openssl#9d180ec94a92d2d08d6463ad047d9d7e7a8d9561"
|
source = "git+https://github.com/sfackler/rust-openssl#8909d3e20682f2f3a3928b53a7cc1ebb118cf19d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -274,6 +426,12 @@ 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 = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.61"
|
version = "1.0.61"
|
||||||
|
@ -292,6 +450,36 @@ 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"
|
||||||
|
@ -343,6 +531,17 @@ 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"
|
||||||
|
@ -359,6 +558,12 @@ 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"
|
||||||
|
@ -390,14 +595,26 @@ 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",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
"openssl",
|
"openssl",
|
||||||
|
"rand",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha1",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -419,6 +636,18 @@ 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 = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
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"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
|
@ -554,3 +783,9 @@ 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,4 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"umskt",
|
"umskt",
|
||||||
|
|
|
@ -6,7 +6,13 @@ 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"
|
||||||
|
num-bigint = { version = "0.4.3", features = ["rand"] }
|
||||||
|
num-integer = "0.1.45"
|
||||||
|
num-traits = "0.2.15"
|
||||||
openssl = { git = "https://github.com/sfackler/rust-openssl" }
|
openssl = { git = "https://github.com/sfackler/rust-openssl" }
|
||||||
|
rand = "0.8.5"
|
||||||
|
sha1 = "0.10.5"
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.40"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
use std::fmt::{Display, Formatter};
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use bitreader::BitReader;
|
use bitreader::BitReader;
|
||||||
use openssl::{
|
use num_bigint::{BigInt, BigUint, RandomBits};
|
||||||
bn::{BigNum, BigNumContext, MsbOption},
|
use num_integer::Integer;
|
||||||
ec::{EcGroup, EcPoint},
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
sha::sha1,
|
use rand::Rng;
|
||||||
};
|
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: i32 = 384;
|
const FIELD_BITS: u64 = 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;
|
||||||
|
|
||||||
|
@ -44,10 +48,10 @@ impl ProductKey {
|
||||||
let sequence = match sequence {
|
let sequence = match sequence {
|
||||||
Some(serial) => serial,
|
Some(serial) => serial,
|
||||||
None => {
|
None => {
|
||||||
let mut bn_rand = BigNum::new()?;
|
let mut rng = rand::thread_rng();
|
||||||
bn_rand.rand(19, MsbOption::MAYBE_ZERO, false)?;
|
let random: BigInt = rng.sample(RandomBits::new(32));
|
||||||
let o_raw = u32::from_be_bytes(bn_rand.to_vec_padded(4)?.try_into().unwrap());
|
let raw = u32::from_be_bytes(random.to_bytes_be().1[0..4].try_into().unwrap());
|
||||||
o_raw % 999999
|
raw % 999999
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,62 +87,75 @@ impl ProductKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate(
|
fn generate(
|
||||||
e_curve: &EcGroup,
|
e_curve: &WeierstrassCurve,
|
||||||
base_point: &EcPoint,
|
base_point: &Point,
|
||||||
gen_order: &BigNum,
|
gen_order: &BigInt,
|
||||||
private_key: &BigNum,
|
private_key: &BigInt,
|
||||||
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 product_key = loop {
|
let mut rng = rand::thread_rng();
|
||||||
let mut r = EcPoint::new(e_curve)?;
|
|
||||||
|
|
||||||
|
let product_key = loop {
|
||||||
// Generate a random number c consisting of 384 bits without any constraints.
|
// Generate a random number c consisting of 384 bits without any constraints.
|
||||||
c.rand(FIELD_BITS, MsbOption::MAYBE_ZERO, false)?;
|
let c: BigUint = rng.sample(RandomBits::new(FIELD_BITS));
|
||||||
|
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;
|
||||||
r.mul(e_curve, base_point, &c, &num_context)?;
|
let r = e_curve.multiply_point(&c, base_point);
|
||||||
|
|
||||||
// Acquire its coordinates.
|
// Acquire its coordinates.
|
||||||
// x = R.x; y = R.y;
|
// x = R.x; y = R.y;
|
||||||
r.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
let (x, y) = match r {
|
||||||
|
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 mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
let x_bin = x.to_signed_bytes_le();
|
||||||
x_bin.reverse();
|
let x_bin = match x_bin.len().cmp(&FIELD_BYTES) {
|
||||||
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
Ordering::Less => (0..FIELD_BYTES - x_bin.len() - 1)
|
||||||
y_bin.reverse();
|
.map(|_| 0)
|
||||||
|
.chain(x_bin.into_iter())
|
||||||
|
.collect(),
|
||||||
|
Ordering::Greater => continue,
|
||||||
|
Ordering::Equal => x_bin,
|
||||||
|
};
|
||||||
|
let y_bin = y.to_signed_bytes_le();
|
||||||
|
let y_bin = match y_bin.len().cmp(&FIELD_BYTES) {
|
||||||
|
Ordering::Less => (0..FIELD_BYTES - y_bin.len() - 1)
|
||||||
|
.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 = sha1(&msg_buffer);
|
let msg_digest = {
|
||||||
|
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;
|
||||||
|
|
||||||
ek = (*private_key).to_owned()?;
|
let mut ek = private_key.clone();
|
||||||
ek.mul_word(hash)?;
|
ek *= hash;
|
||||||
|
|
||||||
s.mod_add(&ek, &c, gen_order, &mut num_context)?;
|
let s = (ek + c).mod_floor(gen_order);
|
||||||
|
|
||||||
let signature = u64::from_be_bytes(s.to_vec_padded(8)?.try_into().unwrap());
|
let signature = s.to_u64().unwrap_or(0);
|
||||||
|
|
||||||
if signature <= bitmask(55) {
|
if signature <= bitmask(55) {
|
||||||
break Self {
|
break Self {
|
||||||
|
@ -156,36 +173,43 @@ impl ProductKey {
|
||||||
|
|
||||||
fn verify(
|
fn verify(
|
||||||
&self,
|
&self,
|
||||||
e_curve: &EcGroup,
|
e_curve: &WeierstrassCurve,
|
||||||
base_point: &EcPoint,
|
base_point: &Point,
|
||||||
public_key: &EcPoint,
|
public_key: &Point,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let mut ctx = BigNumContext::new()?;
|
let e = BigInt::from_u32(self.hash).unwrap();
|
||||||
|
let s = BigInt::from_u64(self.signature).unwrap();
|
||||||
|
|
||||||
let e = BigNum::from_u32(self.hash)?;
|
let t = e_curve.multiply_point(&s, base_point);
|
||||||
let s = BigNum::from_slice(&self.signature.to_be_bytes())?;
|
let mut p = e_curve.multiply_point(&e, public_key);
|
||||||
let mut x = BigNum::new()?;
|
|
||||||
let mut y = BigNum::new()?;
|
|
||||||
|
|
||||||
let mut t = EcPoint::new(e_curve)?;
|
p = e_curve.add_points(&p, &t);
|
||||||
let mut p = EcPoint::new(e_curve)?;
|
|
||||||
|
|
||||||
t.mul(e_curve, base_point, &s, &ctx)?;
|
let (x, y) = match p {
|
||||||
p.mul(e_curve, public_key, &e, &ctx)?;
|
Point::Point { x, y } => (x, y),
|
||||||
|
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 mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
let x_bin = x.to_signed_bytes_le();
|
||||||
x_bin.reverse();
|
let x_bin = if x_bin.len() < FIELD_BYTES {
|
||||||
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
(0..FIELD_BYTES - x_bin.len() - 1)
|
||||||
y_bin.reverse();
|
.map(|_| 0)
|
||||||
|
.chain(x_bin.into_iter())
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
x_bin
|
||||||
|
};
|
||||||
|
let y_bin = y.to_signed_bytes_le();
|
||||||
|
let y_bin = if y_bin.len() < FIELD_BYTES {
|
||||||
|
(0..FIELD_BYTES - y_bin.len() - 1)
|
||||||
|
.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;
|
||||||
|
@ -194,7 +218,11 @@ 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 = sha1(&msg_buffer);
|
let msg_digest = {
|
||||||
|
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;
|
||||||
|
@ -265,7 +293,7 @@ mod tests {
|
||||||
|
|
||||||
use serde_json::from_reader;
|
use serde_json::from_reader;
|
||||||
|
|
||||||
use crate::crypto::EllipticCurve;
|
use crate::{bink1998, crypto::EllipticCurve};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_test() {
|
fn verify_test() {
|
||||||
|
@ -291,8 +319,8 @@ mod tests {
|
||||||
|
|
||||||
let curve = EllipticCurve::new(p, a, b, 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!(bink1998::ProductKey::from_key(&curve, product_key).is_ok());
|
||||||
assert!(super::ProductKey::from_key(&curve, "11111-R6BG2-39J83-RYKHF-W47TT").is_err());
|
assert!(bink1998::ProductKey::from_key(&curve, "11111-R6BG2-39J83-RYKHF-W47TT").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
use std::fmt::{Display, Formatter};
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use bitreader::BitReader;
|
use bitreader::BitReader;
|
||||||
use openssl::{
|
use num_bigint::{BigInt, BigUint, RandomBits};
|
||||||
bn::{BigNum, BigNumContext, MsbOption},
|
use num_integer::Integer;
|
||||||
ec::{EcGroup, EcPoint},
|
use num_traits::ToPrimitive;
|
||||||
rand::rand_bytes,
|
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, by_dword, next_sn_bits},
|
math::{bitmask, by_dword, next_sn_bits},
|
||||||
|
msr::mod_sqrt,
|
||||||
|
weierstrass_curve::{Point, WeierstrassCurve},
|
||||||
};
|
};
|
||||||
|
|
||||||
const FIELD_BITS: i32 = 512;
|
const FIELD_BITS: u64 = 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;
|
||||||
|
|
||||||
|
@ -47,9 +51,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 auth_info_bytes = [0_u8; 4];
|
let mut rng = rand::thread_rng();
|
||||||
rand_bytes(&mut auth_info_bytes)?;
|
let random: BigInt = rng.sample(RandomBits::new(32));
|
||||||
u32::from_ne_bytes(auth_info_bytes) & ((1 << 10) - 1)
|
u32::from_be_bytes(random.to_bytes_be().1[0..4].try_into().unwrap())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,38 +92,50 @@ impl ProductKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate(
|
fn generate(
|
||||||
e_curve: &EcGroup,
|
e_curve: &WeierstrassCurve,
|
||||||
base_point: &EcPoint,
|
base_point: &Point,
|
||||||
gen_order: &BigNum,
|
gen_order: &BigInt,
|
||||||
private_key: &BigNum,
|
private_key: &BigInt,
|
||||||
channel_id: u32,
|
channel_id: u32,
|
||||||
auth_info: u32,
|
auth_info: u32,
|
||||||
upgrade: bool,
|
upgrade: bool,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let mut num_context = BigNumContext::new().unwrap();
|
|
||||||
|
|
||||||
let mut c = BigNum::new()?;
|
|
||||||
let mut x = BigNum::new()?;
|
|
||||||
let mut y = BigNum::new()?;
|
|
||||||
|
|
||||||
let data = channel_id << 1 | upgrade as u32;
|
let data = channel_id << 1 | upgrade as u32;
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
let mut no_square = false;
|
let mut no_square = false;
|
||||||
let key = loop {
|
let key = loop {
|
||||||
let mut r = EcPoint::new(e_curve)?;
|
let c: BigUint = rng.sample(RandomBits::new(FIELD_BITS));
|
||||||
|
let mut c: BigInt = c.into();
|
||||||
|
|
||||||
c.rand(FIELD_BITS, MsbOption::MAYBE_ZERO, false)?;
|
let r = e_curve.multiply_point(&c, base_point);
|
||||||
|
|
||||||
r.mul(e_curve, base_point, &c, &num_context)?;
|
let (x, y) = match r {
|
||||||
|
Point::Point { x, y } => (x, y),
|
||||||
r.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
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 mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
let x_bin = x.to_signed_bytes_le();
|
||||||
x_bin.reverse();
|
let x_bin = match x_bin.len().cmp(&FIELD_BYTES) {
|
||||||
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
Ordering::Less => (0..FIELD_BYTES - x_bin.len() - 1)
|
||||||
y_bin.reverse();
|
.map(|_| 0)
|
||||||
|
.chain(x_bin.into_iter())
|
||||||
|
.collect(),
|
||||||
|
Ordering::Greater => continue,
|
||||||
|
Ordering::Equal => x_bin,
|
||||||
|
};
|
||||||
|
let y_bin = y.to_signed_bytes_le();
|
||||||
|
let y_bin = match y_bin.len().cmp(&FIELD_BYTES) {
|
||||||
|
Ordering::Less => (0..FIELD_BYTES - y_bin.len() - 1)
|
||||||
|
.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;
|
||||||
|
@ -128,7 +144,11 @@ 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 = sha1(&msg_buffer);
|
let msg_digest = {
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -144,42 +164,40 @@ impl ProductKey {
|
||||||
msg_buffer[0x09] = 0x00;
|
msg_buffer[0x09] = 0x00;
|
||||||
msg_buffer[0x0A] = 0x00;
|
msg_buffer[0x0A] = 0x00;
|
||||||
|
|
||||||
let msg_digest = sha1(&msg_buffer[..=0x0A]);
|
let msg_digest = {
|
||||||
|
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 = BigNum::from_slice(&i_signature.to_be_bytes())?;
|
let mut e = BigInt::from(i_signature);
|
||||||
|
|
||||||
let e_2 = e.to_owned()?;
|
e = (e * private_key).mod_floor(gen_order);
|
||||||
e.mod_mul(&e_2, private_key, gen_order, &mut num_context)?;
|
|
||||||
|
|
||||||
let mut s = e.to_owned()?;
|
let mut s = e.clone();
|
||||||
|
|
||||||
let s_2 = s.to_owned()?;
|
s = (&s * &s).mod_floor(gen_order);
|
||||||
s.mod_sqr(&s_2, gen_order, &mut num_context)?;
|
|
||||||
|
|
||||||
let c_2 = c.to_owned()?;
|
c <<= 2;
|
||||||
c.lshift(&c_2, 2)?;
|
|
||||||
|
|
||||||
s = &s + &c;
|
s = &s + &c;
|
||||||
|
|
||||||
let s_2 = s.to_owned()?;
|
if mod_sqrt(&s, gen_order).is_none() {
|
||||||
if s.mod_sqrt(&s_2, gen_order, &mut num_context).is_err() {
|
|
||||||
no_square = true;
|
no_square = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
let s_2 = s.to_owned()?;
|
s = (s - e).mod_floor(gen_order);
|
||||||
s.mod_sub(&s_2, &e, gen_order, &mut num_context)?;
|
|
||||||
|
|
||||||
if s.is_bit_set(0) {
|
if s.is_odd() {
|
||||||
s = &s + gen_order;
|
s = &s + gen_order;
|
||||||
}
|
}
|
||||||
|
|
||||||
let s_2 = s.to_owned()?;
|
s >>= 1;
|
||||||
s.rshift1(&s_2)?;
|
|
||||||
|
|
||||||
let signature = u64::from_be_bytes(s.to_vec_padded(8)?.try_into().unwrap());
|
let signature = s.to_u64().unwrap_or(0);
|
||||||
|
|
||||||
let product_key = Self {
|
let product_key = Self {
|
||||||
upgrade,
|
upgrade,
|
||||||
|
@ -201,12 +219,10 @@ impl ProductKey {
|
||||||
|
|
||||||
fn verify(
|
fn verify(
|
||||||
&self,
|
&self,
|
||||||
e_curve: &EcGroup,
|
e_curve: &WeierstrassCurve,
|
||||||
base_point: &EcPoint,
|
base_point: &Point,
|
||||||
public_key: &EcPoint,
|
public_key: &Point,
|
||||||
) -> 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];
|
||||||
|
@ -223,39 +239,47 @@ impl ProductKey {
|
||||||
msg_buffer[0x09] = 0x00;
|
msg_buffer[0x09] = 0x00;
|
||||||
msg_buffer[0x0A] = 0x00;
|
msg_buffer[0x0A] = 0x00;
|
||||||
|
|
||||||
let msg_digest = sha1(&msg_buffer[..=0x0A]);
|
let msg_digest = {
|
||||||
|
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 = BigNum::from_slice(&i_signature.to_be_bytes())?;
|
let e = BigInt::from(i_signature);
|
||||||
let s = BigNum::from_slice(&self.signature.to_be_bytes())?;
|
let s = BigInt::from(self.signature);
|
||||||
|
|
||||||
let mut x = BigNum::new()?;
|
let t = e_curve.multiply_point(&s, base_point);
|
||||||
let mut y = BigNum::new()?;
|
let mut p = e_curve.multiply_point(&e, public_key);
|
||||||
|
|
||||||
let mut p = EcPoint::new(e_curve)?;
|
p = e_curve.add_points(&t, &p);
|
||||||
let mut t = EcPoint::new(e_curve)?;
|
p = e_curve.multiply_point(&s, &p);
|
||||||
|
|
||||||
t.mul(e_curve, base_point, &s, &num_context)?;
|
let (x, y) = match p {
|
||||||
p.mul(e_curve, public_key, &e, &num_context)?;
|
Point::Point { x, y } => (x, y),
|
||||||
|
Point::Infinity => bail!("Point at infinity!"),
|
||||||
|
};
|
||||||
|
|
||||||
{
|
let x_bin = x.to_signed_bytes_le();
|
||||||
let p_2 = p.to_owned(e_curve)?;
|
let x_bin = if x_bin.len() < FIELD_BYTES {
|
||||||
p.add(e_curve, &t, &p_2, &mut num_context)?;
|
(0..FIELD_BYTES - x_bin.len() - 1)
|
||||||
}
|
.map(|_| 0)
|
||||||
|
.chain(x_bin.into_iter())
|
||||||
{
|
.collect()
|
||||||
let p_2 = p.to_owned(e_curve)?;
|
} else {
|
||||||
p.mul(e_curve, &p_2, &s, &num_context)?;
|
x_bin
|
||||||
}
|
};
|
||||||
|
let y_bin = y.to_signed_bytes_le();
|
||||||
p.affine_coordinates(e_curve, &mut x, &mut y, &mut num_context)?;
|
let y_bin = if y_bin.len() < FIELD_BYTES {
|
||||||
|
(0..FIELD_BYTES - y_bin.len() - 1)
|
||||||
let mut x_bin = x.to_vec_padded(FIELD_BYTES as i32)?;
|
.map(|_| 0)
|
||||||
x_bin.reverse();
|
.chain(y_bin.into_iter())
|
||||||
let mut y_bin = y.to_vec_padded(FIELD_BYTES as i32)?;
|
.collect()
|
||||||
y_bin.reverse();
|
} else {
|
||||||
|
y_bin
|
||||||
|
};
|
||||||
|
|
||||||
msg_buffer[0x00] = 0x79;
|
msg_buffer[0x00] = 0x79;
|
||||||
msg_buffer[0x01] = (data & 0x00FF) as u8;
|
msg_buffer[0x01] = (data & 0x00FF) as u8;
|
||||||
|
@ -264,7 +288,11 @@ 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 = sha1(&msg_buffer);
|
let msg_digest = {
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use openssl::{
|
use num_bigint::BigInt;
|
||||||
bn::{BigNum, BigNumContext},
|
use num_traits::Num;
|
||||||
ec::{EcGroup, EcPoint},
|
|
||||||
};
|
use crate::weierstrass_curve::{Point, WeierstrassCurve};
|
||||||
|
|
||||||
pub struct EllipticCurve {
|
pub struct EllipticCurve {
|
||||||
pub curve: EcGroup,
|
pub curve: WeierstrassCurve,
|
||||||
pub gen_point: EcPoint,
|
pub gen_point: Point,
|
||||||
pub pub_point: EcPoint,
|
pub pub_point: Point,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PrivateKey {
|
pub struct PrivateKey {
|
||||||
pub gen_order: BigNum,
|
pub gen_order: BigInt,
|
||||||
pub private_key: BigNum,
|
pub private_key: BigInt,
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = BigNum::from_dec_str(gen_order)?;
|
let gen_order = BigInt::from_str_radix(gen_order, 10)?;
|
||||||
let private_key = &gen_order - &BigNum::from_dec_str(private_key)?;
|
let private_key = &gen_order - &BigInt::from_str_radix(private_key, 10)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
gen_order,
|
gen_order,
|
||||||
private_key,
|
private_key,
|
||||||
|
@ -36,23 +36,25 @@ impl EllipticCurve {
|
||||||
public_key_x: &str,
|
public_key_x: &str,
|
||||||
public_key_y: &str,
|
public_key_y: &str,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let mut context = BigNumContext::new()?;
|
let p = BigInt::from_str_radix(p, 10)?;
|
||||||
|
let a = BigInt::from_str_radix(a, 10)?;
|
||||||
|
let b = BigInt::from_str_radix(b, 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 p = BigNum::from_dec_str(p)?;
|
let curve = WeierstrassCurve::new(a, b, 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 curve = EcGroup::from_components(p, a, b, &mut context)?;
|
let gen_point = Point::Point {
|
||||||
|
x: generator_x,
|
||||||
|
y: generator_y,
|
||||||
|
};
|
||||||
|
|
||||||
let mut gen_point = EcPoint::new(&curve)?;
|
let pub_point = Point::Point {
|
||||||
gen_point.set_affine_coordinates_gfp(&curve, &generator_x, &generator_y, &mut context)?;
|
x: public_key_x,
|
||||||
|
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,
|
||||||
|
|
|
@ -4,3 +4,5 @@ pub mod confid;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
mod key;
|
mod key;
|
||||||
mod math;
|
mod math;
|
||||||
|
mod msr;
|
||||||
|
mod weierstrass_curve;
|
||||||
|
|
90
umskt/src/msr.rs
Normal file
90
umskt/src/msr.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use openssl::bn::{BigNum, BigNumContext};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let n = "1573769205219068003359487454943505465350185201622247106224183162699789934914421854093895861489537435530695722027283028984396996570717144433549421890648379";
|
||||||
|
let p = "5622613991231344109";
|
||||||
|
|
||||||
|
{
|
||||||
|
let n = num_bigint::BigInt::parse_bytes(n.as_bytes(), 10).unwrap();
|
||||||
|
let p = num_bigint::BigInt::parse_bytes(p.as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
|
let r = super::mod_sqrt(&n, &p).unwrap();
|
||||||
|
dbg!(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut ctx = BigNumContext::new().unwrap();
|
||||||
|
let n = BigNum::from_dec_str(n).unwrap();
|
||||||
|
let p = BigNum::from_dec_str(p).unwrap();
|
||||||
|
|
||||||
|
let mut r = BigNum::new().unwrap();
|
||||||
|
r.mod_sqrt(&n, &p, &mut ctx).unwrap();
|
||||||
|
dbg!(r.to_dec_str().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
umskt/src/weierstrass_curve.rs
Normal file
89
umskt/src/weierstrass_curve.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
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,
|
||||||
|
b: BigInt,
|
||||||
|
p: BigInt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WeierstrassCurve {
|
||||||
|
pub fn new(a: BigInt, b: BigInt, p: BigInt) -> Self {
|
||||||
|
WeierstrassCurve { a, b, 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue