From cb557c1ed8f16d68807785d46e7dcfdba03176b5 Mon Sep 17 00:00:00 2001 From: Neo-Desktop <321592+Neo-Desktop@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:17:32 -0800 Subject: [PATCH] Fix PIDGEN3 --- src/cli.cpp | 14 ++++---- src/libumskt/libumskt.h | 5 +-- src/libumskt/pidgen3/BINK1998.cpp | 33 +++++++++-------- src/libumskt/pidgen3/BINK2002.cpp | 60 ++++++++++++++----------------- src/libumskt/pidgen3/PIDGEN3.cpp | 13 ++++++- src/libumskt/pidgen3/PIDGEN3.h | 10 +++--- 6 files changed, 69 insertions(+), 66 deletions(-) diff --git a/src/cli.cpp b/src/cli.cpp index 686da67..7c35e88 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -402,7 +402,7 @@ BOOL CLI::BINK1998Generate() if (isValid) { printKey(pKey); - if (i < total - 1 || options.verbose) + if (i <= total - 1 || options.verbose) { fmt::print("\n"); } @@ -414,7 +414,7 @@ BOOL CLI::BINK1998Generate() { printKey(pKey); fmt::print(" [Invalid]"); - if (i < total - 1) + if (i <= total - 1) { fmt::print("\n"); } @@ -443,13 +443,11 @@ BOOL CLI::BINK2002Generate() // generate a key for (int i = 0; i < total; i++) { - DWORD pAuthInfo; - RAND_bytes((BYTE *)&pAuthInfo, 4); - pAuthInfo &= BITMASK(10); + options.info.AuthInfo = UMSKT::getRandom() & BITMASK(10); if (options.verbose) { - fmt::print("> AuthInfo: {}\n", pAuthInfo); + fmt::print("> AuthInfo: {:#08x}\n", options.info.AuthInfo); } bink2002.Generate(options.info, pKey); @@ -458,7 +456,7 @@ BOOL CLI::BINK2002Generate() if (isValid) { CLI::printKey(pKey); - if (i < total - 1 || options.verbose) + if (i <= total - 1 || options.verbose) { // check if end of list or verbose fmt::print("\n"); } @@ -470,7 +468,7 @@ BOOL CLI::BINK2002Generate() { CLI::printKey(pKey); // print the key fmt::print(" [Invalid]"); // and add " [Invalid]" to the key - if (i < this->total - 1) + if (i <= total - 1) { // check if end of list fmt::print("\n"); } diff --git a/src/libumskt/libumskt.h b/src/libumskt/libumskt.h index e1426ba..e6c9bad 100644 --- a/src/libumskt/libumskt.h +++ b/src/libumskt/libumskt.h @@ -76,10 +76,7 @@ class UMSKT template static T getRandom() { T retval; - BIGNUM *bnrand = BN_new(); - BN_rand(bnrand, sizeof(T) * 8, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); - BN_bn2lebinpad(bnrand, (unsigned char *)&retval, sizeof(T)); - BN_free(bnrand); + RAND_bytes((BYTE *)&retval, sizeof(retval)); return retval; } }; diff --git a/src/libumskt/pidgen3/BINK1998.cpp b/src/libumskt/pidgen3/BINK1998.cpp index fb31c0b..2d2abaa 100644 --- a/src/libumskt/pidgen3/BINK1998.cpp +++ b/src/libumskt/pidgen3/BINK1998.cpp @@ -98,10 +98,10 @@ BOOL BINK1998::Verify(std::string &pKey) Unpack(info, pRaw); fmt::print(UMSKT::debug, "Validation results:\n"); - fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", info.isUpgrade); - fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", info.Serial); - fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", info.Hash); - fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", info.Signature); + fmt::print(UMSKT::debug, " Upgrade: {:#08x}\n", info.isUpgrade); + fmt::print(UMSKT::debug, " Serial: {:#08x}\n", info.Serial); + fmt::print(UMSKT::debug, " Hash: {:#08x}\n", info.Hash); + fmt::print(UMSKT::debug, " Signature: {:#08x}\n", info.Signature); fmt::print(UMSKT::debug, "\n"); DWORD pData = info.Serial << 1 | info.isUpgrade; @@ -122,7 +122,7 @@ BOOL BINK1998::Verify(std::string &pKey) */ BIGNUM *e = BN_lebin2bn((BYTE *)&info.Hash, sizeof(info.Hash), nullptr), - *s = BN_lebin2bn((BYTE *)&info.Hash, sizeof(info.Hash), nullptr); + *s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr); BIGNUM *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext); @@ -130,10 +130,10 @@ BOOL BINK1998::Verify(std::string &pKey) EC_POINT *t = EC_POINT_new(eCurve), *p = EC_POINT_new(eCurve); // t = sG - EC_POINT_mul(eCurve, t, nullptr, basePoint, s, numContext); + EC_POINT_mul(eCurve, t, nullptr, genPoint, s, numContext); // P = eK - EC_POINT_mul(eCurve, p, nullptr, publicKey, e, numContext); + EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, numContext); // P += t EC_POINT_add(eCurve, p, t, p, numContext); @@ -185,11 +185,14 @@ BOOL BINK1998::Generate(KeyInfo &info, std::string &pKey) BIGNUM *c = BN_CTX_get(numContext), *s = BN_CTX_get(numContext), *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext); - QWORD pRaw[2]{}; + QWORD pRaw[2]; // Data segment of the RPK. DWORD pData = info.Serial << 1 | info.isUpgrade; + // prepare the private key for generation + BN_sub(privateKey, genOrder, privateKey); + do { EC_POINT *r = EC_POINT_new(eCurve); @@ -199,14 +202,14 @@ BOOL BINK1998::Generate(KeyInfo &info, std::string &pKey) // Pick a random derivative of the base point on the elliptic curve. // R = cG; - EC_POINT_mul(eCurve, r, nullptr, basePoint, c, numContext); + EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext); // Acquire its coordinates. // x = R.x; y = R.y; EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext); - BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_XP]{}; - BYTE xBin[FIELD_BYTES]{}, yBin[FIELD_BYTES]{}; + BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_XP]; + BYTE xBin[FIELD_BYTES], yBin[FIELD_BYTES]; // Convert coordinates to bytes. BN_bn2lebin(x, xBin, FIELD_BYTES); @@ -257,10 +260,10 @@ BOOL BINK1998::Generate(KeyInfo &info, std::string &pKey) Pack(info, pRaw); fmt::print(UMSKT::debug, "Generation results:\n"); - fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", info.isUpgrade); - fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", info.Serial); - fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", info.Hash); - fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", info.Signature); + fmt::print(UMSKT::debug, " Upgrade: {:#08x}\n", info.isUpgrade); + fmt::print(UMSKT::debug, " Serial: {:#08x}\n", info.Serial); + fmt::print(UMSKT::debug, " Hash: {:#08x}\n", info.Hash); + fmt::print(UMSKT::debug, " Signature: {:#08x}\n", info.Signature); fmt::print(UMSKT::debug, "\n"); EC_POINT_free(r); diff --git a/src/libumskt/pidgen3/BINK2002.cpp b/src/libumskt/pidgen3/BINK2002.cpp index a164d15..f3a5fa1 100644 --- a/src/libumskt/pidgen3/BINK2002.cpp +++ b/src/libumskt/pidgen3/BINK2002.cpp @@ -86,7 +86,7 @@ BOOL BINK2002::Verify(std::string &pKey) QWORD bKey[2]; // Convert Base24 CD-key to bytecode. - unbase24((BYTE *)bKey, pKey.c_str()); + unbase24((BYTE *)bKey, &pKey[0]); // Extract product key segments from bytecode. Unpack(info, bKey); @@ -101,8 +101,7 @@ BOOL BINK2002::Verify(std::string &pKey) fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", info.AuthInfo); fmt::print(UMSKT::debug, "\n"); - BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_2003]{}, xBin[FIELD_BYTES_2003]{}, - yBin[FIELD_BYTES_2003]{}; + BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_2003], xBin[FIELD_BYTES_2003], yBin[FIELD_BYTES_2003]; // Assemble the first SHA message. msgBuffer[0x00] = 0x5D; @@ -141,16 +140,17 @@ BOOL BINK2002::Verify(std::string &pKey) */ BIGNUM *e = BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), nullptr), - *s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr), *x = BN_new(), *y = BN_new(); + *s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr); + BIGNUM *x = BN_CTX_get(context), *y = BN_CTX_get(context); // Create 2 points on the elliptic curve. EC_POINT *p = EC_POINT_new(eCurve), *t = EC_POINT_new(eCurve); // t = sG - EC_POINT_mul(eCurve, t, nullptr, basePoint, s, context); + EC_POINT_mul(eCurve, t, nullptr, genPoint, s, context); // p = eK - EC_POINT_mul(eCurve, p, nullptr, publicKey, e, context); + EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, context); // p += t EC_POINT_add(eCurve, p, t, p, context); @@ -182,14 +182,12 @@ BOOL BINK2002::Verify(std::string &pKey) BN_free(s); BN_free(e); - BN_free(x); - BN_free(y); - - BN_CTX_free(context); EC_POINT_free(p); EC_POINT_free(t); + BN_CTX_free(context); + // If the computed hash checks out, the key is valid. return compHash == info.Hash; } @@ -199,9 +197,10 @@ BOOL BINK2002::Generate(KeyInfo &info, std::string &pKey) { BN_CTX *numContext = BN_CTX_new(); - BIGNUM *c = BN_new(), *e = BN_new(), *s = BN_new(), *x = BN_new(), *y = BN_new(); + BIGNUM *c = BN_CTX_get(numContext), *e = BN_CTX_get(numContext), *s = BN_CTX_get(numContext), + *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext); - QWORD pRaw[2]{}; + QWORD pRaw[2]; // Data segment of the RPK. DWORD pData = info.ChannelID << 1 | info.isUpgrade; @@ -216,14 +215,14 @@ BOOL BINK2002::Generate(KeyInfo &info, std::string &pKey) BN_rand(c, FIELD_BITS_2003, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); // R = cG - EC_POINT_mul(eCurve, r, nullptr, basePoint, c, numContext); + EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext); // Acquire its coordinates. // x = R.x; y = R.y; EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext); - BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_2003]{}, xBin[FIELD_BYTES_2003]{}, - yBin[FIELD_BYTES_2003]{}; + BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_2003], xBin[FIELD_BYTES_2003], + yBin[FIELD_BYTES_2003]; // Convert resulting point coordinates to bytes. BN_bn2lebin(x, xBin, FIELD_BYTES_2003); @@ -234,24 +233,24 @@ BOOL BINK2002::Generate(KeyInfo &info, std::string &pKey) msgBuffer[0x01] = (pData & 0x00FF); msgBuffer[0x02] = (pData & 0xFF00) >> 8; - memcpy((void *)&msgBuffer[3], (void *)xBin, FIELD_BYTES_2003); - memcpy((void *)&msgBuffer[3 + FIELD_BYTES_2003], (void *)yBin, FIELD_BYTES_2003); + memcpy(&msgBuffer[3], xBin, FIELD_BYTES_2003); + memcpy(&msgBuffer[3 + FIELD_BYTES_2003], yBin, FIELD_BYTES_2003); // pHash = SHA1(79 || Channel ID || R.x || R.y) SHA1(msgBuffer, SHA_MSG_LENGTH_2003, msgDigest); // Translate the byte digest into a 32-bit integer - this is our computed hash. // Truncate the hash to 31 bits. - DWORD pHash = BYDWORD(msgDigest) & BITMASK(31); + info.Hash = BYDWORD(msgDigest) & BITMASK(31); // Assemble the second SHA message. msgBuffer[0x00] = 0x5D; msgBuffer[0x01] = (pData & 0x00FF); msgBuffer[0x02] = (pData & 0xFF00) >> 8; - msgBuffer[0x03] = (pHash & 0x000000FF); - msgBuffer[0x04] = (pHash & 0x0000FF00) >> 8; - msgBuffer[0x05] = (pHash & 0x00FF0000) >> 16; - msgBuffer[0x06] = (pHash & 0xFF000000) >> 24; + msgBuffer[0x03] = (info.Hash & 0x000000FF); + msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8; + msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16; + msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24; msgBuffer[0x07] = (info.AuthInfo & 0x00FF); msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8; msgBuffer[0x09] = 0x00; @@ -323,7 +322,6 @@ BOOL BINK2002::Generate(KeyInfo &info, std::string &pKey) // The order is a prime, so it can't be even. if (BN_is_odd(s)) { - // s = -ek + √((ek)² + 4c) + n BN_add(s, s, genOrder); } @@ -338,11 +336,11 @@ BOOL BINK2002::Generate(KeyInfo &info, std::string &pKey) Pack(info, pRaw); fmt::print(UMSKT::debug, "Generation results:\n"); - fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", info.isUpgrade); - fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", info.ChannelID); - fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", info.Hash); - fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", info.Signature); - fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", info.AuthInfo); + fmt::print(UMSKT::debug, " Upgrade: {:#08x}\n", info.isUpgrade); + fmt::print(UMSKT::debug, "Channel ID: {:#08x}\n", info.ChannelID); + fmt::print(UMSKT::debug, " Hash: {:#08x}\n", info.Hash); + fmt::print(UMSKT::debug, " Signature: {:#08x}\n", info.Signature); + fmt::print(UMSKT::debug, " AuthInfo: {:#08x}\n", info.AuthInfo); fmt::print(UMSKT::debug, "\n"); EC_POINT_free(r); @@ -354,12 +352,6 @@ BOOL BINK2002::Generate(KeyInfo &info, std::string &pKey) // Convert bytecode to Base24 CD-key. base24(pKey, (BYTE *)pRaw); - BN_free(c); - BN_free(s); - BN_free(x); - BN_free(y); - BN_free(e); - BN_CTX_free(numContext); return true; diff --git a/src/libumskt/pidgen3/PIDGEN3.cpp b/src/libumskt/pidgen3/PIDGEN3.cpp index 88137f1..36a32bf 100644 --- a/src/libumskt/pidgen3/PIDGEN3.cpp +++ b/src/libumskt/pidgen3/PIDGEN3.cpp @@ -92,7 +92,6 @@ BOOL PIDGEN3::LoadEllipticCurve(const std::string pSel, const std::string aSel, /* Computed Data */ BN_dec2bn(&genOrder, &genOrderSel[0]); BN_dec2bn(&privateKey, &privateKeySel[0]); - BN_sub(privateKey, genOrder, privateKey); /* Elliptic Curve calculations. */ // The group is defined via Fp = all integers [0; p - 1], where p is prime. @@ -250,3 +249,15 @@ void PIDGEN3::unbase24(BYTE *byteSeq, std::string cdKey) // Reverse the byte sequence. endian(byteSeq, n); } + +BOOL PIDGEN3::getIsBINK1998() +{ + BIGNUM *max = BN_new(); + BN_hex2bn(&max, MAX_BINK1998); + + int retval = BN_cmp(max, privateKey); + + BN_free(max); + + return retval == true; +} diff --git a/src/libumskt/pidgen3/PIDGEN3.h b/src/libumskt/pidgen3/PIDGEN3.h index 820c482..d1baefd 100644 --- a/src/libumskt/pidgen3/PIDGEN3.h +++ b/src/libumskt/pidgen3/PIDGEN3.h @@ -24,13 +24,16 @@ #define UMSKT_PIDGEN3_H #include "../libumskt.h" +#define MAX_BINK1998 \ + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" class PIDGEN3 { protected: + BIGNUM *privateKey, *genOrder; + EC_POINT *genPoint, *pubPoint; EC_GROUP *eCurve; - EC_POINT *basePoint, *publicKey, *genPoint, *pubPoint; - BIGNUM *genOrder, *privateKey; + BOOL isBINK1998; public: PIDGEN3() @@ -42,8 +45,6 @@ class PIDGEN3 EC_GROUP_free(eCurve); EC_POINT_free(genPoint); EC_POINT_free(pubPoint); - EC_POINT_free(basePoint); - EC_POINT_free(publicKey); BN_free(genOrder); BN_free(privateKey); } @@ -88,6 +89,7 @@ class PIDGEN3 void base24(std::string &cdKey, BYTE *byteSeq); void unbase24(BYTE *byteSeq, std::string cdKey); + BOOL getIsBINK1998(); }; #endif // UMSKT_PIDGEN3_H