diff --git a/header.h b/header.h index 5ac47d7..93ed1e3 100644 --- a/header.h +++ b/header.h @@ -31,12 +31,23 @@ #define FIELD_BYTES_2003 64 typedef unsigned char byte; -typedef unsigned long ul32; +typedef uint32_t ul32; extern char charset[]; // util.cpp void endian(byte *data, int length); +EC_GROUP *initializeEllipticCurve( + const char *pSel, + const char *aSel, + const char *bSel, + const char *generatorXSel, + const char *generatorYSel, + const char *publicKeyXSel, + const char *publicKeyYSel, + EC_POINT **genPoint, + EC_POINT **pubPoint +); // key.cpp void unbase24(ul32 *byteSeq, const char *cdKey); diff --git a/main.cpp b/main.cpp index 6f3f1a1..6e18c7e 100644 --- a/main.cpp +++ b/main.cpp @@ -3,13 +3,15 @@ // #include "header.h" +#include char charset[] = "BCDFGHJKMPQRTVWXY2346789"; using json = nlohmann::json; -int main() -{ +int main() { + char* BINKID = "2E"; + std::ifstream f("keys.json"); json keys = json::parse(f); @@ -17,70 +19,79 @@ int main() srand(time(nullptr)); rand(); - // Init - BIGNUM *a, *b, *p, *gx, *gy, *pubx, *puby, *n, *priv; - BN_CTX *ctx = BN_CTX_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(); - // make BigNumbers - a = BN_new(); - b = BN_new(); - p = BN_new(); - gx = BN_new(); - gy = BN_new(); - pubx = BN_new(); - puby = BN_new(); - n = BN_new(); - priv = 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(); - char* BINKID = "2E"; + /* Computed data */ + BN_dec2bn(&genOrder, keys["BINK"][BINKID]["n"].get().c_str()); + BN_dec2bn(&privateKey, keys["BINK"][BINKID]["priv"].get().c_str()); - // Data from pidgen-Bink-resources - /* Elliptic curve parameters: y^2 = x^3 + ax + b mod p */ - BN_dec2bn(&p, keys["BINK"][BINKID]["p"].get().c_str()); - BN_dec2bn(&a, keys["BINK"][BINKID]["a"].get().c_str()); - BN_dec2bn(&b, keys["BINK"][BINKID]["b"].get().c_str()); + std::cout << keys["BINK"][BINKID]["p"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["a"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["b"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["g"]["x"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["g"]["y"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["pub"]["x"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["pub"]["y"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["n"].get().c_str() << std::endl; + std::cout << keys["BINK"][BINKID]["priv"].get().c_str() << std::endl; + EC_POINT *genPoint, *pubPoint; + EC_GROUP *eCurve = initializeEllipticCurve( + keys["BINK"][BINKID]["p"].get().c_str(), + keys["BINK"][BINKID]["a"].get().c_str(), + keys["BINK"][BINKID]["b"].get().c_str(), + keys["BINK"][BINKID]["g"]["x"].get().c_str(), + keys["BINK"][BINKID]["g"]["y"].get().c_str(), + keys["BINK"][BINKID]["pub"]["x"].get().c_str(), + keys["BINK"][BINKID]["pub"]["y"].get().c_str(), + &genPoint, + &pubPoint + ); - /* base point (generator) G */ - BN_dec2bn(&gx, keys["BINK"][BINKID]["g"]["x"].get().c_str()); - BN_dec2bn(&gy, keys["BINK"][BINKID]["g"]["y"].get().c_str()); - - /* inverse of public key */ - BN_dec2bn(&pubx, keys["BINK"][BINKID]["pub"]["x"].get().c_str()); - BN_dec2bn(&puby, keys["BINK"][BINKID]["pub"]["y"].get().c_str()); - - // Computed data - /* order of G - computed in 18 hours using a P3-450 */ - BN_dec2bn(&n, keys["BINK"][BINKID]["n"].get().c_str()); - - /* THE private key - computed in 10 hours using a P3-450 */ - BN_dec2bn(&n, keys["BINK"][BINKID]["priv"].get().c_str()); - + /*BN_print_fp(stdout, p); + std::cout << std::endl; + BN_print_fp(stdout, a); + std::cout << std::endl; + BN_print_fp(stdout, b); + std::cout << std::endl; + BN_print_fp(stdout, gx); + std::cout << std::endl; + BN_print_fp(stdout, gy); + std::cout << std::endl; + BN_print_fp(stdout, pubx); + std::cout << std::endl; + BN_print_fp(stdout, puby); + std::cout << std::endl; + BN_print_fp(stdout, n); + std::cout << std::endl; + BN_print_fp(stdout, priv); + std::cout << std::endl;*/ // Calculation - EC_GROUP *ec = EC_GROUP_new_curve_GFp(p, a, b, ctx); - EC_POINT *g = EC_POINT_new(ec); - EC_POINT_set_affine_coordinates_GFp(ec, g, gx, gy, ctx); - EC_POINT *pub = EC_POINT_new(ec); - EC_POINT_set_affine_coordinates_GFp(ec, pub, pubx, puby, ctx); - char pkey[26]; - ul32 pid[1]; - pid[0] = 640 * 1000000 ; /* <- change */ - pid[0] += rand() & 999999; - printf("> PID: %lu\n", pid[0]); + char pKey[25]; + + ul32 nRaw = 640 * 1000000 ; /* <- change */ + //nRaw += rand() & 999999; + + printf("> PID: %lu\n", nRaw); // generate a key - BN_sub(priv, n, priv); - generateXPKey(pkey, ec, g, n, priv, pid); - print_product_key(pkey); + BN_sub(privateKey, genOrder, privateKey); + nRaw <<= 1; + + generateXPKey(pKey, eCurve, genPoint, genOrder, privateKey, &nRaw); + print_product_key(pKey); printf("\n\n"); // verify the key - verifyXPKey(ec, g, pub, (char*)pkey); - - // Cleanup - BN_CTX_free(ctx); + if (!verifyXPKey(eCurve, genPoint, pubPoint, pKey)) printf("Fail! Key is invalid.\n"); return 0; } \ No newline at end of file diff --git a/util.cpp b/util.cpp index e73f8b4..2984fdf 100644 --- a/util.cpp +++ b/util.cpp @@ -12,3 +12,71 @@ void endian(byte *data, int length) { data[length - i - 1] = temp; } } + +/* Initializes the elliptic curve. */ +EC_GROUP *initializeEllipticCurve( + const char *pSel, + const char *aSel, + const char *bSel, + const char *generatorXSel, + const char *generatorYSel, + const char *publicKeyXSel, + const char *publicKeyYSel, + EC_POINT **genPoint, + EC_POINT **pubPoint +) { + // Initialize BIGNUM and BIGNUMCTX structures. + // BIGNUM - Large numbers + // BIGNUMCTX - Context large numbers (temporary) + BIGNUM *a, *b, *p, *generatorX, *generatorY, *publicKeyX, *publicKeyY; + BN_CTX *context; + + // 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(); + + // Context variable + context = BN_CTX_new(); + + /* Public data */ + BN_dec2bn(&p, pSel); + BN_dec2bn(&a, aSel); + BN_dec2bn(&b, bSel); + BN_dec2bn(&generatorX, generatorXSel); + BN_dec2bn(&generatorY, generatorYSel); + + BN_dec2bn(&publicKeyX, publicKeyXSel); + BN_dec2bn(&publicKeyY, publicKeyYSel); + + /* Elliptic 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). + *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). + *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); + + // Cleanup + BN_CTX_free(context); + + return eCurve; +} \ No newline at end of file diff --git a/xp.cpp b/xp.cpp index ca92e12..f27a14c 100644 --- a/xp.cpp +++ b/xp.cpp @@ -230,6 +230,8 @@ void generateXPKey(char *pKey, EC_GROUP *eCurve, EC_POINT *generator, BIGNUM *or // Pack product key. packXP(bKey, pRaw, &hash, sig); + + printf("PID: %.8lX\nHash: %.8lX\nSig: %.8lX %.8lX\n", pRaw[0], hash, sig[1], sig[0]); } while (bKey[3] >= 0x40000); // ↑ ↑ ↑ // bKey[3] can't be longer than 18 bits, else the signature part will make