diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..62f2531 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.24) +project(Keygen) + +set(CMAKE_CXX_STANDARD 14) + +add_executable( + Keygen + main.cpp +) +target_link_libraries(Keygen ${CMAKE_CURRENT_SOURCE_DIR}/lib/libcrypto.lib -static) \ No newline at end of file diff --git a/lib/engines-3/capi.dll b/lib/engines-3/capi.dll new file mode 100644 index 0000000..3663a84 Binary files /dev/null and b/lib/engines-3/capi.dll differ diff --git a/lib/engines-3/capi.pdb b/lib/engines-3/capi.pdb new file mode 100644 index 0000000..0fa046a Binary files /dev/null and b/lib/engines-3/capi.pdb differ diff --git a/lib/engines-3/loader_attic.dll b/lib/engines-3/loader_attic.dll new file mode 100644 index 0000000..ed9bca4 Binary files /dev/null and b/lib/engines-3/loader_attic.dll differ diff --git a/lib/engines-3/loader_attic.pdb b/lib/engines-3/loader_attic.pdb new file mode 100644 index 0000000..424f7e1 Binary files /dev/null and b/lib/engines-3/loader_attic.pdb differ diff --git a/lib/engines-3/padlock.dll b/lib/engines-3/padlock.dll new file mode 100644 index 0000000..2e5a523 Binary files /dev/null and b/lib/engines-3/padlock.dll differ diff --git a/lib/engines-3/padlock.pdb b/lib/engines-3/padlock.pdb new file mode 100644 index 0000000..051abb4 Binary files /dev/null and b/lib/engines-3/padlock.pdb differ diff --git a/lib/libcrypto.lib b/lib/libcrypto.lib new file mode 100644 index 0000000..7ffaf98 Binary files /dev/null and b/lib/libcrypto.lib differ diff --git a/lib/libssl.lib b/lib/libssl.lib new file mode 100644 index 0000000..66fa1fc Binary files /dev/null and b/lib/libssl.lib differ diff --git a/lib/ossl-modules/legacy.dll b/lib/ossl-modules/legacy.dll new file mode 100644 index 0000000..4d2b055 Binary files /dev/null and b/lib/ossl-modules/legacy.dll differ diff --git a/lib/ossl-modules/legacy.pdb b/lib/ossl-modules/legacy.pdb new file mode 100644 index 0000000..62236b4 Binary files /dev/null and b/lib/ossl-modules/legacy.pdb differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..de22aff --- /dev/null +++ b/main.cpp @@ -0,0 +1,601 @@ +/* + Windows XP CD Key Verification/Generator v0.03 + by z22 + + Compile with OpenSSL libs, modify to suit your needs. + http://gnuwin32.sourceforge.net/packages/openssl.htm + + History: + 0.03 Stack corruptionerror on exit fixed (now pkey is large enough) + More Comments added + 0.02 Changed name the *.cpp; + Fixed minor bugs & Make it compilable on VC++ + 0.01 First version compilable MingW + + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#define FIELD_BITS 384 +#define FIELD_BYTES 48 + +typedef unsigned char U8; +typedef unsigned long U32; + +HANDLE hConsole; +unsigned char charset[] = "BCDFGHJKMPQRTVWXY2346789"; + +/* Colored output */ +VOID cprintf(CONST CHAR *Format, INT nColor, ...) { + va_list vList; + + va_start(vList, nColor); + + SetConsoleTextAttribute(hConsole, nColor); + vprintf(Format, vList); + SetConsoleTextAttribute(hConsole, 0x0F); + + va_end(vList); + + return; +} + +/* Unpacks the Product Key. */ +void extract(unsigned long *serial, unsigned long *hash, unsigned long *sig, unsigned long *raw) { + + // We're assuming that the quantity of information within the product key is at most 114 bits. + // log2(24^25) = 114. + + // Serial = Bits [0..30] -> 31 bits + serial[0] = raw[0] & 0x7fffffff; + + // Hash (e) = Bits [31..58] -> 28 bits + 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); +} + +/* Repacks the Product Key. */ +void pack(unsigned long *raw, unsigned long *serial, unsigned long *hash, unsigned long *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; +} + +/* Convert data between endianness types. */ +void endiannessConvert(unsigned char *data, int length) { + for (int i = 0; i < length / 2; i++) { + unsigned char temp = data[i]; + data[i] = data[length - i - 1]; + data[length - i - 1] = temp; + } +} + +/* Convert from byte sequence to the CD-key. */ +void base24(unsigned char *cdKey, unsigned long *byteSeq) { + unsigned char rbs[16]; + BIGNUM *z; + + // Copy byte sequence to the reversed byte sequence. + memcpy(rbs, byteSeq, sizeof(rbs)); + + // Skip trailing zeroes and reverse y. + int length; + + for (length = 15; rbs[length] == 0; length--); + endiannessConvert(rbs, ++length); + + // Convert reversed byte sequence to BigNum z. + z = BN_bin2bn(rbs, length, nullptr); + + // Divide z by 24 and convert the remainder to a CD-key char. + cdKey[25] = 0; + + for (int i = 24; i >= 0; i--) + cdKey[i] = charset[BN_div_word(z, 24)]; + + BN_free(z); +} + +/* Convert from CD-key to a byte sequence. */ +void unbase24(unsigned long *byteSeq, unsigned char *cdKey) { + BIGNUM *y = BN_new(); + BN_zero(y); + + // 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]); + } + + // Acquire length. + int n = BN_num_bytes(y); + + // Place the generated code into the byte sequence. + BN_bn2bin(y, (unsigned char *)byteSeq); + BN_free(y); + + // Reverse the byte sequence. + endiannessConvert((unsigned char *) byteSeq, n); +} + +/* Print Product ID using a Product Key. */ +void printProductID(unsigned long *pKey) { + char raw[12]; + char b[6], c[8]; + + // Cut away last bit of the product key and convert it to an ASCII-number (=raw) + sprintf(raw, "%lu", pKey[0] >> 1); + + // Make B-part {...-640-...} -> most significant 3 digits of Raw Product Key + strncpy(b, raw, 3); + b[3] = 0; + + // Make C-part {...-123456X-...} -> least significant 6 digits of Raw Product Key + strcpy(c, raw + 3); + + // Make checksum digit-part {...56X-} + assert(strlen(c) == 6); + + int digit = 0; + + // Reverse sum algorithm to find a check digit that would add to the rest to form a sum divisible by 7. + for (int i = 0; i < 6; i++) + digit -= c[i] - '0'; + + while (digit < 0) + digit += 7; + + // Append check digit + null terminate. + c[6] = digit + '0'; + c[7] = 0; + + printf("Product ID: "); + cprintf("PPPPP-%s-%s-23XXX\n", 0x0E, b, c); +} + +/* Print Product Key. */ +void printProductKey(unsigned char *pKey) { + assert(strlen((const char *)pKey) == 25); + + SetConsoleTextAttribute(hConsole, 0x0A); + + for (int i = 0; i < 25; i++) { + putchar(pKey[i]); + if (i != 24 && i % 5 == 4) putchar('-'); + } + + SetConsoleTextAttribute(hConsole, 0x0F); +} + +/* Verify Product Key */ +void verifyKey(EC_GROUP *ec, EC_POINT *generator, EC_POINT *publicKey, char *cdKey) { + unsigned char key[25]; + + BN_CTX *ctx = BN_CTX_new(); + + // Remove dashes from the CD-key. + for (int i = 0, k = 0; i < strlen(cdKey) && k < 25; i++) { + for (int j = 0; j < 24; j++) { + if (cdKey[i] != '-' && cdKey[i] == charset[j]) { + key[k++] = j; + break; + } + + // Make sure the CD-key passes the verification procedure. + assert(j < 24); + } + } + + // Convert Base24 CD-key to bytecode. + unsigned long bKey[4]{}; + unsigned long pID[1], hash[1], sig[2]; + + unbase24(bKey, key); + + // Output CD-key bytecode. + printf("Bytecode: %.8lX %.8lX %.8lX %.8lX\n", bKey[3], bKey[2], bKey[1], bKey[0]); + + // Extract pid_data, hash and signature from the bytecode. + extract(pID, hash, sig, bKey); + printProductID(pID); + + printf("PID: %.8lX\nHash: %.8lX\nSignature: %.8lX %.8lX\n", pID[0], hash[0], sig[1], sig[0]); + + // e = Hash + // s = Signature + BIGNUM *e, *s; + + // Put hash word into BigNum e. + e = BN_new(); + BN_set_word(e, hash[0]); + + // Reverse signature and create a new BigNum s. + endiannessConvert((unsigned char *) sig, sizeof(sig)); + s = BN_bin2bn((unsigned char *)sig, sizeof(sig), nullptr); + + // Create x and y. + BIGNUM *x = BN_new(); + BIGNUM *y = BN_new(); + + // Create 2 new points on the existing elliptic curve. + EC_POINT *u = EC_POINT_new(ec); + EC_POINT *v = EC_POINT_new(ec); + + + // EC_POINT_mul calculates r = generator * n + q * m. + // v = s * generator + e * (-publicKey) + + // u = generator * s + EC_POINT_mul(ec, u, nullptr, generator, s, ctx); + + // v = publicKey * e + EC_POINT_mul(ec, v, nullptr, publicKey, e, ctx); + + // v += u + EC_POINT_add(ec, v, u, v, ctx); + + // EC_POINT_get_affine_coordinates() sets x and y, either of which may be NULL, to the corresponding coordinates of p. + // x = v.x; y = v.y; + EC_POINT_get_affine_coordinates(ec, v, x, y, ctx); + + + unsigned char buf[FIELD_BYTES], md[SHA_DIGEST_LENGTH], t[4]; + unsigned long h; + + SHA_CTX hContext; + + /* h = (first 32 bits of SHA1(pID || v.x, v.y)) >> 4 */ + 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 + + // Hash chunk of data. + SHA1_Update(&hContext, t, sizeof(t)); + + // Empty buffer, place v.x in little-endian. + memset(buf, 0, sizeof(buf)); + BN_bn2bin(x, buf); + endiannessConvert((unsigned char *) buf, sizeof(buf)); + + // Hash chunk of data. + SHA1_Update(&hContext, buf, sizeof(buf)); + + // Empty buffer, place v.y in little-endian. + memset(buf, 0, sizeof(buf)); + BN_bn2bin(y, buf); + endiannessConvert((unsigned char *) buf, sizeof(buf)); + + // Hash chunk of data. + SHA1_Update(&hContext, buf, sizeof(buf)); + + // Store the final message from hContext in md. + SHA1_Final(md, &hContext); + + // h = (first 32 bits of SHA1(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 generateKey a key with the same hash, the key 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); + + BN_CTX_free(ctx); + + EC_POINT_free(u); + EC_POINT_free(v); +} + +/* Generate a valid Product Key. */ +void generateKey(unsigned char *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *order, BIGNUM *privateKey, unsigned long *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(); + + unsigned long bKey[4]; + + do { + // 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); + + // r = generator * c; + EC_POINT_mul(eCurve, r, NULL, generator, c, ctx); + + // x = r.x; y = r.y; + EC_POINT_get_affine_coordinates(eCurve, r, x, y, ctx); + + SHA_CTX hContext; + unsigned char md[SHA_DIGEST_LENGTH], buf[FIELD_BYTES], t[4]; + unsigned long hash[1]; + + /* h = (fist 32 bits of SHA1(pRaw || r.x, r.y)) >> 4 */ + 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; + + // Hash chunk of data. + SHA1_Update(&hContext, t, sizeof(t)); + + // Empty buffer, place r.x in little-endian. + memset(buf, 0, sizeof(buf)); + BN_bn2bin(x, buf); + endiannessConvert((unsigned char *) buf, sizeof(buf)); + + // Hash chunk of data. + SHA1_Update(&hContext, buf, sizeof(buf)); + + // Empty buffer, place r.y in little-endian. + memset(buf, 0, sizeof(buf)); + BN_bn2bin(y, buf); + endiannessConvert((unsigned char *) buf, sizeof(buf)); + + // Hash chunk of data. + SHA1_Update(&hContext, buf, sizeof(buf)); + + // Store the final message from hContext in md. + SHA1_Final(md, &hContext); + + // h = (First-32(SHA1(pRaw, r.x, r.y)) >> 4 + hash[0] = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) >> 4; + hash[0] &= 0xfffffff; + + /* s = privateKey * hash + c; */ + // s = privateKey; + BN_copy(s, privateKey); + + // s *= hash; + BN_mul_word(s, hash[0]); + + // 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); + + // Convert s from BigNum back to bytecode and reverse the endianness. + unsigned long sig[2]{}; + + BN_bn2bin(s, (unsigned char *)sig); + endiannessConvert((unsigned char *) sig, BN_num_bytes(s)); + + // Pack product key. + pack(bKey, pRaw, hash, sig); + + printf("PID: %.8lX\nHash: %.8lX\nSignature: %.8lX %.8lX\n\n", pRaw[0], hash[0], sig[1], sig[0]); + } while (bKey[3] >= 0x62A32); // Loop in case 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); + + BN_CTX_free(ctx); + EC_POINT_free(r); +} + + +/* + * PK: VX8CG-8KC6V-PVPMD-GKPPH-GC7W8 + * + * The Windows XP product key is composed of 25 characters. The dashes store no information. + * The product key is encoded in Base24 with an alphabet of "BCDFGHJKMPQRTVWXY2346789" in order + * to avoid ambiguous characters (e.g. "I" and "1", "0" and "O"). + * + * To convert a 25-digit key to binary data, we need to: + * 1. Think of the key as of an array of bytes. Then convert the concatenated key VX8CG8KC6VPVPMDGKPPHGC7W8 + * into its Base24 representation ('B' = 0, 'C' = 1, 'D' = 2, ...) -> [ 13, 15, 22, 1, 4, ... ]. + * 2. Compute the decoded array in little-endian. + * 3. The decoded result is divided into sections: + * - 12 bits -> OS Family + * - 31 bits -> Hash + * - 62 bits -> Signature + * - 9 bits -> Prefix + * + * Product ID: AAAAA-BBB-CCCCCCC-DDEEE + * + * digits | length | encoding + * --------+---------+--------------------------------------- + * AAAAA | 17 bits | bit 0 to bit 16 of P1 + * BBB | 10 bits | bit 17 to bit 26 of P1 + * CCCCCCC | 28 bits | bit 27 to bit 31 of P1 (lower 5 bits) + * | | bit 0 to bit 22 of P2 (upper 23 bits) + * DDEEE | 17 bits | bit 23 to bit 31 of P2 (lower 9 bits) + * | | bit 0 to bit 7 of P3 (upper 8 bits) + * + * digits | meaning + * --------+------------------------------------------------- + * AAAAA | apparently always 55034 (in Windows XP RC1) + * BBB | most significant three digits of Raw Product Key + * | (see below) + * CCCCCCC | least significant six digits of Raw Product Key + * | plus check digit (see below) + * DD | index of the public key used to verify the + * | Product Key. Example: 22 for PRO version and 23 for VLK version + * EEE | random value (used for phone activation, different installation IDs are generated) + */ + + +int main() { + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + // Initialize BIGNUM and BIGNUMCTX structures. + // BIGNUM - Large numbers + // BIGNUMCTX - Context large numbers (temporary) + BIGNUM *a, *b, *p, *generatorX, *generatorY, *publicKeyX, *publicKeyY, *genOrder, *privateKey; + BN_CTX *context; + + // Microsoft Product Key identification program uses a public key stored in pidgen.dll's BINK resource, + // which is an Elliptic Curve Cryptography (ECC) public key. It can be decomposed into a following mathematical task: + + // We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where + // y^2 % p = x^3 + ax + b % p. + a = BN_new(); + b = BN_new(); + p = BN_new(); + + // Public key will consist of the resulting (x; y) values. + publicKeyX = BN_new(); + publicKeyY = BN_new(); + + // G(x; y) is a generator function, its return value represents a point on the elliptic curve. + generatorX = BN_new(); + generatorY = 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). + 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. + genOrder = BN_new(); + + // Context variable + context = BN_CTX_new(); + + + /* Public data */ + // Data taken from pidgen.dll BINK-resources + BN_hex2bn(&p, "92ddcf14cb9e71f4489a2e9ba350ae29454d98cb93bdbcc07d62b502ea12238ee904a8b20d017197aae0c103b32713a9"); + + BN_set_word(a, 1); + BN_set_word(b, 0); + + // Base point G (Generator) + BN_hex2bn(&generatorX, "46E3775ECE21B0898D39BEA57050D422A0AF989E497962BAEE2CB17E0A28D5360D5476B8DC966443E37A14F1AEF37742"); + BN_hex2bn(&generatorY, "7C8E741D2C34F4478E325469CD491603D807222C9C4AC09DDB2B31B3CE3F7CC191B3580079932BC6BEF70BE27604F65E"); + + // Inverse of the public key + BN_hex2bn(&publicKeyX, "5D8DBE75198015EC41C45AAB6143542EB098F6A5CC9CE4178A1B8A1E7ABBB5BC64DF64FAF6177DC1B0988AB00BA94BF8"); + BN_hex2bn(&publicKeyY, "23A2909A0B4803C89F910C7191758B48746CEA4D5FF07667444ACDB9512080DBCA55E6EBF30433672B894F44ACE92BFA"); + + + /* Computed data */ + // The order of G was computed in 18 hours using a Pentium III 450 + BN_hex2bn(&genOrder, "DB6B4C58EFBAFD"); + + // The private key was computed in 10 hours using a Pentium III 450 + BN_hex2bn(&privateKey, "565B0DFF8496C8"); + + + /* 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 *pub = EC_POINT_new(eCurve); + EC_POINT_set_affine_coordinates(eCurve, pub, publicKeyX, publicKeyY, context); + + + /* Generate a key. */ + unsigned char pKey[26]{}; + unsigned long pRaw[1]{}; + + /* + * Decoding the Product Key results in an example byte sequence. + * + * 0x6F 0xFA 0x95 0x45 0xFC 0x75 0xB5 0x52 0xBB 0xEF 0xB1 0x17 0xDA 0xCD 0x00 + * + * Of these 15 bytes the least significant four bytes contain the Raw + * Product Key in little endian byte order. The least significant bit is + * removed by shifting this 32-bit value (0x4595FA6F - remember the + * little endian byte order) to the left by one bit position, resulting + * in a Raw Product Key of 0x22CAFD37, or + * + * 583728439 + * + * in decimal notation. + */ + + SetConsoleTitleA("Windows XP VLK Keygen"); + + system("cls"); + cprintf("Windows XP VLK Keygen\n\n", 0x08); + + cprintf("Principle of Operation:\n", 0x0C); + printf("We need a valid Raw Product Key to generate the Product ID in form of AAAAA-BBB-CCCCCCS-DDEEE.\n\n"); + printf("AAAAA is the Windows XP Series constant - different for each version.\n"); + printf("Raw Product Key directly represents the BBB-CCCCCC part of the Product ID.\n"); + printf("S is a \"check bit\": it's picked so that the sum of all C digits with it added makes a number divisble by 7.\n"); + printf("DD is the index of the public key used to verify the Product Key.\n"); + printf("EEE is a random number used to generate a different Installation ID each time.\n\n"); + + printf("The Product Key itself can at most contain 114 bits of information, as per the alphabet capacity formula.\n"); + printf("Based on that, we unpack the 114-bit Raw Product Key into 3 ordered segments:\n"); + printf("\tData (31 bits), Hash (28 bits) and Signature (55 bits).\n\n"); + printf("Microsoft uses a really elegant Elliptic Curve Algorithm to validate the product keys.\n"); + printf("It is a public-key cryptographic system, thus Microsoft had to share the public key,\nand it's, in fact, stored within pidgen.dll.\n"); + printf("To crack the CD-key generation algorithm we must find the corresponding private key from the public key,\nwhich was conveniently computed before us.\n"); + printf("In general, there are 2 special cases for the Elliptic Curve leveraged in cryptography - F2m and Fp.\nMicrosoft used the latter.\n"); + printf("\ty^2 = x^3 + ax + b %% p.\n"); + printf("The task boils down to generating a valid Hash/Signature pair for the Raw Key we provided:\n"); + printf("\t1. We need to generate a random 384-bit number r, and define C = R(r.x, r.y) = rG.\n"); + printf("\t2. Hash = (First32Bits(SHA1(pRaw, r.x, r.y)) >> 4.\n"); + printf("\t3. Signature = privateKey * Hash + (C %% Order)\n"); + printf("Finally, we pack these components together, convert them to Base24 and get a valid Windows XP key.\n"); + + cprintf("Input Raw Product Key BBB-CCCCCC WITHOUT DASHES in range [100-000000; 999-999999]: ", 0x0E); + scanf_s("%lu", pRaw); + + printf("\n"); + + pRaw[0] <<= 1; + + + for (int i = 0; i < 10; i++) { + cprintf("Product Key %d:\n", 0x08, i + 1); + + generateKey(pKey, eCurve, genPoint, genOrder, privateKey, pRaw); + printProductKey(pKey); + + printf("\n\n"); + + // Verify the key + verifyKey(eCurve, genPoint, pub, (char *) pKey); + } + + + // Cleanup + BN_CTX_free(context); + + return 0; +} diff --git a/openssl/c_rehash.pl b/openssl/c_rehash.pl new file mode 100644 index 0000000..a98cffd --- /dev/null +++ b/openssl/c_rehash.pl @@ -0,0 +1,252 @@ +#!/usr/bin/env perl + +# WARNING: do not edit! +# Generated by makefile from tools\c_rehash.in +# Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +# Perl c_rehash script, scan all files in a directory +# and add symbolic links to their hash values. + +my $dir = ""; +my $prefix = ""; + +my $errorcount = 0; +my $openssl = $ENV{OPENSSL} || "openssl"; +my $pwd; +my $x509hash = "-subject_hash"; +my $crlhash = "-hash"; +my $verbose = 0; +my $symlink_exists=eval {symlink("",""); 1}; +my $removelinks = 1; + +## Parse flags. +while ( $ARGV[0] =~ /^-/ ) { + my $flag = shift @ARGV; + last if ( $flag eq '--'); + if ( $flag eq '-old') { + $x509hash = "-subject_hash_old"; + $crlhash = "-hash_old"; + } elsif ( $flag eq '-h' || $flag eq '-help' ) { + help(); + } elsif ( $flag eq '-n' ) { + $removelinks = 0; + } elsif ( $flag eq '-v' ) { + $verbose++; + } + else { + print STDERR "Usage error; try -h.\n"; + exit 1; + } +} + +sub help { + print "Usage: c_rehash [-old] [-h] [-help] [-v] [dirs...]\n"; + print " -old use old-style digest\n"; + print " -h or -help print this help text\n"; + print " -v print files removed and linked\n"; + exit 0; +} + +eval "require Cwd"; +if (defined(&Cwd::getcwd)) { + $pwd=Cwd::getcwd(); +} else { + $pwd=`pwd`; + chomp($pwd); +} + +# DOS/Win32 or Unix delimiter? Prefix our installdir, then search. +my $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; +$ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : ""); + +if (! -x $openssl) { + my $found = 0; + foreach (split /$path_delim/, $ENV{PATH}) { + if (-x "$_/$openssl") { + $found = 1; + $openssl = "$_/$openssl"; + last; + } + } + if ($found == 0) { + print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n"; + exit 0; + } +} + +if (@ARGV) { + @dirlist = @ARGV; +} elsif ($ENV{SSL_CERT_DIR}) { + @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR}; +} else { + $dirlist[0] = "$dir/certs"; +} + +if (-d $dirlist[0]) { + chdir $dirlist[0]; + $openssl="$pwd/$openssl" if (!-x $openssl); + chdir $pwd; +} + +foreach (@dirlist) { + if (-d $_ ) { + if ( -w $_) { + hash_dir($_); + } else { + print "Skipping $_, can't write\n"; + $errorcount++; + } + } +} +exit($errorcount); + +sub copy_file { + my ($src_fname, $dst_fname) = @_; + + if (open(my $in, "<", $src_fname)) { + if (open(my $out, ">", $dst_fname)) { + print $out $_ while (<$in>); + close $out; + } else { + warn "Cannot open $dst_fname for write, $!"; + } + close $in; + } else { + warn "Cannot open $src_fname for read, $!"; + } +} + +sub hash_dir { + my $dir = shift; + my %hashlist; + + print "Doing $dir\n"; + + if (!chdir $dir) { + print STDERR "WARNING: Cannot chdir to '$dir', $!\n"; + return; + } + + opendir(DIR, ".") || print STDERR "WARNING: Cannot opendir '.', $!\n"; + my @flist = sort readdir(DIR); + closedir DIR; + if ( $removelinks ) { + # Delete any existing symbolic links + foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { + if (-l $_) { + print "unlink $_\n" if $verbose; + unlink $_ || warn "Can't unlink $_, $!\n"; + } + } + } + FILE: foreach $fname (grep {/\.(pem|crt|cer|crl)$/} @flist) { + # Check to see if certificates and/or CRLs present. + my ($cert, $crl) = check_file($fname); + if (!$cert && !$crl) { + print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; + next; + } + link_hash_cert($fname) if ($cert); + link_hash_crl($fname) if ($crl); + } + + chdir $pwd; +} + +sub check_file { + my ($is_cert, $is_crl) = (0,0); + my $fname = $_[0]; + + open(my $in, "<", $fname); + while(<$in>) { + if (/^-----BEGIN (.*)-----/) { + my $hdr = $1; + if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) { + $is_cert = 1; + last if ($is_crl); + } elsif ($hdr eq "X509 CRL") { + $is_crl = 1; + last if ($is_cert); + } + } + } + close $in; + return ($is_cert, $is_crl); +} + +sub compute_hash { + my $fh; + if ( $^O eq "VMS" ) { + # VMS uses the open through shell + # The file names are safe there and list form is unsupported + if (!open($fh, "-|", join(' ', @_))) { + print STDERR "Cannot compute hash on '$fname'\n"; + return; + } + } else { + if (!open($fh, "-|", @_)) { + print STDERR "Cannot compute hash on '$fname'\n"; + return; + } + } + return (<$fh>, <$fh>); +} + +# Link a certificate to its subject name hash value, each hash is of +# the form . where n is an integer. If the hash value already exists +# then we need to up the value of n, unless its a duplicate in which +# case we skip the link. We check for duplicates by comparing the +# certificate fingerprints + +sub link_hash_cert { + link_hash($_[0], 'cert'); +} + +# Same as above except for a CRL. CRL links are of the form .r + +sub link_hash_crl { + link_hash($_[0], 'crl'); +} + +sub link_hash { + my ($fname, $type) = @_; + my $is_cert = $type eq 'cert'; + + my ($hash, $fprint) = compute_hash($openssl, + $is_cert ? "x509" : "crl", + $is_cert ? $x509hash : $crlhash, + "-fingerprint", "-noout", + "-in", $fname); + chomp $hash; + $hash =~ s/^.*=// if !$is_cert; + chomp $fprint; + return if !$hash; + $fprint =~ s/^.*=//; + $fprint =~ tr/://d; + my $suffix = 0; + # Search for an unused hash filename + my $crlmark = $is_cert ? "" : "r"; + while(exists $hashlist{"$hash.$crlmark$suffix"}) { + # Hash matches: if fingerprint matches its a duplicate cert + if ($hashlist{"$hash.$crlmark$suffix"} eq $fprint) { + my $what = $is_cert ? 'certificate' : 'CRL'; + print STDERR "WARNING: Skipping duplicate $what $fname\n"; + return; + } + $suffix++; + } + $hash .= ".$crlmark$suffix"; + if ($symlink_exists) { + print "link $fname -> $hash\n" if $verbose; + symlink $fname, $hash || warn "Can't symlink, $!"; + } else { + print "copy $fname -> $hash\n" if $verbose; + copy_file($fname, $hash); + } + $hashlist{$hash} = $fprint; +} diff --git a/openssl/libcrypto-3-x64.dll b/openssl/libcrypto-3-x64.dll new file mode 100644 index 0000000..5eaa018 Binary files /dev/null and b/openssl/libcrypto-3-x64.dll differ diff --git a/openssl/libcrypto-3-x64.pdb b/openssl/libcrypto-3-x64.pdb new file mode 100644 index 0000000..a936d87 Binary files /dev/null and b/openssl/libcrypto-3-x64.pdb differ diff --git a/openssl/libssl-3-x64.dll b/openssl/libssl-3-x64.dll new file mode 100644 index 0000000..1f8cdb8 Binary files /dev/null and b/openssl/libssl-3-x64.dll differ diff --git a/openssl/libssl-3-x64.pdb b/openssl/libssl-3-x64.pdb new file mode 100644 index 0000000..7c859ef Binary files /dev/null and b/openssl/libssl-3-x64.pdb differ diff --git a/openssl/openssl.exe b/openssl/openssl.exe new file mode 100644 index 0000000..edadb27 Binary files /dev/null and b/openssl/openssl.exe differ diff --git a/openssl/openssl.pdb b/openssl/openssl.pdb new file mode 100644 index 0000000..893cf2a Binary files /dev/null and b/openssl/openssl.pdb differ