├── LICENSE ├── README.md ├── Srv2003KGmain.cpp └── main.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 TheMCHK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## **Windows XP Keygen!** 2 | 3 | # **FAQ** 4 | 5 | * **What does it do?** 6 | 7 | This program allows you to generate endless Windows XP keys. 8 | You also can use it to check your already existing keys. 9 | 10 | * **How does it work?** 11 | 12 | This program is based on [this paper](https://www.licenturion.com/xp/fully-licensed-wpa.txt) Basically, 13 | it uses a cracked private key from Microsoft to sign some stuff encoded in the 25-digit product key. It also does this process in reverse to check for the validation of the keys. 14 | 15 | * **How do I use it?** 16 | 17 | It all comes down to four simple steps: 18 | 19 | 20 | **1.** Use this program to generate a key, and use such key during installation. 21 | 22 | **2.** After installation, you will be prompted to activate Windows. Select the 23 | *telephone activation* method, then, fire up [this website](https://msdev.gointeract.io/interact/index?interaction=1461173234028-3884f8602eccbe259104553afa8415434b4581-05d1&accountId=microsoft&appkey=196de13c-e946-4531-98f6-2719ec8405ce) and enter the installation ID that the activation wizard gave you. 24 | 25 | **3.** Click "**Next**" 26 | 27 | **4.** Profit! 28 | 29 | 30 | 31 | **REQUIREMENTS:** 32 | 33 | * `OpenSSL >0.9.8b` 34 | -------------------------------------------------------------------------------- /Srv2003KGmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef unsigned char U8; 10 | typedef unsigned long U32; 11 | 12 | U8 cset[] = "BCDFGHJKMPQRTVWXY2346789"; 13 | 14 | #define FIELD_BITS_2003 512 15 | #define FIELD_BYTES_2003 64 16 | 17 | void unpack2003(U32 *osfamily, U32 *hash, U32 *sig, U32 *prefix, U32 *raw) 18 | { 19 | osfamily[0] = raw[0] & 0x7ff; 20 | hash[0] = ((raw[0] >> 11) | (raw[1] << 21)) & 0x7fffffff; 21 | sig[0] = (raw[1] >> 10) | (raw[2] << 22); 22 | sig[1] = ((raw[2] >> 10) | (raw[3] << 22)) & 0x3fffffff; 23 | prefix[0] = (raw[3] >> 8) & 0x3ff; 24 | } 25 | 26 | void pack2003(U32 *raw, U32 *osfamily, U32 *hash, U32 *sig, U32 *prefix) 27 | { 28 | raw[0] = osfamily[0] | (hash[0] << 11); 29 | raw[1] = (hash[0] >> 21) | (sig[0] << 10); 30 | raw[2] = (sig[0] >> 22) | (sig[1] << 10); 31 | raw[3] = (sig[1] >> 22) | (prefix[0] << 8); 32 | } 33 | 34 | static void endian(U8 *x, int n) 35 | { 36 | int i; 37 | for (i = 0; i < n/2; i++) { 38 | U8 t; 39 | t = x[i]; 40 | x[i] = x[n-i-1]; 41 | x[n-i-1] = t; 42 | } 43 | } 44 | 45 | void unbase24(U32 *x, U8 *c) 46 | { 47 | memset(x, 0, 16); 48 | int i, n; 49 | 50 | BIGNUM *y = BN_new(); 51 | BN_zero(y); 52 | 53 | for (i = 0; i < 25; i++) 54 | { 55 | BN_mul_word(y, 24); 56 | BN_add_word(y, c[i]); 57 | } 58 | n = BN_num_bytes(y); 59 | BN_bn2bin(y, (U8 *)x); 60 | BN_free(y); 61 | 62 | endian((U8 *)x, n); 63 | } 64 | 65 | void base24(U8 *c, U32 *x) 66 | { 67 | U8 y[16]; 68 | int i; 69 | 70 | BIGNUM *z; 71 | memcpy(y, x, sizeof(y)); 72 | for (i = 15; y[i] == 0; i--) {} i++; 73 | endian(y, i); 74 | z = BN_bin2bn(y, i, NULL); 75 | 76 | c[25] = 0; 77 | for (i = 24; i >= 0; i--) { 78 | U8 t = BN_div_word(z, 24); 79 | c[i] = cset[t]; 80 | } 81 | BN_free(z); 82 | } 83 | 84 | void print_product_key(U8 *pk) 85 | { 86 | int i; 87 | assert(strlen(pk) == 25); 88 | for (i = 0; i < 25; i++) { 89 | putchar(pk[i]); 90 | if (i != 24 && i % 5 == 4) putchar('-'); 91 | } 92 | } 93 | 94 | void verify2003(EC_GROUP *ec, EC_POINT *generator, EC_POINT *public_key, char *cdkey) 95 | { 96 | U8 key[25]; 97 | int i, j, k; 98 | 99 | BN_CTX *ctx = BN_CTX_new(); 100 | 101 | for (i = 0, k = 0; i < strlen(cdkey); i++) { 102 | for (j = 0; j < 24; j++) { 103 | if (cdkey[i] != '-' && cdkey[i] == cset[j]) { 104 | key[k++] = j; 105 | break; 106 | } 107 | assert(j < 24); 108 | } 109 | if (k >= 25) break; 110 | } 111 | 112 | U32 bkey[4] = {0}; 113 | U32 osfamily[1], hash[1], sig[2], prefix[1]; 114 | unbase24(bkey, key); 115 | printf("%.8x %.8x %.8x %.8x\n", bkey[3], bkey[2], bkey[1], bkey[0]); 116 | unpack2003(osfamily, hash, sig, prefix, bkey); 117 | 118 | printf("OS Family: %u\nHash: %.8x\nSig: %.8x %.8x\nPrefix: %.8x\n", osfamily[0], hash[0], sig[1], sig[0], prefix[0]); 119 | 120 | U8 buf[FIELD_BYTES_2003], md[20]; 121 | U32 h1[2]; 122 | SHA_CTX h_ctx; 123 | 124 | /* h1 = SHA-1(5D || OS Family || Hash || Prefix || 00 00) */ 125 | SHA1_Init(&h_ctx); 126 | buf[0] = 0x5d; 127 | buf[1] = osfamily[0] & 0xff; 128 | buf[2] = (osfamily[0] & 0xff00) >> 8; 129 | buf[3] = hash[0] & 0xff; 130 | buf[4] = (hash[0] & 0xff00) >> 8; 131 | buf[5] = (hash[0] & 0xff0000) >> 16; 132 | buf[6] = (hash[0] & 0xff000000) >> 24; 133 | buf[7] = prefix[0] & 0xff; 134 | buf[8] = (prefix[0] & 0xff00) >> 8; 135 | buf[9] = buf[10] = 0; 136 | SHA1_Update(&h_ctx, buf, 11); 137 | SHA1_Final(md, &h_ctx); 138 | h1[0] = md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24); 139 | h1[1] = (md[4] | (md[5] << 8) | (md[6] << 16) | (md[7] << 24)) >> 2; 140 | h1[1] &= 0x3FFFFFFF; 141 | printf("h1: %.8x %.8x\n", h1[1], h1[0]); 142 | 143 | BIGNUM *s, *h, *x, *y; 144 | x = BN_new(); 145 | y = BN_new(); 146 | endian((U8 *)sig, 8); 147 | endian((U8 *)h1, 8); 148 | s = BN_bin2bn((U8 *)sig, 8, NULL); 149 | h = BN_bin2bn((U8 *)h1, 8, NULL); 150 | 151 | EC_POINT *r = EC_POINT_new(ec); 152 | EC_POINT *t = EC_POINT_new(ec); 153 | /* r = sig*(sig*generator + h1*public_key) */ 154 | EC_POINT_mul(ec, t, NULL, generator, s, ctx); 155 | EC_POINT_mul(ec, r, NULL, public_key, h, ctx); 156 | EC_POINT_add(ec, r, r, t, ctx); 157 | EC_POINT_mul(ec, r, NULL, r, s, ctx); 158 | EC_POINT_get_affine_coordinates_GFp(ec, r, x, y, ctx); 159 | 160 | U32 h2[1]; 161 | /* h2 = SHA-1(79 || OS Family || r.x || r.y) */ 162 | SHA1_Init(&h_ctx); 163 | buf[0] = 0x79; 164 | buf[1] = osfamily[0] & 0xff; 165 | buf[2] = (osfamily[0] & 0xff00) >> 8; 166 | SHA1_Update(&h_ctx, buf, 3); 167 | 168 | memset(buf, 0, FIELD_BYTES_2003); 169 | BN_bn2bin(x, buf); 170 | endian((U8 *)buf, FIELD_BYTES_2003); 171 | SHA1_Update(&h_ctx, buf, FIELD_BYTES_2003); 172 | 173 | memset(buf, 0, FIELD_BYTES_2003); 174 | BN_bn2bin(y, buf); 175 | endian((U8 *)buf, FIELD_BYTES_2003); 176 | SHA1_Update(&h_ctx, buf, FIELD_BYTES_2003); 177 | 178 | SHA1_Final(md, &h_ctx); 179 | h2[0] = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) & 0x7fffffff; 180 | printf("Calculated hash: %.8x\n", h2[0]); 181 | 182 | if (h2[0] == hash[0]) printf("Key VALID\n"); 183 | else printf("Key invalid\n"); 184 | 185 | BN_free(s); 186 | BN_free(h); 187 | BN_free(x); 188 | BN_free(y); 189 | EC_POINT_free(r); 190 | EC_POINT_free(t); 191 | BN_CTX_free(ctx); 192 | } 193 | 194 | void generate2003(U8 *pkey, EC_GROUP *ec, EC_POINT *generator, BIGNUM *order, BIGNUM *priv, U32 *osfamily, U32 *prefix) 195 | { 196 | BN_CTX *ctx = BN_CTX_new(); 197 | 198 | BIGNUM *k = BN_new(); 199 | BIGNUM *s = BN_new(); 200 | BIGNUM *x = BN_new(); 201 | BIGNUM *y = BN_new(); 202 | BIGNUM *b = BN_new(); 203 | EC_POINT *r = EC_POINT_new(ec); 204 | 205 | U32 bkey[4]; 206 | U8 buf[FIELD_BYTES_2003], md[20]; 207 | U32 h1[2]; 208 | U32 hash[1], sig[2]; 209 | 210 | SHA_CTX h_ctx; 211 | 212 | for (;;) { 213 | /* r = k*generator */ 214 | BN_pseudo_rand(k, FIELD_BITS_2003, -1, 0); 215 | EC_POINT_mul(ec, r, NULL, generator, k, ctx); 216 | EC_POINT_get_affine_coordinates_GFp(ec, r, x, y, ctx); 217 | 218 | /* hash = SHA-1(79 || OS Family || r.x || r.y) */ 219 | SHA1_Init(&h_ctx); 220 | buf[0] = 0x79; 221 | buf[1] = osfamily[0] & 0xff; 222 | buf[2] = (osfamily[0] & 0xff00) >> 8; 223 | SHA1_Update(&h_ctx, buf, 3); 224 | 225 | memset(buf, 0, FIELD_BYTES_2003); 226 | BN_bn2bin(x, buf); 227 | endian((U8 *)buf, FIELD_BYTES_2003); 228 | SHA1_Update(&h_ctx, buf, FIELD_BYTES_2003); 229 | 230 | memset(buf, 0, FIELD_BYTES_2003); 231 | BN_bn2bin(y, buf); 232 | endian((U8 *)buf, FIELD_BYTES_2003); 233 | SHA1_Update(&h_ctx, buf, FIELD_BYTES_2003); 234 | 235 | SHA1_Final(md, &h_ctx); 236 | hash[0] = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) & 0x7fffffff; 237 | 238 | /* h1 = SHA-1(5D || OS Family || Hash || Prefix || 00 00) */ 239 | SHA1_Init(&h_ctx); 240 | buf[0] = 0x5d; 241 | buf[1] = osfamily[0] & 0xff; 242 | buf[2] = (osfamily[0] & 0xff00) >> 8; 243 | buf[3] = hash[0] & 0xff; 244 | buf[4] = (hash[0] & 0xff00) >> 8; 245 | buf[5] = (hash[0] & 0xff0000) >> 16; 246 | buf[6] = (hash[0] & 0xff000000) >> 24; 247 | buf[7] = prefix[0] & 0xff; 248 | buf[8] = (prefix[0] & 0xff00) >> 8; 249 | buf[9] = buf[10] = 0; 250 | SHA1_Update(&h_ctx, buf, 11); 251 | SHA1_Final(md, &h_ctx); 252 | h1[0] = md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24); 253 | h1[1] = (md[4] | (md[5] << 8) | (md[6] << 16) | (md[7] << 24)) >> 2; 254 | h1[1] &= 0x3FFFFFFF; 255 | printf("h1: %.8x %.8x\n", h1[1], h1[0]); 256 | 257 | /* s = ( -h1*priv + sqrt( (h1*priv)^2 + 4k ) ) / 2 */ 258 | endian((U8 *)h1, 8); 259 | BN_bin2bn((U8 *)h1, 8, b); 260 | BN_mod_mul(b, b, priv, order, ctx); 261 | BN_copy(s, b); 262 | BN_mod_sqr(s, s, order, ctx); 263 | BN_lshift(k, k, 2); 264 | BN_add(s, s, k); 265 | BN_mod_sqrt(s, s, order, ctx); 266 | BN_mod_sub(s, s, b, order, ctx); 267 | if (BN_is_odd(s)) { 268 | BN_add(s, s, order); 269 | } 270 | BN_rshift1(s, s); 271 | sig[0] = sig[1] = 0; 272 | BN_bn2bin(s, (U8 *)sig); 273 | endian((U8 *)sig, BN_num_bytes(s)); 274 | if (sig[1] < 0x40000000) break; 275 | } 276 | pack2003(bkey, osfamily, hash, sig, prefix); 277 | printf("OS family: %u\nHash: %.8x\nSig: %.8x %.8x\nPrefix: %.8x\n", osfamily[0], hash[0], sig[1], sig[0], prefix[0]); 278 | printf("%.8x %.8x %.8x %.8x\n", bkey[3], bkey[2], bkey[1], bkey[0]); 279 | base24(pkey, bkey); 280 | 281 | BN_free(k); 282 | BN_free(s); 283 | BN_free(x); 284 | BN_free(y); 285 | BN_free(b); 286 | EC_POINT_free(r); 287 | 288 | BN_CTX_free(ctx); 289 | 290 | } 291 | 292 | int main() 293 | { 294 | BIGNUM *a, *b, *p, *gx, *gy, *pubx, *puby, *n, *priv; 295 | BN_CTX *ctx = BN_CTX_new(); 296 | 297 | a = BN_new(); 298 | b = BN_new(); 299 | p = BN_new(); 300 | gx = BN_new(); 301 | gy = BN_new(); 302 | pubx = BN_new(); 303 | puby = BN_new(); 304 | n = BN_new(); 305 | priv = BN_new(); 306 | 307 | /* Windows Sever 2003 VLK */ 308 | BN_set_word(a, 1); 309 | BN_set_word(b, 0); 310 | BN_hex2bn(&p, "C9AE7AED19F6A7E100AADE98134111AD8118E59B8264734327940064BC675A0C682E19C89695FBFA3A4653E47D47FD7592258C7E3C3C61BBEA07FE5A7E842379"); 311 | BN_hex2bn(&gx, "85ACEC9F9F9B456A78E43C3637DC88D21F977A9EC15E5225BD5060CE5B892F24FEDEE574BF5801F06BC232EEF2161074496613698D88FAC4B397CE3B475406A7"); 312 | BN_hex2bn(&gy, "66B7D1983F5D4FE43E8B4F1E28685DE0E22BBE6576A1A6B86C67533BF72FD3D082DBA281A556A16E593DB522942C8DD7120BA50C9413DF944E7258BDDF30B3C4"); 313 | BN_hex2bn(&pubx, "90BF6BD980C536A8DB93B52AA9AEBA640BABF1D31BEC7AA345BB7510194A9B07379F552DA7B4A3EF81A9B87E0B85B5118E1E20A098641EE4CCF2045558C98C0E"); 314 | BN_hex2bn(&puby, "6B87D1E658D03868362945CDD582E2CF33EE4BA06369E0EFE9E4851F6DCBEC7F15081E250D171EA0CC4CB06435BCFCFEA8F438C9766743A06CBD06E7EFB4C3AE"); 315 | BN_hex2bn(&n, "4CC5C56529F0237D"); // from mskey 4in1 316 | BN_hex2bn(&priv, "2606120F59C05118"); 317 | 318 | 319 | EC_GROUP *ec = EC_GROUP_new_curve_GFp(p, a, b, ctx); 320 | EC_POINT *g = EC_POINT_new(ec); 321 | EC_POINT_set_affine_coordinates_GFp(ec, g, gx, gy, ctx); 322 | EC_POINT *pub = EC_POINT_new(ec); 323 | EC_POINT_set_affine_coordinates_GFp(ec, pub, pubx, puby, ctx); 324 | 325 | assert(EC_POINT_is_on_curve(ec, g, ctx) == 1); 326 | assert(EC_POINT_is_on_curve(ec, pub, ctx) == 1); 327 | 328 | U8 pkey[25]; 329 | U32 osfamily[1], prefix[1]; 330 | 331 | osfamily[0] = 1280; 332 | RAND_pseudo_bytes((U8 *)prefix, 4); 333 | prefix[0] &= 0x3ff; 334 | generate2003(pkey, ec, g, n, priv, osfamily, prefix); 335 | print_product_key(pkey); printf("\n\n"); 336 | verify2003(ec, g, pub, pkey); 337 | 338 | BN_CTX_free(ctx); 339 | 340 | return 0; 341 | } 342 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Windows XP CD Key Verification/Generator v0.03 3 | by z22 4 | 5 | Compile with OpenSSL libs, modify to suit your needs. 6 | http://gnuwin32.sourceforge.net/packages/openssl.htm 7 | 8 | History: 9 | 0.03 Stack corruptionerror on exit fixed (now pkey is large enough) 10 | More Comments added 11 | 0.02 Changed name the *.cpp; 12 | Fixed minor bugs & Make it compilable on VC++ 13 | 0.01 First version compilable MingW 14 | 15 | 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | #define FIELD_BITS 384 27 | #define FIELD_BYTES 48 28 | unsigned char cset[] = "BCDFGHJKMPQRTVWXY2346789"; 29 | 30 | 31 | static void unpack(unsigned long *pid, unsigned long *hash, unsigned long *sig, unsigned long *raw) 32 | { 33 | // pid = Bit 0..30 34 | pid[0] = raw[0] & 0x7fffffff; 35 | 36 | // hash(s) = Bit 31..58 37 | hash[0] = ((raw[0] >> 31) | (raw[1] << 1)) & 0xfffffff; 38 | 39 | // sig(e) = bit 58..113 40 | sig[0] = (raw[1] >> 27) | (raw[2] << 5); 41 | sig[1] = (raw[2] >> 27) | (raw[3] << 5); 42 | } 43 | 44 | static void pack(unsigned long *raw, unsigned long *pid, unsigned long *hash, unsigned long *sig) 45 | { 46 | raw[0] = pid[0] | ((hash[0] & 1) << 31); 47 | raw[1] = (hash[0] >> 1) | ((sig[0] & 0x1f) << 27); 48 | raw[2] = (sig[0] >> 5) | (sig[1] << 27); 49 | raw[3] = sig[1] >> 5; 50 | } 51 | 52 | // Reverse data 53 | static void endian(unsigned char *data, int len) 54 | { 55 | int i; 56 | for (i = 0; i < len/2; i++) { 57 | unsigned char temp; 58 | temp = data[i]; 59 | data[i] = data[len-i-1]; 60 | data[len-i-1] = temp; 61 | } 62 | } 63 | 64 | void unbase24(unsigned long *x, unsigned char *c) 65 | { 66 | 67 | memset(x, 0, 16); 68 | int i, n; 69 | 70 | BIGNUM *y = BN_new(); 71 | BN_zero(y); 72 | 73 | for (i = 0; i < 25; i++) 74 | { 75 | BN_mul_word(y, 24); 76 | BN_add_word(y, c[i]); 77 | } 78 | n = BN_num_bytes(y); 79 | BN_bn2bin(y, (unsigned char *)x); 80 | BN_free(y); 81 | 82 | endian((unsigned char *)x, n); 83 | } 84 | 85 | void base24(unsigned char *c, unsigned long *x) 86 | { 87 | unsigned char y[16]; 88 | int i; 89 | BIGNUM *z; 90 | 91 | // Convert x to BigNum z 92 | memcpy(y, x, sizeof(y)); // Copy X to Y; Y=X 93 | for (i = 15; y[i] == 0; i--) {} i++; // skip following nulls 94 | endian(y, i); // Reverse y 95 | z = BN_bin2bn(y, i, NULL); // Convert y to BigNum z 96 | 97 | 98 | // Divide z by 24 and convert remainder with cset to Base24-CDKEY Char 99 | c[25] = 0; 100 | for (i = 24; i >= 0; i--) { 101 | unsigned char t = BN_div_word(z, 24); 102 | c[i] = cset[t]; 103 | } 104 | 105 | BN_free(z); 106 | } 107 | 108 | void print_product_id(unsigned long *pid) 109 | { 110 | char raw[12]; 111 | char b[6], c[8]; 112 | int i, digit = 0; 113 | 114 | // Cut a away last bit of pid and convert it to an accii-number (=raw) 115 | sprintf(raw, "%d", pid[0] >> 1); 116 | 117 | // Make b-part {640-....} 118 | strncpy(b, raw, 3); 119 | b[3] = 0; 120 | 121 | // Make c-part {...-123456X...} 122 | strcpy(c, raw + 3); 123 | 124 | // Make checksum digit-part {...56X-} 125 | assert(strlen(c) == 6); 126 | for (i = 0; i < 6; i++) 127 | digit -= c[i] - '0'; // Sum digits 128 | 129 | while (digit < 0) 130 | digit += 7; 131 | c[6] = digit + '0'; 132 | c[7] = 0; 133 | 134 | printf("Product ID: 55274-%s-%s-23xxx\n", b, c); 135 | } 136 | 137 | void print_product_key(unsigned char *pk) 138 | { 139 | int i; 140 | assert(strlen((const char *)pk) == 25); 141 | for (i = 0; i < 25; i++) { 142 | putchar(pk[i]); 143 | if (i != 24 && i % 5 == 4) putchar('-'); 144 | } 145 | } 146 | 147 | void verify(EC_GROUP *ec, EC_POINT *generator, EC_POINT *public_key, char *cdkey) 148 | { 149 | unsigned char key[25]; 150 | int i, j, k; 151 | 152 | BN_CTX *ctx = BN_CTX_new(); 153 | // remove Dashs from CDKEY 154 | for (i = 0, k = 0; i < strlen(cdkey); i++) { 155 | for (j = 0; j < 24; j++) { 156 | if (cdkey[i] != '-' && cdkey[i] == cset[j]) { 157 | key[k++] = j; 158 | break; 159 | } 160 | assert(j < 24); 161 | } 162 | if (k >= 25) break; 163 | } 164 | 165 | // Base24_CDKEY -> Bin_CDKEY 166 | unsigned long bkey[4] = {0}; 167 | unsigned long pid[1], hash[1], sig[2]; 168 | unbase24(bkey, key); 169 | 170 | // Output Bin_CDKEY 171 | printf("%.8x %.8x %.8x %.8x\n", bkey[3], bkey[2], bkey[1], bkey[0]); 172 | 173 | // Divide/Extract pid_data, hash, sig from Bin_CDKEY 174 | unpack(pid, hash, sig, bkey); 175 | print_product_id(pid); 176 | 177 | printf("PID: %.8x\nHash: %.8x\nSig: %.8x %.8x\n", pid[0], hash[0], sig[1], sig[0]); 178 | 179 | 180 | BIGNUM *e, *s; 181 | 182 | /* e = hash, s = sig */ 183 | e = BN_new(); 184 | BN_set_word(e, hash[0]); 185 | endian((unsigned char *)sig, sizeof(sig)); 186 | s = BN_bin2bn((unsigned char *)sig, sizeof(sig), NULL); 187 | 188 | BIGNUM *x = BN_new(); 189 | BIGNUM *y = BN_new(); 190 | EC_POINT *u = EC_POINT_new(ec); 191 | EC_POINT *v = EC_POINT_new(ec); 192 | 193 | /* v = s*generator + e*(-public_key) */ 194 | EC_POINT_mul(ec, u, NULL, generator, s, ctx); 195 | EC_POINT_mul(ec, v, NULL, public_key, e, ctx); 196 | EC_POINT_add(ec, v, u, v, ctx); 197 | EC_POINT_get_affine_coordinates_GFp(ec, v, x, y, ctx); 198 | 199 | unsigned char buf[FIELD_BYTES], md[20]; 200 | unsigned long h; 201 | unsigned char t[4]; 202 | SHA_CTX h_ctx; 203 | 204 | /* h = (fist 32 bits of SHA1(pid || v.x, v.y)) >> 4 */ 205 | SHA1_Init(&h_ctx); 206 | t[0] = pid[0] & 0xff; 207 | t[1] = (pid[0] & 0xff00) >> 8; 208 | t[2] = (pid[0] & 0xff0000) >> 16; 209 | t[3] = (pid[0] & 0xff000000) >> 24; 210 | SHA1_Update(&h_ctx, t, sizeof(t)); 211 | 212 | memset(buf, 0, sizeof(buf)); 213 | BN_bn2bin(x, buf); 214 | endian((unsigned char *)buf, sizeof(buf)); 215 | SHA1_Update(&h_ctx, buf, sizeof(buf)); 216 | 217 | memset(buf, 0, sizeof(buf)); 218 | BN_bn2bin(y, buf); 219 | endian((unsigned char *)buf, sizeof(buf)); 220 | SHA1_Update(&h_ctx, buf, sizeof(buf)); 221 | 222 | SHA1_Final(md, &h_ctx); 223 | h = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) >> 4; 224 | h &= 0xfffffff; 225 | 226 | printf("Calculated hash: %.8x\n", h); 227 | if (h == hash[0]) printf("Key valid\n"); 228 | else printf("Key invalid\n"); 229 | putchar('\n'); 230 | 231 | BN_free(e); 232 | BN_free(s); 233 | BN_free(x); 234 | BN_free(y); 235 | EC_POINT_free(u); 236 | EC_POINT_free(v); 237 | 238 | BN_CTX_free(ctx); 239 | } 240 | 241 | void generate(unsigned char *pkey, EC_GROUP *ec, EC_POINT *generator, BIGNUM *order, BIGNUM *priv, unsigned long *pid) 242 | { 243 | BN_CTX *ctx = BN_CTX_new(); 244 | 245 | BIGNUM *k = BN_new(); 246 | BIGNUM *s = BN_new(); 247 | BIGNUM *x = BN_new(); 248 | BIGNUM *y = BN_new(); 249 | EC_POINT *r = EC_POINT_new(ec); 250 | unsigned long bkey[4]; 251 | 252 | // Loop in case signaturepart will make cdkey(base-24 "digits") longer than 25 253 | do { 254 | BN_pseudo_rand(k, FIELD_BITS, -1, 0); 255 | EC_POINT_mul(ec, r, NULL, generator, k, ctx); 256 | EC_POINT_get_affine_coordinates_GFp(ec, r, x, y, ctx); 257 | 258 | SHA_CTX h_ctx; 259 | unsigned char t[4], md[20], buf[FIELD_BYTES]; 260 | unsigned long hash[1]; 261 | /* h = (fist 32 bits of SHA1(pid || r.x, r.y)) >> 4 */ 262 | SHA1_Init(&h_ctx); 263 | t[0] = pid[0] & 0xff; 264 | t[1] = (pid[0] & 0xff00) >> 8; 265 | t[2] = (pid[0] & 0xff0000) >> 16; 266 | t[3] = (pid[0] & 0xff000000) >> 24; 267 | SHA1_Update(&h_ctx, t, sizeof(t)); 268 | 269 | memset(buf, 0, sizeof(buf)); 270 | BN_bn2bin(x, buf); 271 | endian((unsigned char *)buf, sizeof(buf)); 272 | SHA1_Update(&h_ctx, buf, sizeof(buf)); 273 | 274 | memset(buf, 0, sizeof(buf)); 275 | BN_bn2bin(y, buf); 276 | endian((unsigned char *)buf, sizeof(buf)); 277 | SHA1_Update(&h_ctx, buf, sizeof(buf)); 278 | 279 | SHA1_Final(md, &h_ctx); 280 | hash[0] = (md[0] | (md[1] << 8) | (md[2] << 16) | (md[3] << 24)) >> 4; 281 | hash[0] &= 0xfffffff; 282 | 283 | /* s = priv*h + k */ 284 | BN_copy(s, priv); 285 | BN_mul_word(s, hash[0]); 286 | BN_mod_add(s, s, k, order, ctx); 287 | 288 | unsigned long sig[2] = {0}; 289 | BN_bn2bin(s, (unsigned char *)sig); 290 | endian((unsigned char *)sig, BN_num_bytes(s)); 291 | pack(bkey, pid, hash, sig); 292 | printf("PID: %.8x\nHash: %.8x\nSig: %.8x %.8x\n", pid[0], hash[0], sig[1], sig[0]); 293 | } while (bkey[3] >= 0x62a32); 294 | 295 | base24(pkey, bkey); 296 | 297 | BN_free(k); 298 | BN_free(s); 299 | BN_free(x); 300 | BN_free(y); 301 | EC_POINT_free(r); 302 | 303 | BN_CTX_free(ctx); 304 | } 305 | 306 | int main() 307 | { 308 | // Init 309 | BIGNUM *a, *b, *p, *gx, *gy, *pubx, *puby, *n, *priv; 310 | BN_CTX *ctx = BN_CTX_new(); 311 | 312 | // make BigNumbers 313 | a = BN_new(); 314 | b = BN_new(); 315 | p = BN_new(); 316 | gx = BN_new(); 317 | gy = BN_new(); 318 | pubx = BN_new(); 319 | puby = BN_new(); 320 | n = BN_new(); 321 | priv = BN_new(); 322 | 323 | // Data from pidgen-Bink-resources 324 | /* Elliptic curve parameters: y^2 = x^3 + ax + b mod p */ 325 | BN_hex2bn(&p, "92ddcf14cb9e71f4489a2e9ba350ae29454d98cb93bdbcc07d62b502ea12238ee904a8b20d017197aae0c103b32713a9"); 326 | BN_set_word(a, 1); 327 | BN_set_word(b, 0); 328 | 329 | 330 | /* base point (generator) G */ 331 | BN_hex2bn(&gx, "46E3775ECE21B0898D39BEA57050D422A0AF989E497962BAEE2CB17E0A28D5360D5476B8DC966443E37A14F1AEF37742"); 332 | BN_hex2bn(&gy, "7C8E741D2C34F4478E325469CD491603D807222C9C4AC09DDB2B31B3CE3F7CC191B3580079932BC6BEF70BE27604F65E"); 333 | 334 | /* inverse of public key */ 335 | BN_hex2bn(&pubx, "5D8DBE75198015EC41C45AAB6143542EB098F6A5CC9CE4178A1B8A1E7ABBB5BC64DF64FAF6177DC1B0988AB00BA94BF8"); 336 | BN_hex2bn(&puby, "23A2909A0B4803C89F910C7191758B48746CEA4D5FF07667444ACDB9512080DBCA55E6EBF30433672B894F44ACE92BFA"); 337 | 338 | // Computed data 339 | /* order of G - computed in 18 hours using a P3-450 */ 340 | BN_hex2bn(&n, "DB6B4C58EFBAFD"); 341 | 342 | /* THE private key - computed in 10 hours using a P3-450 */ 343 | BN_hex2bn(&priv, "565B0DFF8496C8"); 344 | 345 | // Calculation 346 | EC_GROUP *ec = EC_GROUP_new_curve_GFp(p, a, b, ctx); 347 | EC_POINT *g = EC_POINT_new(ec); 348 | EC_POINT_set_affine_coordinates_GFp(ec, g, gx, gy, ctx); 349 | EC_POINT *pub = EC_POINT_new(ec); 350 | EC_POINT_set_affine_coordinates_GFp(ec, pub, pubx, puby, ctx); 351 | 352 | unsigned char pkey[26]; 353 | unsigned long pid[1]; 354 | pid[0] = 640000000 << 1; /* <- change */ 355 | 356 | // generate a key 357 | generate(pkey, ec, g, n, priv, pid); 358 | print_product_key(pkey); printf("\n\n"); 359 | 360 | // verify the key 361 | verify(ec, g, pub, (char*)pkey); 362 | 363 | // Cleanup 364 | BN_CTX_free(ctx); 365 | 366 | return 0; 367 | } 368 | --------------------------------------------------------------------------------