diff --git a/.gitignore b/.gitignore
index 1100325..27e3db0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 build/*
+bink.h
 
 ### NotepadPP template
 # Notepad++ backups #
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e67783d..285f1e5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,17 +2,30 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
 PROJECT(WindowsXPKg)
 SET(CMAKE_CXX_STANDARD 17)
 
+set(OPENSSL_USE_STATIC_LIBS TRUE)
 find_package(PkgConfig REQUIRED)
 pkg_search_module(OPENSSL REQUIRED openssl)
 
 if (!OPENSSL_FOUND)
-    message(FATAL_ERROR "OpenSSL Not Found")
+    message(FATAL_ERROR "OpenSSL Development Libraries Not Found")
 endif()
 
-ADD_EXECUTABLE(xpkey xp_algorithm.cpp shared.cpp)
+# generate bink.h
+add_custom_command(
+        OUTPUT bink.h
+        COMMAND ${PROJECT_SOURCE_DIR}/convert_keys_to_cpp.py
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+        DEPENDS bink.h
+)
+
+set(BUILD_SHARED_LIBS OFF)
+set(CMAKE_EXE_LINKER_FLAGS "-static")
+ADD_EXECUTABLE(xpkey xp_algorithm.cpp shared.cpp bink.h)
 TARGET_INCLUDE_DIRECTORIES(xpkey PUBLIC crypto)
 TARGET_LINK_LIBRARIES(xpkey PUBLIC crypto)
+add_dependencies(xpkey bink.h)
 
-ADD_EXECUTABLE(srv2003key server_algorithm.cpp shared.cpp)
+ADD_EXECUTABLE(srv2003key server_algorithm.cpp shared.cpp bink.h)
 TARGET_INCLUDE_DIRECTORIES(srv2003key PUBLIC crypto)
 TARGET_LINK_LIBRARIES(srv2003key PUBLIC crypto)
+add_dependencies(srv2003key bink.h)
diff --git a/convert_keys_to_cpp.py b/convert_keys_to_cpp.py
new file mode 100644
index 0000000..d6460f4
--- /dev/null
+++ b/convert_keys_to_cpp.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+import json
+
+with open('keys.json') as json_file:
+    data = json.load(json_file)
+
+with open('bink.h', 'w') as out:
+    out.write('''
+ /******************************************************************
+ * This file was automatically generated by convert_keys_to_cpp.py *
+ *                         DO NOT EDIT                             *
+ ******************************************************************/
+ 
+#ifndef WINDOWSXPKG_BINK_H
+#define WINDOWSXPKG_BINK_H
+
+#include "shared.h"
+
+std::unordered_map<std::string, std::unordered_map<int, std::string>> Products;
+std::unordered_map<std::string, ECDLP_Params> BINKData;
+
+void initBink() {
+''')
+
+    for product in data['Products']:
+        d = data['Products'][product]
+        k = 0
+        for v in d:
+            out.write('    Products["' + product + '"][' + str(k) + '] = "' + v + '";' + "\n")
+            k += 1
+
+    out.write("\n")
+
+    for bink in data['BINK']:
+        d = data['BINK'][bink]
+        out.write('    BINKData["' + bink + '"] = {' +
+                  '{"' + d['p'] + '", "' + d['a'] + '", "' + d['b'] + '"}, ' +
+                  '{"' + d['pub']['x'] + '", "' + d['pub']['y'] + '"}, ' +
+                  '{"' + d['g']['x'] + '", "' + d['g']['y'] + '"}, ' +
+                  '"' + d['n'] + '", "' + d['priv'] + '"};' + "\n")
+
+    out.write("""
+}
+
+#endif //WINDOWSXPKG_BINK_H
+""")
diff --git a/keys.json b/keys.json
index c27b272..6c7e0b7 100644
--- a/keys.json
+++ b/keys.json
@@ -7,9 +7,9 @@
     "Windows XP Pro Retail": ["2C","2D"],
     "Windows XP Pro VLK": ["2E","2F"],
     "Halo: Combat Evolved": ["50","51"],
+    "Visual Studio 2005": ["52", "53"],
     "Windows XP Pro 64 Bit Edition VLK": ["64","65"],
-    "Windows XP Pro 64 Bit Edition Retail": ["66","67"],
-    "Visual Studio 2005": ["82", "83"]
+    "Windows XP Pro 64 Bit Edition Retail": ["66","67"]
   },
   "BINK": {
     "00": {
@@ -21,7 +21,7 @@
       },
       "n": "42464065991425877",
       "p": "22771656396649042914677651938348976006738044330885828909690000917475479649330897416453073715484777125675617411561753",
-      "priv": "29126373822686368",
+      "priv": "38647306188807670",
       "pub": {
         "x": "19001842596799889735847089805697287001733951474617682470323383968715961244343387245639296624260576737647372909452518",
         "y": "5073995932966536731583795294253584537145351666788650220967374102582334986751283480528872642160868858730405130413714"
@@ -136,15 +136,15 @@
       "a": "1",
       "b": "0",
       "g": {
-        "x": "17272533675023793624680016937607161394427776688401278127884215858369066406365237833207419170117031265147050748737186",
-        "y": "10897684556651576571671151674586120690608236542740270859915076272932083320838022698730208293779451126638581586588925"
+        "x": "23948165163161423827781659252187464228156720755142058092673382257634334615418008758683925938170704019069504769068767",
+        "y": "29262124142683887534232736126380966649037190576572850117401576509403154245303113352176870318970330981025925802076215"
       },
-      "n": "44682719955829289",
-      "p": "31123778862031392435299439090755153401162704597024288571183830527113563344679315725116915983118187065183839828632113",
-      "priv": "30177475288172038",
+      "n": "48764835656345441",
+      "p": "37184132387158636185823166107076967114138479407440093455278818158072422008561996049871236605258164895216434405941633",
+      "priv": "7983635268050735",
       "pub": {
-        "x": "10584120526089473026246191383792758367144927589909587205278073830223938861208553884400816982485323081066790399437204",
-        "y": "19710761542152200618172612283139324015316083022563473705358032993141026289202915973780473937312193485361804450068338"
+        "x": "16148631041299144072435534784738008519949841221985024060408677162532254304915141767288991659528028804911680226440414",
+        "y": "11647588982042777999933885074728841323429055317640349743317690400085264609368266409172384083304384956740124856614996"
       }
     },
     "0B": {
@@ -267,7 +267,7 @@
         "y": "16695949431099551936765494864197903910720045366223287633678257137673564581472696006269235457344268044769517631487706"
       }
     },
-    "2C": {
+    "2B": {
       "a": "1",
       "b": "0",
       "g": {
@@ -282,6 +282,21 @@
         "y": "22357703575020535444907398820227602869440920600838658819039554416206966784231890678810435029947588971910074121002504"
       }
     },
+    "2C": {
+      "a": "1",
+      "b": "0",
+      "g": {
+        "x": "21673361717619259910600499419800485528178801849923454062050055236231939594233283543796077751210469045350919066368895",
+        "y": "5232476492611604888729825305639232005017822876108144652169892952989580351454246958886421453535493897842819359154864"
+      },
+      "n": "55681564377333977",
+      "p": "24412280675538104642884792561502783185577987209710041026341163083973933860854736635268965257725055809364646140091249",
+      "priv": "30951839223306173",
+      "pub": {
+        "x": "21551722775458524408480112576069559265917312687549112053580919391285918530584174752292844347621326558272739603979057",
+        "y": "13463977158522661542654520438933687107907187215503371589980428235633526671841388652148099285621876350916055100879930"
+      }
+    },
     "2D": {
       "a": "1",
       "b": "0",
@@ -357,6 +372,36 @@
         "y": "1602626801939716053837744749626887002577837581116068515054873921829954905161054352599862173139179466561314851772116951576800443217651935171703906272161567"
       }
     },
+    "52": {
+      "a": "1",
+      "b": "0",
+      "g": {
+        "x": "7622412265904735790820724331145536880745869825302538676187160201387756396703356170295759091096405122096528698138948171749042031919696117032628083107811310",
+        "y": "3538375182189891751042048643308526629143293454794797073670319319588710166560996649992384714763805806154167398467726209193990040912148556093458840915181768"
+      },
+      "n": "5216282502541235641",
+      "p": "7925879388779818270822108768038895267533535400819446253716123243519501003959374444666474060360457012670942180897278261140356687371434584564816524729756569",
+      "priv": "4227382804860771752",
+      "pub": {
+        "x": "6623556837430211176716056285998438105129944636206613041325109163453346309568154499263565700497812782312007627435399691032717221155535887685349983547725754",
+        "y": "5143784137008935243415940746877546954904928787927831202191636787181715337470635194144636469817455076012295951914913996004499369538889959671269557189749708"
+      }
+    },
+    "53": {
+      "a": "1",
+      "b": "0",
+      "g": {
+        "x": "9952482702654268996410178765652497590105592800065574407952582838585534879676909122255372769768497901699832734933374032257806046204765452502338245789575378",
+        "y": "2089340264888419262996854021383298637761210445052455642799587750065248165559506120835367654357551061138377729286193320086948280413270555247250470924892526"
+      },
+      "n": "5068632114228449537",
+      "p": "11157014936597533577019045418547240616925175420814360521608554171517236939326924856555251208920173226882496853458122801623011764787655866100297968178218817",
+      "priv": "190541113341533176",
+      "pub": {
+        "x": "2564907221347665920571154160633426030926627289520132946090180496419693396052978749696275133983838854756474194181054881535849242976180540032615757743858664",
+        "y": "11135232968162438329449039042851302679976903318047276891184960732245822185866013956710495287987401311857788873227422869430044705095334454666338599981024663"
+      }
+    },
     "64": {
       "a": "1",
       "b": "0",
@@ -396,7 +441,7 @@
       },
       "n": "5470028972637037037",
       "p": "7414450614060932787248839197458070896684910960804177158392134961003575366268790629245141903395927609515264078025359653122837316120017343739991702588044217",
-      "priv": "5092684937889775537",
+      "priv": "822304248535969741",
       "pub": {
         "x": "2533341772295393491400808023462145665845043632064869971512603543404657302513574864471005505089780300953060578102587786092252155788924277962864392102891310",
         "y": "2853142146312045946205021435741931506513454835730828192678723851241580545655918715491324159683420265904946172614320824838207026955146237265100158801292103"
@@ -417,36 +462,6 @@
         "y": "1531615552769437372403026851115800774961251901795490190286680044124146107960174759313522242631208697837075037127449543341158979848323485793132900943144563"
       }
     },
-    "82": {
-      "a": "1",
-      "b": "0",
-      "g": {
-        "x": "7622412265904735790820724331145536880745869825302538676187160201387756396703356170295759091096405122096528698138948171749042031919696117032628083107811310",
-        "y": "3538375182189891751042048643308526629143293454794797073670319319588710166560996649992384714763805806154167398467726209193990040912148556093458840915181768"
-      },
-      "n": "5216282502541235641",
-      "p": "7925879388779818270822108768038895267533535400819446253716123243519501003959374444666474060360457012670942180897278261140356687371434584564816524729756569",
-      "priv": "4227382804860771752",
-      "pub": {
-        "x": "6623556837430211176716056285998438105129944636206613041325109163453346309568154499263565700497812782312007627435399691032717221155535887685349983547725754",
-        "y": "5143784137008935243415940746877546954904928787927831202191636787181715337470635194144636469817455076012295951914913996004499369538889959671269557189749708"
-      }
-    },
-    "83": {
-      "a": "1",
-      "b": "0",
-      "g": {
-        "x": "9952482702654268996410178765652497590105592800065574407952582838585534879676909122255372769768497901699832734933374032257806046204765452502338245789575378",
-        "y": "2089340264888419262996854021383298637761210445052455642799587750065248165559506120835367654357551061138377729286193320086948280413270555247250470924892526"
-      },
-      "n": "5068632114228449537",
-      "p": "11157014936597533577019045418547240616925175420814360521608554171517236939326924856555251208920173226882496853458122801623011764787655866100297968178218817",
-      "priv": "190541113341533176",
-      "pub": {
-        "x": "2564907221347665920571154160633426030926627289520132946090180496419693396052978749696275133983838854756474194181054881535849242976180540032615757743858664",
-        "y": "11135232968162438329449039042851302679976903318047276891184960732245822185866013956710495287987401311857788873227422869430044705095334454666338599981024663"
-      }
-    },
     "windows-server-2003": {
       "a": "1",
       "b": "0",
@@ -455,11 +470,27 @@
         "y": "5379780378477219053711555876878459214243674711784518156355184015695786277532464885846858297098947964642836892714492422913471742703229817151186461774623684"
       },
       "n": "5532044755580494717",
+      "priv": "2739897280441110808",
       "p": "10562920556476600174223203553624763158759224241690200395609486946570543757980521851146458516500451409335864053457189473296570712977858859585999979839497081",
       "pub": {
         "x": "7581054250900465100241221249174490036171686256743764922844514529943814922537182958165791392786846977936233032863941877071806567396668766127251287523822606",
         "y": "5631831699091940711241625425017356833183657380411816572111689187965538416134562629982530928101557014697032032310481274355673900378431834102530761513288622"
       }
+    },
+    "office-xp": {
+      "a": "1",
+      "b": "0",
+      "g": {
+        "x": "12259358487924366608305813282440364085684395756994923636191629847503895994037183295786380452071239418106026509150804",
+        "y": "14853676372788121804436447106529209167572424731944959299344702242030301728072117127341066233856180747847416655851934"
+      },
+      "n": "69284057899286401",
+      "priv": "13576107630579530",
+      "p": "31648573662208007208411279340972174081655191771220726603117102285639562723584318781472781870749438532939445789762497",
+      "pub": {
+        "x": "5871898692465293699950936882527671235864759453647136933264801904900692020319864572178035453433020771524967155028662",
+        "y": "7797169826989892215278245730061461386927964876868463824394796499325209401088175936040551790551876059967923119137155"
+      }
     }
   }
 }
\ No newline at end of file
diff --git a/server_algorithm.cpp b/server_algorithm.cpp
index c731c70..acf5818 100644
--- a/server_algorithm.cpp
+++ b/server_algorithm.cpp
@@ -1,4 +1,5 @@
 #include "shared.h"
+#include "bink.h"
 
 #define FIELD_BITS_2003 512
 #define FIELD_BYTES_2003 64
@@ -23,12 +24,10 @@ void pack2003(uint32_t *raw, uint32_t *osfamily, uint32_t *hash, uint32_t *sig,
 int verify2003(EC_GROUP *ec, EC_POINT *generator, EC_POINT *public_key, char *cdkey)
 {
 	uint8_t key[25];
-	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++) {
+	for (int i = 0, k = 0; i < strlen(cdkey); i++) {
+		for (int j = 0; j < 24; j++) {
 			if (cdkey[i] != '-' && cdkey[i] == cset[j]) {
 				key[k++] = j;
 				break;
diff --git a/shared.cpp b/shared.cpp
index c9bb41f..0dcb564 100644
--- a/shared.cpp
+++ b/shared.cpp
@@ -20,7 +20,6 @@ void endian(uint8_t *data, int len)
 
 void unbase24(uint32_t *x, uint8_t *c)
 {
-
     memset(x, 0, 16);
     int i, n;
 
@@ -32,6 +31,7 @@ void unbase24(uint32_t *x, uint8_t *c)
         BN_mul_word(y, 24);
         BN_add_word(y, c[i]);
     }
+
     n = BN_num_bytes(y);
     BN_bn2bin(y, (uint8_t *)x);
     BN_free(y);
@@ -51,7 +51,6 @@ void base24(uint8_t *c, uint32_t *x)
     endian(y, i);							// Reverse y
     z = BN_bin2bn(y, i, NULL);				// Convert y to BigNum z
 
-
     // Divide z by 24 and convert remainder with cset to Base24-CDKEY Char
     c[25] = 0;
     for (i = 24; i >= 0; i--) {
@@ -77,8 +76,8 @@ void print_product_id(uint32_t *pid)
 
     // Make c-part {...-123456X...}
     strcpy(c, raw + 3);
-
     printf("> %s\n", c);
+
     // Make checksum digit-part {...56X-}
     assert(strlen(c) == 6);
     for (i = 0; i < 6; i++)
@@ -89,7 +88,7 @@ void print_product_id(uint32_t *pid)
     c[6] = digit + '0';
     c[7] = 0;
 
-    printf("Product ID: 55274-%s-%s-23xxx\n", b, c);
+    printf("Product ID: PPPPP-%s-%s-23xxx\n", b, c);
 }
 
 void print_product_key(uint8_t *pk)
diff --git a/shared.h b/shared.h
index 9d9376f..a93302b 100644
--- a/shared.h
+++ b/shared.h
@@ -8,7 +8,12 @@
 #include <assert.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
+#include <time.h>
+#include <string>
+#include <vector>
+#include <unordered_map>
 
 #include <openssl/bn.h>
 #include <openssl/ec.h>
@@ -23,4 +28,27 @@ void base24(uint8_t *c, uint32_t *x);
 void print_product_key(uint8_t *pk);
 void print_product_id(uint32_t *pid);
 
+struct ECDLP_Params {
+    //         p,           a,           b
+    std::tuple<std::string, std::string, std::string> E;
+
+    //         x,           y
+    std::tuple<std::string, std::string> K;
+
+    //         x,           y
+    std::tuple<std::string, std::string> G;
+
+    std::string n;
+    std::string k;
+};
+
+struct ProductID {
+    uint8_t SiteID;
+    uint16_t Serial;
+};
+
+extern std::unordered_map<std::string, std::unordered_map<int, std::string>> Products;
+extern std::unordered_map<std::string, ECDLP_Params> BINKData;
+void initBink();
+
 #endif //WINDOWSXPKG_SHARED_H
diff --git a/xp_algorithm.cpp b/xp_algorithm.cpp
index 6e6ebb9..6656499 100644
--- a/xp_algorithm.cpp
+++ b/xp_algorithm.cpp
@@ -16,6 +16,7 @@
 */
 
 #include "shared.h"
+#include "bink.h"
 
 #define FIELD_BITS 384
 #define FIELD_BYTES 48
@@ -203,6 +204,12 @@ void generate(uint8_t *pkey, EC_GROUP *ec, EC_POINT *generator, BIGNUM *order, B
 
 int main()
 {
+    initBink();
+
+    rand();
+    srand(time(nullptr));
+    rand();
+
  // Init
 	BIGNUM *a, *b, *p, *gx, *gy, *pubx, *puby, *n, *priv;
 	BN_CTX *ctx = BN_CTX_new();
@@ -218,27 +225,29 @@ int main()
 	n = BN_new();
 	priv = BN_new();
 
+    char* BINKID = "2E";
+
  // Data from pidgen-Bink-resources
 	/* Elliptic curve parameters: y^2 = x^3 + ax + b mod p */
-	BN_hex2bn(&p,    "92ddcf14cb9e71f4489a2e9ba350ae29454d98cb93bdbcc07d62b502ea12238ee904a8b20d017197aae0c103b32713a9");
-	BN_set_word(a, 1);
-	BN_set_word(b, 0);
+	BN_dec2bn(&p,    std::get<0>(BINKData[BINKID].E).c_str());
+    BN_dec2bn(&a,    std::get<1>(BINKData[BINKID].E).c_str());
+    BN_dec2bn(&b,    std::get<2>(BINKData[BINKID].E).c_str());
 	
 
 	/* base point (generator) G */
-	BN_hex2bn(&gx,   "46E3775ECE21B0898D39BEA57050D422A0AF989E497962BAEE2CB17E0A28D5360D5476B8DC966443E37A14F1AEF37742");
-	BN_hex2bn(&gy,   "7C8E741D2C34F4478E325469CD491603D807222C9C4AC09DDB2B31B3CE3F7CC191B3580079932BC6BEF70BE27604F65E");
+    BN_dec2bn(&gx,   std::get<0>(BINKData[BINKID].G).c_str());
+    BN_dec2bn(&gy,   std::get<1>(BINKData[BINKID].G).c_str());
 
 	/* inverse of public key */
-	BN_hex2bn(&pubx, "5D8DBE75198015EC41C45AAB6143542EB098F6A5CC9CE4178A1B8A1E7ABBB5BC64DF64FAF6177DC1B0988AB00BA94BF8");
-	BN_hex2bn(&puby, "23A2909A0B4803C89F910C7191758B48746CEA4D5FF07667444ACDB9512080DBCA55E6EBF30433672B894F44ACE92BFA");
+    BN_dec2bn(&pubx, std::get<0>(BINKData[BINKID].K).c_str());
+    BN_dec2bn(&puby, std::get<1>(BINKData[BINKID].K).c_str());
 
  // Computed data
 	/* order of G - computed in 18 hours using a P3-450 */
-	BN_hex2bn(&n,    "DB6B4C58EFBAFD");
+    BN_dec2bn(&n,    BINKData[BINKID].n.c_str());
 
 	/* THE private key  - computed in 10 hours using a P3-450 */
-	BN_hex2bn(&priv, "565B0DFF8496C8");
+    BN_dec2bn(&priv, BINKData[BINKID].k.c_str());
 
  // Calculation
 	EC_GROUP *ec = EC_GROUP_new_curve_GFp(p, a, b, ctx);
@@ -249,11 +258,16 @@ int main()
 	
 	uint8_t pkey[26];
 	uint32_t pid[1];
-	pid[0] = 640000000 << 1; /* <- change */
+    pid[0] = 640 * 1000000 ; /* <- change */
+    pid[0] += rand() & 999999;
+
+    printf("> PID: %d\n", pid[0]);
 
  // generate a key
+    BN_sub(priv, n, priv);
 	generate(pkey, ec, g, n, priv, pid);
-	print_product_key(pkey); printf("\n\n");
+	print_product_key(pkey);
+    printf("\n\n");
 
  // verify the key
 	verify(ec, g, pub, (char*)pkey);