diff --git a/Keygen.vcxproj b/Keygen.vcxproj index 0840267..217458f 100644 --- a/Keygen.vcxproj +++ b/Keygen.vcxproj @@ -171,6 +171,8 @@ + + diff --git a/Keygen.vcxproj.filters b/Keygen.vcxproj.filters index a98b5b6..430b619 100644 --- a/Keygen.vcxproj.filters +++ b/Keygen.vcxproj.filters @@ -45,5 +45,7 @@ + + \ No newline at end of file diff --git a/header.h b/header.h index 0da400a..0c82e67 100644 --- a/header.h +++ b/header.h @@ -39,6 +39,7 @@ #define IDC_INPUT2 1021 #define IDC_IMAGE1 1050 +#define IDC_IMAGE2 1051 #define IDC_LABEL1 1055 #define IDC_LABEL2 1056 @@ -58,11 +59,9 @@ extern const long aXP; extern const long bXP; // xp.cpp -int keyXP( - char *pKey, - ul32 *hash, - ul32 *sig, - ul32 nRaw +bool keyXP( + char *pKey, + ul32 nRaw ); void unpackXP( @@ -70,39 +69,43 @@ void unpackXP( ul32 *hash, ul32 *sig, ul32 *raw - ); +); void packXP( ul32 *raw, ul32 *serial, ul32 *hash, ul32 *sig - ); +); -void verifyXPKey( +bool verifyXPKey( EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *publicKey, char *cdKey - ); +); void generateXPKey( - byte *pKey, + char *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *order, BIGNUM *privateKey, ul32 *pRaw - ); +); // server.cpp +bool keyServer( + char *pKey +); + void unpackServer( ul32 *osFamily, ul32 *hash, ul32 *sig, ul32 *prefix, ul32 *raw - ); +); void packServer( ul32 *raw, @@ -110,24 +113,24 @@ void packServer( ul32 *hash, ul32 *sig, ul32 *prefix - ); +); -void verifyServerKey( +bool verifyServerKey( EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *public_key, char *cdKey - ); +); void generateServerKey( - byte *pKey, + char *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *order, BIGNUM *privateKey, ul32 *osFamily, ul32 *prefix - ); +); // utilities.cpp void cprintf(const char *Format, int nColor, ...); @@ -149,8 +152,8 @@ EC_GROUP *initializeEllipticCurve( ); // key.cpp -void unbase24(ul32 *byteSeq, byte *cdKey); -void base24(byte *cdKey, ul32 *byteSeq); +void unbase24(ul32 *byteSeq, const char *cdKey); +void base24(char *cdKey, ul32 *byteSeq); void printProductKey(const char *pKey); void printProductID(const ul32 *pRaw); diff --git a/key.cpp b/key.cpp index 08c18ae..17d8baa 100644 --- a/key.cpp +++ b/key.cpp @@ -5,7 +5,7 @@ #include "header.h" /* Convert from byte sequence to the CD-key. */ -void base24(byte *cdKey, ul32 *byteSeq) { +void base24(char *cdKey, ul32 *byteSeq) { byte rbs[16]; BIGNUM *z; @@ -31,39 +31,51 @@ void base24(byte *cdKey, ul32 *byteSeq) { } /* Convert from CD-key to a byte sequence. */ -void unbase24(ul32 *byteSeq, byte *cdKey) { +void unbase24(ul32 *byteSeq, const char *cdKey) { + byte pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{}; BIGNUM *y = BN_new(); + BN_zero(y); + // Remove dashes from the CD-key and put it into a Base24 byte array. + for (int i = 0, k = 0; i < strlen(cdKey) && k < PK_LENGTH; i++) { + for (int j = 0; j < 24; j++) { + if (cdKey[i] != '-' && cdKey[i] == charset[j]) { + pDecodedKey[k++] = j; + break; + } + } + } + // Empty byte sequence. memset(byteSeq, 0, 16); - // For each character in product key, place its ASCII-code. - for (int i = 0; i < 25; i++) { - BN_mul_word(y, 24); - BN_add_word(y, cdKey[i]); + // Calculate the weighed sum of byte array elements. + for (int i = 0; i < PK_LENGTH; i++) { + BN_mul_word(y, PK_LENGTH - 1); + BN_add_word(y, pDecodedKey[i]); } // Acquire length. int n = BN_num_bytes(y); // Place the generated code into the byte sequence. - BN_bn2bin(y, (unsigned char *)byteSeq); + BN_bn2bin(y, (byte *)byteSeq); BN_free(y); // Reverse the byte sequence. - endiannessConvert((unsigned char *) byteSeq, n); + endiannessConvert((byte *) byteSeq, n); } /* Print Product Key. */ void printProductKey(const char *pKey) { - assert(strlen((const char *)pKey) == 25); + assert(strlen(pKey) == 25); SetConsoleTextAttribute(hConsole, 0x0A); - for (int i = 0; i < 25; i++) { + for (int i = 0; i < PK_LENGTH; i++) { putchar(pKey[i]); - if (i != 24 && i % 5 == 4) putchar('-'); + if (i != PK_LENGTH - 1 && i % 5 == 4) putchar('-'); } SetConsoleTextAttribute(hConsole, 0x0F); diff --git a/main.cpp b/main.cpp index ad9b70c..6a81596 100644 --- a/main.cpp +++ b/main.cpp @@ -9,80 +9,6 @@ HANDLE hConsole; ul32 dwSeed; byte charset[] = "BCDFGHJKMPQRTVWXY2346789"; -int mainServer() { - BIGNUM *a, *b, *p, *generatorX, *generatorY, *publicKeyX, *publicKeyY, *genOrder, *privateKey; - BN_CTX *context = BN_CTX_new(); - - a = BN_new(); - b = BN_new(); - p = BN_new(); - - generatorX = BN_new(); - generatorY = BN_new(); - - publicKeyX = BN_new(); - publicKeyY = BN_new(); - - genOrder = BN_new(); - - privateKey = BN_new(); - - /* Public data */ - // Data taken from pidgen.dll BINK-resources - BN_hex2bn(&p, "C9AE7AED19F6A7E100AADE98134111AD8118E59B8264734327940064BC675A0C682E19C89695FBFA3A4653E47D47FD7592258C7E3C3C61BBEA07FE5A7E842379"); - - BN_set_word(a, 1); - BN_set_word(b, 0); - - // Base point G (Generator) - BN_hex2bn(&generatorX, "85ACEC9F9F9B456A78E43C3637DC88D21F977A9EC15E5225BD5060CE5B892F24FEDEE574BF5801F06BC232EEF2161074496613698D88FAC4B397CE3B475406A7"); - BN_hex2bn(&generatorY, "66B7D1983F5D4FE43E8B4F1E28685DE0E22BBE6576A1A6B86C67533BF72FD3D082DBA281A556A16E593DB522942C8DD7120BA50C9413DF944E7258BDDF30B3C4"); - - // Inverse of the public key - BN_hex2bn(&publicKeyX, "90BF6BD980C536A8DB93B52AA9AEBA640BABF1D31BEC7AA345BB7510194A9B07379F552DA7B4A3EF81A9B87E0B85B5118E1E20A098641EE4CCF2045558C98C0E"); - BN_hex2bn(&publicKeyY, "6B87D1E658D03868362945CDD582E2CF33EE4BA06369E0EFE9E4851F6DCBEC7F15081E250D171EA0CC4CB06435BCFCFEA8F438C9766743A06CBD06E7EFB4C3AE"); - - /* Computed data */ - // Order of G <- from MSKey 4-in-1 - BN_hex2bn(&genOrder, "4CC5C56529F0237D"); - - // Computed private key - BN_hex2bn(&privateKey, "2606120F59C05118"); - - /* Elliptical Curve calculations. */ - // The group is defined via Fp = all integers [0; p - 1], where p is prime. - // The function EC_POINT_set_affine_coordinates() sets the x and y coordinates for the point p defined over the curve given in group. - EC_GROUP *eCurve = EC_GROUP_new_curve_GFp(p, a, b, context); - - // Create new point for the generator on the elliptic curve and set its coordinates to (genX; genY). - EC_POINT *genPoint = EC_POINT_new(eCurve); - EC_POINT_set_affine_coordinates(eCurve, genPoint, generatorX, generatorY, context); - - // Create new point for the public key on the elliptic curve and set its coordinates to (pubX; pubY). - EC_POINT *pubPoint = EC_POINT_new(eCurve); - EC_POINT_set_affine_coordinates(eCurve, pubPoint, publicKeyX, publicKeyY, context); - - // If generator and public key points are not on the elliptic curve, either the generator or the public key values are incorrect. - assert(EC_POINT_is_on_curve(eCurve, genPoint, context) == 1); - assert(EC_POINT_is_on_curve(eCurve, pubPoint, context) == 1); - - char pkey[25]{}; - ul32 osfamily[1], prefix[1]; - - osfamily[0] = 1280; - RAND_bytes((byte *)prefix, 4); - - prefix[0] &= 0x3ff; - generateServerKey((byte *)pkey, eCurve, genPoint, genOrder, privateKey, osfamily, prefix); - printProductKey(pkey); - printf("\n\n"); - verifyServerKey(eCurve, genPoint, pubPoint, (char *) pkey); - - BN_CTX_free(context); - - return 0; -} - /* * PK: VX8CG-8KC6V-PVPMD-GKPPH-GC7W8 * diff --git a/resource.h b/resource.h index f10e207..6d93db9 100644 --- a/resource.h +++ b/resource.h @@ -6,12 +6,14 @@ #define IDR_WAVE1 102 #define IDB_BITMAP1 103 #define IDB_BITMAP2 104 +#define IDB_BITMAP3 105 +#define IDB_BITMAP4 106 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_RESOURCE_VALUE 107 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/resource.rc b/resource.rc index bee4e7b..4d10680 100644 Binary files a/resource.rc and b/resource.rc differ diff --git a/resources/musicoff.bmp b/resources/musicoff.bmp new file mode 100644 index 0000000..e244248 Binary files /dev/null and b/resources/musicoff.bmp differ diff --git a/resources/musicon.bmp b/resources/musicon.bmp new file mode 100644 index 0000000..84ddb06 Binary files /dev/null and b/resources/musicon.bmp differ diff --git a/server.cpp b/server.cpp index 59ed7fa..75cb40d 100644 --- a/server.cpp +++ b/server.cpp @@ -4,11 +4,32 @@ #include "header.h" +const char pSv[] = "C9AE7AED19F6A7E100AADE98134111AD8118E59B8264734327940064BC675A0C682E19C89695FBFA3A4653E47D47FD7592258C7E3C3C61BBEA07FE5A7E842379"; +const long aSv = 1; +const long bSv = 0; + +// Base point G (Generator) +const char genXSv[] = "85ACEC9F9F9B456A78E43C3637DC88D21F977A9EC15E5225BD5060CE5B892F24FEDEE574BF5801F06BC232EEF2161074496613698D88FAC4B397CE3B475406A7"; +const char genYSv[] = "66B7D1983F5D4FE43E8B4F1E28685DE0E22BBE6576A1A6B86C67533BF72FD3D082DBA281A556A16E593DB522942C8DD7120BA50C9413DF944E7258BDDF30B3C4"; + +// Inverse of the public key +const char pubXSv[] = "90BF6BD980C536A8DB93B52AA9AEBA640BABF1D31BEC7AA345BB7510194A9B07379F552DA7B4A3EF81A9B87E0B85B5118E1E20A098641EE4CCF2045558C98C0E"; +const char pubYSv[] = "6B87D1E658D03868362945CDD582E2CF33EE4BA06369E0EFE9E4851F6DCBEC7F15081E250D171EA0CC4CB06435BCFCFEA8F438C9766743A06CBD06E7EFB4C3AE"; + +// Order of G <- from MSKey 4-in-1 +const char genOrderSv[] = "4CC5C56529F0237D"; + +// Computed private key +const char privateKeySv[] = "2606120F59C05118"; + void unpackServer(ul32 *osFamily, ul32 *hash, ul32 *sig, ul32 *prefix, ul32 *raw) { osFamily[0] = raw[0] & 0x7ff; + hash[0] = ((raw[0] >> 11) | (raw[1] << 21)) & 0x7fffffff; + sig[0] = (raw[1] >> 10) | (raw[2] << 22); sig[1] = ((raw[2] >> 10) | (raw[3] << 22)) & 0x3fffffff; + prefix[0] = (raw[3] >> 8) & 0x3ff; } @@ -19,26 +40,14 @@ void packServer(ul32 *raw, ul32 *osFamily, ul32 *hash, ul32 *sig, ul32 *prefix) raw[3] = (sig[1] >> 22) | (prefix[0] << 8); } -void verifyServerKey(EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *public_key, char *cdKey) { - byte key[25]; +bool verifyServerKey(EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *public_key, char *cdKey) { int i, j, k; BN_CTX *ctx = BN_CTX_new(); - - for (i = 0, k = 0; i < strlen(cdKey); i++) { - for (j = 0; j < 24; j++) { - if (cdKey[i] != '-' && cdKey[i] == charset[j]) { - key[k++] = j; - break; - } - assert(j < 24); - } - if (k >= 25) break; - } ul32 bkey[4] = {0}; ul32 osfamily[1], hash[1], sig[2], prefix[1]; - unbase24(bkey, key); + unbase24(bkey, cdKey); printf("%.8x %.8x %.8x %.8x\n", bkey[3], bkey[2], bkey[1], bkey[0]); unpackServer(osfamily, hash, sig, prefix, bkey); @@ -72,16 +81,16 @@ void verifyServerKey(EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *public_key y = BN_new(); endiannessConvert((byte *) sig, 8); endiannessConvert((byte *) h1, 8); - s = BN_bin2bn((byte *)sig, 8, NULL); - h = BN_bin2bn((byte *)h1, 8, NULL); + s = BN_bin2bn((byte *)sig, 8, nullptr); + h = BN_bin2bn((byte *)h1, 8, nullptr); EC_POINT *r = EC_POINT_new(eCurve); EC_POINT *t = EC_POINT_new(eCurve); /* r = sig*(sig*generator + h1*public_key) */ - EC_POINT_mul(eCurve, t, NULL, generator, s, ctx); - EC_POINT_mul(eCurve, r, NULL, public_key, h, ctx); + EC_POINT_mul(eCurve, t, nullptr, generator, s, ctx); + EC_POINT_mul(eCurve, r, nullptr, public_key, h, ctx); EC_POINT_add(eCurve, r, r, t, ctx); - EC_POINT_mul(eCurve, r, NULL, r, s, ctx); + EC_POINT_mul(eCurve, r, nullptr, r, s, ctx); EC_POINT_get_affine_coordinates_GFp(eCurve, r, x, y, ctx); ul32 h2[1]; @@ -105,10 +114,7 @@ void verifyServerKey(EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *public_key SHA1_Final(md, &h_ctx); h2[0] = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) & 0x7fffffff; printf("Calculated hash: %.8x\n", h2[0]); - - if (h2[0] == hash[0]) printf("Key VALID\n"); - else printf("Key invalid\n"); - + BN_free(s); BN_free(h); BN_free(x); @@ -116,65 +122,87 @@ void verifyServerKey(EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *public_key EC_POINT_free(r); EC_POINT_free(t); BN_CTX_free(ctx); + + if (h2[0] == hash[0]) return true; + else return false; } -void generateServerKey(byte *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *order, BIGNUM *privateKey, ul32 *osFamily, ul32 *prefix) { +void generateServerKey(char *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *order, BIGNUM *privateKey, ul32 *osFamily, ul32 *prefix) { BN_CTX *ctx = BN_CTX_new(); - BIGNUM *k = BN_new(); + BIGNUM *c = BN_new(); BIGNUM *s = BN_new(); BIGNUM *x = BN_new(); BIGNUM *y = BN_new(); BIGNUM *b = BN_new(); EC_POINT *r = EC_POINT_new(eCurve); - ul32 bkey[4]; - byte buf[FIELD_BYTES_2003], md[20]; + ul32 bKey[4]; ul32 h1[2]; - ul32 hash[1], sig[2]; - SHA_CTX h_ctx; - - for (;;) { - /* r = k*generator */ - BN_rand(k, FIELD_BITS_2003, -1, 0); - EC_POINT_mul(eCurve, r, NULL, generator, k, ctx); + do { + ul32 hash = 0, sig[2]{}; + + memset(bKey, 0, 4); + + // Generate a random number c consisting of 512 bits without any constraints. + BN_rand(c, FIELD_BITS_2003, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); + + // r = generator * c + EC_POINT_mul(eCurve, r, nullptr, generator, c, ctx); + + // x = r.x; y = r.y; EC_POINT_get_affine_coordinates(eCurve, r, x, y, ctx); - /* hash = SHA-1(79 || OS Family || r.x || r.y) */ - SHA1_Init(&h_ctx); + SHA_CTX hContext; + byte md[SHA_DIGEST_LENGTH]{}, buf[FIELD_BYTES_2003]{}; + + // hash = SHA-1(79 || OS Family || r.x || r.y) + SHA1_Init(&hContext); + buf[0] = 0x79; - buf[1] = osFamily[0] & 0xff; - buf[2] = (osFamily[0] & 0xff00) >> 8; - SHA1_Update(&h_ctx, buf, 3); + + buf[1] = (*osFamily & 0xff); + buf[2] = (*osFamily & 0xff00) >> 8; + + SHA1_Update(&hContext, buf, 3); memset(buf, 0, FIELD_BYTES_2003); + BN_bn2bin(x, buf); endiannessConvert((byte *) buf, FIELD_BYTES_2003); - SHA1_Update(&h_ctx, buf, FIELD_BYTES_2003); + SHA1_Update(&hContext, buf, FIELD_BYTES_2003); memset(buf, 0, FIELD_BYTES_2003); + BN_bn2bin(y, buf); endiannessConvert((byte *) buf, FIELD_BYTES_2003); - SHA1_Update(&h_ctx, buf, FIELD_BYTES_2003); - - SHA1_Final(md, &h_ctx); - hash[0] = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) & 0x7fffffff; + + SHA1_Update(&hContext, buf, FIELD_BYTES_2003); + SHA1_Final(md, &hContext); + + hash = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) & 0x7fffffff; /* h1 = SHA-1(5D || OS Family || Hash || Prefix || 00 00) */ - SHA1_Init(&h_ctx); - buf[0] = 0x5d; - buf[1] = osFamily[0] & 0xff; - buf[2] = (osFamily[0] & 0xff00) >> 8; - buf[3] = hash[0] & 0xff; - buf[4] = (hash[0] & 0xff00) >> 8; - buf[5] = (hash[0] & 0xff0000) >> 16; - buf[6] = (hash[0] & 0xff000000) >> 24; + SHA1_Init(&hContext); + buf[0] = 0x5D; + + buf[1] = (*osFamily & 0xff); + buf[2] = (*osFamily & 0xff00) >> 8; + + buf[3] = (hash & 0xff); + buf[4] = (hash & 0xff00) >> 8; + buf[5] = (hash & 0xff0000) >> 16; + buf[6] = (hash & 0xff000000) >> 24; + buf[7] = prefix[0] & 0xff; buf[8] = (prefix[0] & 0xff00) >> 8; - buf[9] = buf[10] = 0; - SHA1_Update(&h_ctx, buf, 11); - SHA1_Final(md, &h_ctx); + + buf[9] = 0x00; + buf[10] = 0x00; + SHA1_Update(&hContext, buf, 11); + SHA1_Final(md, &hContext); + h1[0] = md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24); h1[1] = (md[4] | (md[5] << 8) | (md[6] << 16) | (md[7] << 24)) >> 2; h1[1] &= 0x3FFFFFFF; @@ -186,8 +214,8 @@ void generateServerKey(byte *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM BN_mod_mul(b, b, privateKey, order, ctx); BN_copy(s, b); BN_mod_sqr(s, s, order, ctx); - BN_lshift(k, k, 2); - BN_add(s, s, k); + BN_lshift(c, c, 2); + BN_add(s, s, c); BN_mod_sqrt(s, s, order, ctx); BN_mod_sub(s, s, b, order, ctx); if (BN_is_odd(s)) { @@ -196,21 +224,64 @@ void generateServerKey(byte *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM BN_rshift1(s, s); sig[0] = sig[1] = 0; BN_bn2bin(s, (byte *)sig); - endiannessConvert((byte *) sig, BN_num_bytes(s)); - if (sig[1] < 0x40000000) break; - } - packServer(bkey, osFamily, hash, sig, prefix); - printf("OS family: %u\nHash: %.8x\nSig: %.8x %.8x\nPrefix: %.8x\n", osFamily[0], hash[0], sig[1], sig[0], prefix[0]); - printf("%.8x %.8x %.8x %.8x\n", bkey[3], bkey[2], bkey[1], bkey[0]); - base24(pKey, bkey); + endiannessConvert((byte *)sig, BN_num_bytes(s)); + packServer(bKey, osFamily, &hash, sig, prefix); + + printf("OS family: %u\nHash: %.8x\nSig: %.8x %.8x\nPrefix: %.8x\n", *osFamily, hash, sig[1], sig[0], *prefix); + printf("%.8x %.8x %.8x %.8x\n", bKey[3], bKey[2], bKey[1], bKey[0]); + } while (bKey[3] >= 0x40000000); + + base24(pKey, bKey); - BN_free(k); + BN_free(c); BN_free(s); BN_free(x); BN_free(y); BN_free(b); - EC_POINT_free(r); BN_CTX_free(ctx); + EC_POINT_free(r); +} + +bool keyServer(char *pKey) { + + // We cannot produce a valid key without knowing the private key k. The reason for this is that + // we need the result of the function K(x; y) = kG(x; y). + BIGNUM *privateKey = BN_new(); + + // We can, however, validate any given key using the available public key: {p, a, b, G, K}. + // genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm. + BIGNUM *genOrder = BN_new(); + + /* Computed data */ + BN_hex2bn(&genOrder, genOrderSv); + BN_hex2bn(&privateKey, privateKeySv); + + EC_POINT *genPoint, *pubPoint; + EC_GROUP *eCurve = initializeEllipticCurve( + pSv, + aSv, + bSv, + genXSv, + genYSv, + pubXSv, + pubYSv, + genOrder, + privateKey, + &genPoint, + &pubPoint + ); + + ul32 osFamily = 1280, prefix = 0; + + RAND_bytes((byte *)&prefix, 4); + prefix &= 0x3ff; + + generateServerKey(pKey, eCurve, genPoint, genOrder, privateKey, &osFamily, &prefix); + + printProductKey(pKey); + printf("\n\n"); + + return verifyServerKey(eCurve, genPoint, pubPoint, pKey); } \ No newline at end of file diff --git a/utilities.cpp b/utilities.cpp index fa1dc01..d8b7dc6 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -66,8 +66,6 @@ EC_GROUP *initializeEllipticCurve( // Context variable context = BN_CTX_new(); - - /* Public data */ BN_hex2bn(&p, pSel); BN_set_word(a, aSel); diff --git a/windows.cpp b/windows.cpp index b0bd48c..f807cb8 100644 --- a/windows.cpp +++ b/windows.cpp @@ -14,7 +14,88 @@ HWND hMainWindow; const WCHAR *pAboutLink = L"https://github.com/Endermanch/XPKeygen", - *pWebsite = L"https://malwarewatch.org"; + *pWebsite = L"https://malwarewatch.org", + *pVersion = L"2.2"; + +bool bServer = false, + bMusic = true; + +void formatXP(WCHAR *pBSection, WCHAR *pCSection, WCHAR *pText) { + WCHAR pFPK[32]{}; + + int pSSection = 0; + + for (int i = 0; i < wcslen(pCSection); i++) + pSSection -= pCSection[i] - '0'; + + while (pSSection < 0) + pSSection += 7; + + char pKey[PK_LENGTH + NULL_TERMINATOR]{}; + ul32 msDigits = _wtoi(pBSection), + lsDigits = _wtoi(pCSection); + + ul32 nRPK = msDigits * 1'000'000 + lsDigits, + hash = 0, + bKey[4]{}, + bSig[2]{}; + + bool bValid = keyXP(pKey, nRPK); + + unbase24(bKey, pKey); + unpackXP(nullptr, &hash, bSig, bKey); + + for (int i = 0; i < 5; i++) + wsprintfW(pFPK, L"%s%s%.5S", pFPK, i != 0 ? L"-" : L"", &pKey[5 * i]); + + wsprintfW( + pText, + L"Product ID:\tPPPPP-%03d-%06d%d-23XXX\r\n\r\nBytecode:\t%08lX %08lX %08lX %08lX\r\nHash:\t\t%08lX\r\nSignature:\t%08lX %08lX\r\nCurve Point:\t%s\r\n\r\n%s\r\n", + nRPK / 1'000'000, + nRPK % 1'000'000, + pSSection, + bKey[3], bKey[2], bKey[1], bKey[0], + hash, + bSig[1], bSig[0], + bValid ? L"True" : L"False", + pFPK + ); +} + +void formatServer(WCHAR *pText) { + WCHAR pFPK[32]{}; + + char pKey[PK_LENGTH + NULL_TERMINATOR]{}; + ul32 hash = 0, + osFamily = 0, + prefix = 0, + bKey[4]{}, + bSig[2]{}; + + bool bValid = keyServer(pKey); + + unbase24(bKey, pKey); + unpackServer(&osFamily, &hash, bSig, &prefix, bKey); + + for (int i = 0; i < 5; i++) + wsprintfW(pFPK, L"%s%s%.5S", pFPK, i != 0 ? L"-" : L"", &pKey[5 * i]); + + wsprintfW( + pText, + L"Bytecode:\t%08lX %08lX %08lX %08lX\r\nOS Family:\t%d\r\nHash:\t\t%08lX\r\nSignature:\t%08lX %08lX\r\nPrefix:\t\t%04lX\r\nCurve Point:\t%s\r\n\r\n%s\r\n", + bKey[3], bKey[2], bKey[1], bKey[0], + osFamily, + hash, + bSig[1], bSig[0], + prefix, + bValid ? L"True" : L"False", + pFPK + ); +} + +void StopAudio() { + PlaySoundW(nullptr, nullptr, 0); +} bool PlayAudio(HINSTANCE hInstance, WCHAR *lpName, UINT bFlags) { HANDLE hResInfo = FindResourceW(hInstance, lpName, L"WAVE"); @@ -33,8 +114,8 @@ bool PlayAudio(HINSTANCE hInstance, WCHAR *lpName, UINT bFlags) { return sndPlaySoundW(lpRes, SND_MEMORY | bFlags); } -/* Static link processor. */ -LRESULT StaticLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { +/* Bitmap link processor. */ +LRESULT BitmapLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { static TRACKMOUSEEVENT trackMouse; static BOOL isSet = FALSE; @@ -42,7 +123,7 @@ LRESULT StaticLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UI switch (uMsg) { // Set the struct up outside of a frequently executed message to speed things up. - case WM_APP + IDC_LABEL4: { + case WM_APP + 0x69: { trackMouse.cbSize = sizeof(TRACKMOUSEEVENT); trackMouse.dwFlags = TME_LEAVE; trackMouse.dwHoverTime = HOVER_DEFAULT; @@ -58,7 +139,7 @@ LRESULT StaticLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UI case WM_MOUSEMOVE: { if (!isSet) { TrackMouseEvent(&trackMouse); - SetCursor(LoadCursorW(NULL, IDC_HAND)); + SetCursor(LoadCursorW(nullptr, IDC_HAND)); isSet = TRUE; } @@ -69,7 +150,7 @@ LRESULT StaticLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UI // Set cursor back to normal if it's outside of static area. case WM_MOUSELEAVE: { if (isSet) { - SetCursor(LoadCursorW(NULL, IDC_ARROW)); + SetCursor(LoadCursorW(nullptr, IDC_ARROW)); isSet = FALSE; } @@ -78,7 +159,64 @@ LRESULT StaticLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UI // Remove the subclass before window closes. case WM_NCDESTROY: { - RemoveWindowSubclass(hWindow, StaticLinkProc, 1); + RemoveWindowSubclass(hWindow, BitmapLinkProc, uIdSubclass); + + break; + } + + // Pass everything else to DefWndProc. + default: return DefSubclassProc(hWindow, uMsg, wParam, lParam); + } + + return 0; +} + +/* Static link processor. */ +LRESULT StaticLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { + static TRACKMOUSEEVENT trackMouse; + static BOOL isSet = FALSE; + + // The worst part here was to avoid pointer flickering, as well as spamming the SetCursor function. + switch (uMsg) { + + // Set the struct up outside of a frequently executed message to speed things up. + case WM_APP + 0x69: { + trackMouse.cbSize = sizeof(TRACKMOUSEEVENT); + trackMouse.dwFlags = TME_LEAVE; + trackMouse.dwHoverTime = HOVER_DEFAULT; + trackMouse.hwndTrack = hWindow; + + break; + } + + // You have to turn off the WM_SETCURSOR, because it spams the SetCursor function with IDC_ARROW in the DefWndProc. Moist garbage. + case WM_SETCURSOR: break; + + // Set cursor to hand if it's inside of static area, refresh the mouse tracking loop. + case WM_MOUSEMOVE: { + if (!isSet) { + TrackMouseEvent(&trackMouse); + SetCursor(LoadCursorW(nullptr, IDC_HAND)); + + isSet = TRUE; + } + + break; + } + + // Set cursor back to normal if it's outside of static area. + case WM_MOUSELEAVE: { + if (isSet) { + SetCursor(LoadCursorW(nullptr, IDC_ARROW)); + isSet = FALSE; + } + + break; + } + + // Remove the subclass before window closes. + case WM_NCDESTROY: { + RemoveWindowSubclass(hWindow, StaticLinkProc, uIdSubclass); break; } @@ -91,6 +229,8 @@ LRESULT StaticLinkProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam, UI } LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lParam) { + static HINSTANCE hInstance; + static HBRUSH hBGColorPrim, hBGColorSec, hFGColor, hBtnDefault, hBtn1Select, hBtn1Hot, hBtn2Select, hBtn2Hot, @@ -102,12 +242,23 @@ LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lPar hBtn2SelectP, hBtn2HotP, hBtn3SelectP, hBtn3HotP, hBtn4SelectP, hBtn4HotP; + static HDC hMainDC; + static HBITMAP hBMusicOn, hBMusicOff; + switch (uMessage) { case WM_CREATE: + bMusic = true; + + hInstance = ((LPCREATESTRUCT)(lParam))->hInstance; hMainDC = GetDC(hWindow); + PlayAudio(hInstance, MAKEINTRESOURCEW(IDR_WAVE1), SND_ASYNC | SND_LOOP | SND_NODEFAULT); + + hBMusicOn = (HBITMAP)LoadImageW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP3), IMAGE_BITMAP, 0, 0, 0); + hBMusicOff = (HBITMAP)LoadImageW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP4), IMAGE_BITMAP, 0, 0, 0); + hFrameColor = CreatePen(PS_SOLID, 1, RGB(240, 240, 240)); hFramePrim = CreatePen(PS_SOLID, 1, RGB(10, 10, 10)); @@ -115,7 +266,6 @@ LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lPar hBGColorSec = (HBRUSH)(GetStockObject(BLACK_BRUSH)); hFGColor = (HBRUSH)GetStockObject(WHITE_BRUSH); - // yellow, blue, red, green hBtnDefaultP = CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); hBtn1SelectP = CreatePen(PS_SOLID, 1, RGB(160, 160, 0)); @@ -160,7 +310,11 @@ LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lPar SetBkMode((HDC)wParam, TRANSPARENT); if ((HWND)lParam == GetDlgItem(hWindow, IDC_EDIT1)) { - SetTextColor((HDC)wParam, RGB(255, 255, 0)); + if (bServer) + SetTextColor((HDC)wParam, RGB(30, 255, 30)); + else + SetTextColor((HDC)wParam, RGB(255, 255, 0)); + return (LRESULT)(hBGColorSec); } else if ((HWND)lParam == GetDlgItem(hWindow, IDC_LABEL4)) { @@ -279,6 +433,38 @@ LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lPar case WM_COMMAND: switch (LOWORD(wParam)) { + case IDC_IMAGE2: { + switch (HIWORD(wParam)) { + case STN_CLICKED: + if (bMusic) { + SendMessageW((HWND)lParam, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBMusicOff); + StopAudio(); + + bMusic = false; + } + else { + SendMessageW((HWND)lParam, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBMusicOn); + PlayAudio(hInstance, MAKEINTRESOURCEW(IDR_WAVE1), SND_ASYNC | SND_LOOP | SND_NODEFAULT); + + bMusic = true; + } + break; + } + + break; + } + + case IDC_LABEL4: { + switch (HIWORD(wParam)) { + case STN_CLICKED: + ShellExecuteW(hWindow, L"open", pWebsite, nullptr, nullptr, SW_SHOWNORMAL); + + break; + } + + break; + } + case IDC_LABEL2: { switch (HIWORD(wParam)) { case STN_CLICKED: @@ -287,9 +473,24 @@ LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lPar break; } - break; + __fallthrough; } + case IDC_RADIO1: + switch (HIWORD(wParam)) { + case BN_CLICKED: + EnableWindow(GetDlgItem(hMainWindow, IDC_BUTTON4), true); + + EnableWindow(GetDlgItem(hMainWindow, IDC_INPUT1), true); + EnableWindow(GetDlgItem(hMainWindow, IDC_INPUT2), true); + + bServer = false; + + break; + } + + break; + case IDC_LABEL3: { switch (HIWORD(wParam)) { case STN_CLICKED: @@ -298,19 +499,23 @@ LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lPar break; } - break; + __fallthrough; } - case IDC_LABEL4: { + case IDC_RADIO2: switch (HIWORD(wParam)) { - case STN_CLICKED: - ShellExecuteW(hWindow, L"open", pWebsite, nullptr, nullptr, SW_SHOWNORMAL); + case BN_CLICKED: + EnableWindow(GetDlgItem(hMainWindow, IDC_BUTTON4), false); + + EnableWindow(GetDlgItem(hMainWindow, IDC_INPUT1), false); + EnableWindow(GetDlgItem(hMainWindow, IDC_INPUT2), false); + + bServer = true; break; } break; - } case IDC_BUTTON1: { ShellExecuteW(hWindow, L"open", pAboutLink, nullptr, nullptr, SW_SHOWNORMAL); @@ -319,54 +524,24 @@ LRESULT CALLBACK WNDProc(HWND hWindow, UINT uMessage, WPARAM wParam, LPARAM lPar } case IDC_BUTTON2: { - HWND hEdit = GetDlgItem(hMainWindow, IDC_EDIT1); - HWND hInput1 = GetDlgItem(hMainWindow, IDC_INPUT1); - HWND hInput2 = GetDlgItem(hMainWindow, IDC_INPUT2); + WCHAR *pText = (WCHAR *)calloc(512, sizeof(WCHAR)); + HWND hEdit = GetDlgItem(hMainWindow, IDC_EDIT1); - WCHAR pBSection[4]{}, pCSection[8]{}, pFPK[32]{}; + if (bServer) { + formatServer(pText); + } + else { + WCHAR pBSection[4]{}, pCSection[8]{}; + HWND hInput1 = GetDlgItem(hMainWindow, IDC_INPUT1), + hInput2 = GetDlgItem(hMainWindow, IDC_INPUT2); - SendMessageW(hInput1, WM_GETTEXT, 3 + NULL_TERMINATOR, (LPARAM)pBSection); - SendMessageW(hInput2, WM_GETTEXT, 6 + NULL_TERMINATOR, (LPARAM)pCSection); + SendMessageW(hInput1, WM_GETTEXT, 3 + NULL_TERMINATOR, (LPARAM)pBSection); + SendMessageW(hInput2, WM_GETTEXT, 6 + NULL_TERMINATOR, (LPARAM)pCSection); - int pSSection = 0; - - for (int i = 0; i < wcslen(pCSection); i++) - pSSection -= pCSection[i] - '0'; - - while (pSSection < 0) - pSSection += 7; - - ul32 msDigits = _wtoi(pBSection), - lsDigits = _wtoi(pCSection); - - ul32 nRPK = msDigits * 1'000'000 + lsDigits, - hash = 0, - sig[2]{}; - - CHAR pKey[PK_LENGTH + NULL_TERMINATOR]{}; - - keyXP(pKey, &hash, sig, nRPK); - - for (int i = 0; i < 5; i++) - wsprintfW(pFPK, L"%s%s%.5S", pFPK, i != 0 ? L"-" : L"", &pKey[5 * i]); - - WCHAR *pText = (WCHAR *)calloc(512 + 4 + 9 + 5 * NULL_TERMINATOR, sizeof(WCHAR)); - - wsprintfW( - pText, - L"%s%sProduct ID: PPPPP-%03d-%06d%d-23XXX\r\nHash: %08lX\r\nSignature: %08lX-%08lX\r\n\r\n%s\r\n", - pText, - wcslen(pText) ? L"\r\n" : L"", - nRPK / 1'000'000, - nRPK % 1'000'000, - pSSection, - hash, - sig[1], sig[0], - pFPK - ); + formatXP(pBSection, pCSection, pText); + } SendMessageW(hEdit, WM_SETTEXT, 0, (LPARAM)pText); - free(pText); return 0; @@ -516,7 +691,7 @@ bool InitializeWindow(HINSTANCE hInstance) { // Select the default font. SelectObject(hMainDC, hLabelFont); - HBITMAP hBitmap = (HBITMAP)LoadImageW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP2), IMAGE_BITMAP, 0, 0, 0); + HBITMAP hBLogo = (HBITMAP)LoadImageW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP2), IMAGE_BITMAP, 0, 0, 0); HWND hLogo = CreateWindowExW( 0, @@ -529,7 +704,27 @@ bool InitializeWindow(HINSTANCE hInstance) { hInstance, nullptr ); - SendMessageW(hLogo, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); + SendMessageW(hLogo, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBLogo); + + HBITMAP hBMusicOn = (HBITMAP)LoadImageW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP3), IMAGE_BITMAP, 0, 0, 0), + hBMusicOff = (HBITMAP)LoadImageW(hInstance, MAKEINTRESOURCEW(IDB_BITMAP4), IMAGE_BITMAP, 0, 0, 0); + + HWND hMusic = CreateWindowExW( + 0, + L"Static", nullptr, + WS_CHILD | WS_VISIBLE | + SS_BITMAP | SS_REALSIZECONTROL | + SS_NOTIFY, + w - 67, 180, + 32, 32, + hMainWindow, (HMENU)IDC_IMAGE2, + hInstance, nullptr + ); + + SendMessageW(hMusic, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBMusicOn); + + SetWindowSubclass(hMusic, BitmapLinkProc, IDC_IMAGE2, 0); + SendMessageW(hMusic, WM_APP + 0x69, 0, 0); HWND hGroupBox = CreateWindowExW( 0, @@ -571,6 +766,7 @@ bool InitializeWindow(HINSTANCE hInstance) { ); SendMessageW(hInput1, EM_SETCUEBANNER, 0, (LPARAM)L"BBB"); + SendMessageW(hInput1, WM_SETTEXT, 0, (LPARAM)L"640"); SendMessageW(hInput1, WM_SETFONT, (WPARAM)hLabelFont, 0); SendMessageW(hInput1, EM_SETLIMITTEXT, (WPARAM)3, 0); @@ -602,6 +798,7 @@ bool InitializeWindow(HINSTANCE hInstance) { ); SendMessageW(hInput2, EM_SETCUEBANNER, 0, (LPARAM)L"CCCCCC"); + SendMessageW(hInput2, WM_SETTEXT, 0, (LPARAM)L"883400"); SendMessageW(hInput2, WM_SETFONT, (WPARAM)hLabelFont, 0); SendMessageW(hInput2, EM_SETLIMITTEXT, (WPARAM)6, 0); @@ -643,7 +840,7 @@ bool InitializeWindow(HINSTANCE hInstance) { 17, 20, hMainWindow, (HMENU)IDC_RADIO1, - hInstance, NULL + hInstance, nullptr ); SendMessageW(hRadio1, BM_SETCHECK, 1, 0); @@ -673,7 +870,7 @@ bool InitializeWindow(HINSTANCE hInstance) { 17, 20, hMainWindow, (HMENU)IDC_RADIO2, - hInstance, NULL); + hInstance, nullptr); SendMessageW(hRadio2, WM_SETFONT, (WPARAM)hLabelFont, 0); @@ -755,8 +952,6 @@ bool InitializeWindow(HINSTANCE hInstance) { ); SendMessageW(hQuit, WM_SETFONT, (WPARAM)hLabelFont, 0); - - const WCHAR *pVersion = L"2.1"; WCHAR pVersionString[256]{}; @@ -777,12 +972,12 @@ bool InitializeWindow(HINSTANCE hInstance) { SetWindowSubclass(hVersion, StaticLinkProc, IDC_LABEL4, 0); SendMessageW(hVersion, WM_SETFONT, (WPARAM)hSmolFont, 0); - SendMessageW(hVersion, WM_APP + IDC_LABEL4, 0, 0); + SendMessageW(hVersion, WM_APP + 0x69, 0, 0); HWND hMotto = CreateWindowExW( 0, L"Static", - L"we keep on downloading ◄ 11/04/2023", + L"we keep on downloading ◄ 12/04/2023", WS_CHILD | WS_VISIBLE, w - (170 + 15), 436, 170, 16, @@ -795,8 +990,6 @@ bool InitializeWindow(HINSTANCE hInstance) { ShowWindow(hMainWindow, SW_SHOW); UpdateWindow(hMainWindow); - PlayAudio(hInstance, MAKEINTRESOURCEW(IDR_WAVE1), SND_ASYNC | SND_LOOP | SND_NODEFAULT); - MSG uMessage; while(GetMessageW(&uMessage, nullptr, 0, 0)) { diff --git a/xp.cpp b/xp.cpp index 8c95b01..46818ab 100644 --- a/xp.cpp +++ b/xp.cpp @@ -29,294 +29,282 @@ void unpackXP(ul32 *serial, ul32 *hash, ul32 *sig, ul32 *raw) { // log2(24^25) = 114. // Serial = Bits [0..30] -> 31 bits - serial[0] = raw[0] & 0x7fffffff; + if (serial) + serial[0] = raw[0] & 0x7fffffff; // Hash (e) = Bits [31..58] -> 28 bits - hash[0] = ((raw[0] >> 31) | (raw[1] << 1)) & 0xfffffff; + if (hash) + hash[0] = ((raw[0] >> 31) | (raw[1] << 1)) & 0xfffffff; // Signature (s) = Bits [59..113] -> 55 bits - sig[0] = (raw[1] >> 27) | (raw[2] << 5); - sig[1] = (raw[2] >> 27) | (raw[3] << 5); + if (sig) { + sig[0] = (raw[1] >> 27) | (raw[2] << 5); + sig[1] = (raw[2] >> 27) | (raw[3] << 5); + } } /* Repacks the Product Key. */ void packXP(ul32 *raw, ul32 *serial, ul32 *hash, ul32 *sig) { - raw[0] = serial[0] | ((hash[0] & 1) << 31); - raw[1] = (hash[0] >> 1) | ((sig[0] & 0x1f) << 27); - raw[2] = (sig[0] >> 5) | (sig[1] << 27); - raw[3] = sig[1] >> 5; + raw[0] = serial[0] | ((hash[0] & 1) << 31); + raw[1] = (hash[0] >> 1) | ((sig[0] & 0x1f) << 27); + raw[2] = (sig[0] >> 5) | (sig[1] << 27); + raw[3] = sig[1] >> 5; } /* Verify Product Key */ -void verifyXPKey(EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *publicKey, char *cdKey) { - byte pKey[PK_LENGTH]; +bool verifyXPKey(EC_GROUP *eCurve, EC_POINT *generator, EC_POINT *publicKey, char *cdKey) { + BN_CTX *context = BN_CTX_new(); + + // Convert Base24 CD-key to bytecode. + ul32 bKey[4]{}; + ul32 pID, hash, sig[2]; - BN_CTX *context = BN_CTX_new(); - - // Remove dashes from the CD-pKey. - for (int i = 0, k = 0; i < strlen(cdKey) && k < PK_LENGTH; i++) { - for (int j = 0; j < PK_LENGTH - 1; j++) { - if (cdKey[i] != '-' && cdKey[i] == charset[j]) { - pKey[k++] = j; - break; - } - } - - if (k >= PK_LENGTH) break; - } - - // Convert Base24 CD-pKey to bytecode. - ul32 bKey[4]{}; - ul32 pID[1], hash[1], sig[2]; - - unbase24(bKey, pKey); + unbase24(bKey, cdKey); - // Output CD-pKey bytecode. - printf("Bytecode: %.8lX %.8lX %.8lX %.8lX\n", bKey[3], bKey[2], bKey[1], bKey[0]); + // Output CD-key bytecode. + printf("Bytecode: %.8lX %.8lX %.8lX %.8lX\n", bKey[3], bKey[2], bKey[1], bKey[0]); // Extract data, hash and signature from the bytecode. - unpackXP(pID, hash, sig, bKey); - printProductID(pID); - - printf("PID: %.8lX\nHash: %.8lX\nSignature: %.8lX %.8lX\n", pID[0], hash[0], sig[1], sig[0]); + unpackXP(&pID, &hash, sig, bKey); + printProductID(&pID); + + printf("PID: %.8lX\nHash: %.8lX\nSignature: %.8lX %.8lX\n", pID, hash, sig[1], sig[0]); // e = Hash // s = Signature - BIGNUM *e, *s; + BIGNUM *e, *s; // Put hash word into BigNum e. - e = BN_new(); - BN_set_word(e, hash[0]); + e = BN_new(); + BN_set_word(e, hash); // Reverse signature and create a new BigNum s. - endiannessConvert((unsigned char *) sig, sizeof(sig)); - s = BN_bin2bn((unsigned char *)sig, sizeof(sig), nullptr); + endiannessConvert((byte *) sig, sizeof(sig)); + s = BN_bin2bn((byte *)sig, sizeof(sig), nullptr); // Create x and y. - BIGNUM *x = BN_new(); - BIGNUM *y = BN_new(); + BIGNUM *x = BN_new(); + BIGNUM *y = BN_new(); // Create 2 new points on the existing elliptic curve. - EC_POINT *u = EC_POINT_new(eCurve); - EC_POINT *v = EC_POINT_new(eCurve); + EC_POINT *u = EC_POINT_new(eCurve); + EC_POINT *v = EC_POINT_new(eCurve); // EC_POINT_mul calculates r = generator * n + q * m. - // v = s * generator + e * (-publicKey) + // v = s * generator + e * (-publicKey) // u = generator * s - EC_POINT_mul(eCurve, u, nullptr, generator, s, context); + EC_POINT_mul(eCurve, u, nullptr, generator, s, context); // v = publicKey * e - EC_POINT_mul(eCurve, v, nullptr, publicKey, e, context); + EC_POINT_mul(eCurve, v, nullptr, publicKey, e, context); // v += u - EC_POINT_add(eCurve, v, u, v, context); + EC_POINT_add(eCurve, v, u, v, context); - // EC_POINT_get_affine_coordinates() sets x and y, either of which may be NULL, to the corresponding coordinates of p. + // EC_POINT_get_affine_coordinates() sets x and y, either of which may be nullptr, to the corresponding coordinates of p. // x = v.x; y = v.y; - EC_POINT_get_affine_coordinates(eCurve, v, x, y, context); + EC_POINT_get_affine_coordinates(eCurve, v, x, y, context); - byte buf[FIELD_BYTES], md[SHA_DIGEST_LENGTH], t[4]; - ul32 h; + byte buf[FIELD_BYTES], md[SHA_DIGEST_LENGTH], t[4]; + ul32 newHash; - SHA_CTX hContext; + SHA_CTX hContext; // h = First32(SHA-1(pID || v.x || v.y)) >> 4 - SHA1_Init(&hContext); + SHA1_Init(&hContext); // Chop Product ID into 4 bytes. - t[0] = pID[0] & 0xff; // First 8 bits - t[1] = (pID[0] & 0xff00) >> 8; // Second 8 bits - t[2] = (pID[0] & 0xff0000) >> 16; // Third 8 bits - t[3] = (pID[0] & 0xff000000) >> 24; // Fourth 8 bits + t[0] = (pID & 0xff); // First 8 bits + t[1] = (pID & 0xff00) >> 8; // Second 8 bits + t[2] = (pID & 0xff0000) >> 16; // Third 8 bits + t[3] = (pID & 0xff000000) >> 24; // Fourth 8 bits // Hash chunk of data. - SHA1_Update(&hContext, t, sizeof(t)); + SHA1_Update(&hContext, t, sizeof(t)); - // Empty buffer, place v.x in little-endiannessConvert. - memset(buf, 0, sizeof(buf)); - BN_bn2bin(x, buf); - endiannessConvert((unsigned char *) buf, sizeof(buf)); + // Empty buffer, place v.x in little-endian. + memset(buf, 0, FIELD_BYTES); + BN_bn2bin(x, buf); + endiannessConvert(buf, FIELD_BYTES); // Hash chunk of data. - SHA1_Update(&hContext, buf, sizeof(buf)); + SHA1_Update(&hContext, buf, FIELD_BYTES); - // Empty buffer, place v.y in little-endiannessConvert. - memset(buf, 0, sizeof(buf)); - BN_bn2bin(y, buf); - endiannessConvert((unsigned char *) buf, sizeof(buf)); + // Empty buffer, place v.y in little-endian. + memset(buf, 0, FIELD_BYTES); + BN_bn2bin(y, buf); + endiannessConvert(buf, FIELD_BYTES); // Hash chunk of data. - SHA1_Update(&hContext, buf, sizeof(buf)); + SHA1_Update(&hContext, buf, FIELD_BYTES); // Store the final message from hContext in md. - SHA1_Final(md, &hContext); + SHA1_Final(md, &hContext); // h = First32(SHA-1(pID || v.x || v.y)) >> 4 - h = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) >> 4; - h &= 0xfffffff; - - printf("Calculated hash: %.8lX\n", h); - - // If we managed to generateXPKey a pKey with the same hash, the pKey is correct. - if (h == hash[0]) cprintf("Key valid\n", 0x0A); - else cprintf("Key invalid\n", 0x0C); - - putchar('\n'); - - BN_free(e); - BN_free(s); - BN_free(x); - BN_free(y); + newHash = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) >> 4; + newHash &= 0xfffffff; + + printf("Calculated hash: %.8lX\n", newHash); + + BN_free(e); + BN_free(s); + BN_free(x); + BN_free(y); BN_CTX_free(context); - EC_POINT_free(u); - EC_POINT_free(v); + EC_POINT_free(u); + EC_POINT_free(v); + + // If we managed to generateXPKey a pKey with the same hash, the pKey is correct. + if (newHash == hash) return true; + else return false; } /* Generate a valid Product Key. */ -void generateXPKey(byte *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *order, BIGNUM *privateKey, ul32 *pRaw, ul32 *hash, ul32 *sig) { +void generateXPKey(char *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *order, BIGNUM *privateKey, ul32 *pRaw) { EC_POINT *r = EC_POINT_new(eCurve); BN_CTX *ctx = BN_CTX_new(); - BIGNUM *c = BN_new(); - BIGNUM *s = BN_new(); - BIGNUM *x = BN_new(); - BIGNUM *y = BN_new(); + BIGNUM *c = BN_new(); + BIGNUM *s = BN_new(); + BIGNUM *x = BN_new(); + BIGNUM *y = BN_new(); - ul32 bKey[4]{}; + ul32 bKey[4]{}; + + do { + ul32 hash = 0, sig[2]{}; - do { memset(bKey, 0, 4); // Generate a random number c consisting of 384 bits without any constraints. - BN_rand(c, FIELD_BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); + BN_rand(c, FIELD_BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); // r = generator * c; - EC_POINT_mul(eCurve, r, nullptr, generator, c, ctx); + EC_POINT_mul(eCurve, r, nullptr, generator, c, ctx); // x = r.x; y = r.y; - EC_POINT_get_affine_coordinates(eCurve, r, x, y, ctx); - - SHA_CTX hContext; - byte md[SHA_DIGEST_LENGTH], buf[FIELD_BYTES], t[4]; + EC_POINT_get_affine_coordinates(eCurve, r, x, y, ctx); + + SHA_CTX hContext; + byte md[SHA_DIGEST_LENGTH]{}, buf[FIELD_BYTES]{}, t[4]{}; // h = (First-32(SHA1(pRaw, r.x, r.y)) >> 4 - SHA1_Init(&hContext); + SHA1_Init(&hContext); // Chop Raw Product Key into 4 bytes. - t[0] = pRaw[0] & 0xff; - t[1] = (pRaw[0] & 0xff00) >> 8; - t[2] = (pRaw[0] & 0xff0000) >> 16; - t[3] = (pRaw[0] & 0xff000000) >> 24; + t[0] = (*pRaw & 0xff); + t[1] = (*pRaw & 0xff00) >> 8; + t[2] = (*pRaw & 0xff0000) >> 16; + t[3] = (*pRaw & 0xff000000) >> 24; // Hash chunk of data. - SHA1_Update(&hContext, t, sizeof(t)); + SHA1_Update(&hContext, t, sizeof(t)); // Empty buffer, place r.x in little-endiannessConvert. - memset(buf, 0, sizeof(buf)); - BN_bn2bin(x, buf); - endiannessConvert((unsigned char *) buf, sizeof(buf)); + memset(buf, 0, FIELD_BYTES); + BN_bn2bin(x, buf); + endiannessConvert(buf, FIELD_BYTES); // Hash chunk of data. - SHA1_Update(&hContext, buf, sizeof(buf)); + SHA1_Update(&hContext, buf, FIELD_BYTES); // Empty buffer, place r.y in little-endiannessConvert. - memset(buf, 0, sizeof(buf)); - BN_bn2bin(y, buf); - endiannessConvert((unsigned char *) buf, sizeof(buf)); + memset(buf, 0, FIELD_BYTES); + BN_bn2bin(y, buf); + endiannessConvert(buf, FIELD_BYTES); // Hash chunk of data. - SHA1_Update(&hContext, buf, sizeof(buf)); + SHA1_Update(&hContext, buf, FIELD_BYTES); // Store the final message from hContext in md. - SHA1_Final(md, &hContext); + SHA1_Final(md, &hContext); // h = (First-32(SHA1(pRaw, r.x, r.y)) >> 4 - *hash = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) >> 4; - *hash &= 0xfffffff; - - /* s = privateKey * hash + c; */ + hash = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) >> 4; + hash &= 0xfffffff; + + /* s = privateKey * hash + c; */ // s = privateKey; - BN_copy(s, privateKey); + BN_copy(s, privateKey); // s *= hash; - BN_mul_word(s, *hash); + BN_mul_word(s, hash); // BN_mod_add() adds a to b % m and places the non-negative result in r. // s = |s + c % order|; - BN_mod_add(s, s, c, order, ctx); + BN_mod_add(s, s, c, order, ctx); // Convert s from BigNum back to bytecode and reverse the endianness. - BN_bn2bin(s, (byte *)sig); - endiannessConvert((byte *) sig, BN_num_bytes(s)); + BN_bn2bin(s, (byte *)sig); + endiannessConvert((byte *)sig, BN_num_bytes(s)); // Pack product key. - packXP(bKey, pRaw, hash, sig); + packXP(bKey, pRaw, &hash, sig); - printf("PID: %.8lX\nHash: %.8lX\nSignature: %.8lX %.8lX\n\n", pRaw[0], *hash, sig[1], sig[0]); - } while (bKey[3] >= 0x40000); + printf("PID: %.8lX\nHash: %.8lX\nSignature: %.8lX %.8lX\n\n", *pRaw, hash, sig[1], sig[0]); + } while (bKey[3] >= 0x40000); // ↑ ↑ ↑ // bKey[3] can't be longer than 18 bits, else the signature part will make // the CD-key longer than 25 characters. // Convert the key to Base24. - base24(pKey, bKey); - - BN_free(c); - BN_free(s); - BN_free(x); - BN_free(y); + base24(pKey, bKey); + + BN_free(c); + BN_free(s); + BN_free(x); + BN_free(y); BN_CTX_free(ctx); - EC_POINT_free(r); + EC_POINT_free(r); } -int keyXP(char *pKey, ul32 *hash, ul32 *sig, ul32 nRaw) { - assert(nRaw <= 1'000'000'000); +bool keyXP(char *pKey, ul32 nRaw) { + assert(nRaw <= 1'000'000'000); - // We cannot produce a valid key without knowing the private key k. The reason for this is that - // we need the result of the function K(x; y) = kG(x; y). - BIGNUM *privateKey = BN_new(); + // We cannot produce a valid key without knowing the private key k. The reason for this is that + // we need the result of the function K(x; y) = kG(x; y). + BIGNUM *privateKey = BN_new(); - // We can, however, validate any given key using the available public key: {p, a, b, G, K}. - // genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm. - BIGNUM *genOrder = BN_new(); + // We can, however, validate any given key using the available public key: {p, a, b, G, K}. + // genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm. + BIGNUM *genOrder = BN_new(); - /* Computed data */ - BN_hex2bn(&genOrder, genOrderXP); - BN_hex2bn(&privateKey, privateKeyXP); + /* Computed data */ + BN_hex2bn(&genOrder, genOrderXP); + BN_hex2bn(&privateKey, privateKeyXP); - EC_POINT *genPoint, *pubPoint; - EC_GROUP *eCurve = initializeEllipticCurve( - pXP, - aXP, - bXP, - genXXP, - genYXP, - pubXXP, - pubYXP, - genOrder, - privateKey, - &genPoint, - &pubPoint - ); + EC_POINT *genPoint, *pubPoint; + EC_GROUP *eCurve = initializeEllipticCurve( + pXP, + aXP, + bXP, + genXXP, + genYXP, + pubXXP, + pubYXP, + genOrder, + privateKey, + &genPoint, + &pubPoint + ); - // Shift left once. - nRaw <<= 1; + // Shift left once. + nRaw <<= 1; - cprintf("Product Key:", 0x0A); + cprintf("Product Key:", 0x0A); - // Generate the key. - generateXPKey((byte *)pKey, eCurve, genPoint, genOrder, privateKey, &nRaw, hash, sig); - printProductKey(pKey); + // Generate the key. + generateXPKey(pKey, eCurve, genPoint, genOrder, privateKey, &nRaw); + printProductKey(pKey); - printf("\n\n"); + printf("\n\n"); - // Verify the key. - verifyXPKey(eCurve, genPoint, pubPoint, pKey); - - return 0; + // Verify the key. + return verifyXPKey(eCurve, genPoint, pubPoint, pKey); } \ No newline at end of file