Skip to content

Instantly share code, notes, and snippets.

@bertm
Last active November 19, 2017 20:58
Show Gist options
  • Save bertm/3a50d0c32520dfb4b34b to your computer and use it in GitHub Desktop.
Save bertm/3a50d0c32520dfb4b34b to your computer and use it in GitHub Desktop.
Freenet vanity key generator
/*
Link to libcrypto and libgmp. Only tested on a 64 bit machine.
This program may disclose your private key, harm your computer or kill your cat. Use only if you
understand what it does. I accept no responsibility for any use of this program.
*/
#include <openssl/evp.h>
#include <gmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
// SHA256 contexts
EVP_MD_CTX *mdctx;
EVP_MD_CTX *mdctx_clean;
const EVP_MD *md;
// DSA group info
const uint8_t P[] = "8608ac4f55361337f2a3e38ab1864ff3c98d66411d8d2afc9c526320c541f650"
"78e86bc78494a5d73e4a9a67583f941f2993ed6c97dbc795dd88f0915c9cfbff"
"c7e5373cde13e3c7ca9073b9106eb31bf82272ed0057f984a870a19f8a83bfa7"
"07d16440c382e62d3890473ea79e9d50c4ac6b1f1d30b10c32a02f685833c627"
"8fc29eb3439c5333885614a115219b3808c92a37a0f365cd5e61b5861761dad9"
"eff0ce23250f558848f8db932b87a3bd8d7a2f7cf99c75822bdc2fb7c1a1d78d"
"0bcf81488ae0de5269ff853ab8b8f1f2bf3e6c0564573f612808f68dbfef49d5"
"c9b4a705794cf7a424cd4eb1e0260552e67bfc1fa37b4a1f78b757ef185e86e9";
const uint8_t Q[] = "b143368abcd51f58d6440d5417399339a4d15bef096a2c5d8e6df44f52d6d379";
const uint8_t G[] = "51a45ab670c1c9fd10bd395a6805d33339f5675e4b0d35defc9fa03aa5c2bf4c"
"e9cfcdc256781291bfff6d546e67d47ae4e160f804ca72ec3c5492709f5f80f6"
"9e6346dd8d3e3d8433b6eeef63bce7f98574185c6aff161c9b536d76f8731373"
"65a4246cf414bfe8049ee11e31373cd0a6558e2950ef095320ce86218f992551"
"cc292224114f3b60146d22dd51f8125c9da0c028126ffa85efd4f4bfea2c1044"
"53329cc1268a97e9a835c14e4a9a43c6a1886580e35ad8f1de230e1af32208ef"
"9337f1924702a4514e95dc16f30f0c11e714a112ee84a9d8d6c9bc9e74e33656"
"0bb5cd4e91eabf6dad26bf0ca04807f8c31a2fc18ea7d45baab7cc997b53c356";
const uint8_t group[] = { // pre-encoded because I'm too lazy to code it myself
0x08, 0x00, 0x00, 0x86, 0x08, 0xac, 0x4f, 0x55, 0x36, 0x13, 0x37, 0xf2, 0xa3, 0xe3, 0x8a, 0xb1,
0x86, 0x4f, 0xf3, 0xc9, 0x8d, 0x66, 0x41, 0x1d, 0x8d, 0x2a, 0xfc, 0x9c, 0x52, 0x63, 0x20, 0xc5,
0x41, 0xf6, 0x50, 0x78, 0xe8, 0x6b, 0xc7, 0x84, 0x94, 0xa5, 0xd7, 0x3e, 0x4a, 0x9a, 0x67, 0x58,
0x3f, 0x94, 0x1f, 0x29, 0x93, 0xed, 0x6c, 0x97, 0xdb, 0xc7, 0x95, 0xdd, 0x88, 0xf0, 0x91, 0x5c,
0x9c, 0xfb, 0xff, 0xc7, 0xe5, 0x37, 0x3c, 0xde, 0x13, 0xe3, 0xc7, 0xca, 0x90, 0x73, 0xb9, 0x10,
0x6e, 0xb3, 0x1b, 0xf8, 0x22, 0x72, 0xed, 0x00, 0x57, 0xf9, 0x84, 0xa8, 0x70, 0xa1, 0x9f, 0x8a,
0x83, 0xbf, 0xa7, 0x07, 0xd1, 0x64, 0x40, 0xc3, 0x82, 0xe6, 0x2d, 0x38, 0x90, 0x47, 0x3e, 0xa7,
0x9e, 0x9d, 0x50, 0xc4, 0xac, 0x6b, 0x1f, 0x1d, 0x30, 0xb1, 0x0c, 0x32, 0xa0, 0x2f, 0x68, 0x58,
0x33, 0xc6, 0x27, 0x8f, 0xc2, 0x9e, 0xb3, 0x43, 0x9c, 0x53, 0x33, 0x88, 0x56, 0x14, 0xa1, 0x15,
0x21, 0x9b, 0x38, 0x08, 0xc9, 0x2a, 0x37, 0xa0, 0xf3, 0x65, 0xcd, 0x5e, 0x61, 0xb5, 0x86, 0x17,
0x61, 0xda, 0xd9, 0xef, 0xf0, 0xce, 0x23, 0x25, 0x0f, 0x55, 0x88, 0x48, 0xf8, 0xdb, 0x93, 0x2b,
0x87, 0xa3, 0xbd, 0x8d, 0x7a, 0x2f, 0x7c, 0xf9, 0x9c, 0x75, 0x82, 0x2b, 0xdc, 0x2f, 0xb7, 0xc1,
0xa1, 0xd7, 0x8d, 0x0b, 0xcf, 0x81, 0x48, 0x8a, 0xe0, 0xde, 0x52, 0x69, 0xff, 0x85, 0x3a, 0xb8,
0xb8, 0xf1, 0xf2, 0xbf, 0x3e, 0x6c, 0x05, 0x64, 0x57, 0x3f, 0x61, 0x28, 0x08, 0xf6, 0x8d, 0xbf,
0xef, 0x49, 0xd5, 0xc9, 0xb4, 0xa7, 0x05, 0x79, 0x4c, 0xf7, 0xa4, 0x24, 0xcd, 0x4e, 0xb1, 0xe0,
0x26, 0x05, 0x52, 0xe6, 0x7b, 0xfc, 0x1f, 0xa3, 0x7b, 0x4a, 0x1f, 0x78, 0xb7, 0x57, 0xef, 0x18,
0x5e, 0x86, 0xe9, 0x01, 0x00, 0x00, 0xb1, 0x43, 0x36, 0x8a, 0xbc, 0xd5, 0x1f, 0x58, 0xd6, 0x44,
0x0d, 0x54, 0x17, 0x39, 0x93, 0x39, 0xa4, 0xd1, 0x5b, 0xef, 0x09, 0x6a, 0x2c, 0x5d, 0x8e, 0x6d,
0xf4, 0x4f, 0x52, 0xd6, 0xd3, 0x79, 0x07, 0xff, 0x51, 0xa4, 0x5a, 0xb6, 0x70, 0xc1, 0xc9, 0xfd,
0x10, 0xbd, 0x39, 0x5a, 0x68, 0x05, 0xd3, 0x33, 0x39, 0xf5, 0x67, 0x5e, 0x4b, 0x0d, 0x35, 0xde,
0xfc, 0x9f, 0xa0, 0x3a, 0xa5, 0xc2, 0xbf, 0x4c, 0xe9, 0xcf, 0xcd, 0xc2, 0x56, 0x78, 0x12, 0x91,
0xbf, 0xff, 0x6d, 0x54, 0x6e, 0x67, 0xd4, 0x7a, 0xe4, 0xe1, 0x60, 0xf8, 0x04, 0xca, 0x72, 0xec,
0x3c, 0x54, 0x92, 0x70, 0x9f, 0x5f, 0x80, 0xf6, 0x9e, 0x63, 0x46, 0xdd, 0x8d, 0x3e, 0x3d, 0x84,
0x33, 0xb6, 0xee, 0xef, 0x63, 0xbc, 0xe7, 0xf9, 0x85, 0x74, 0x18, 0x5c, 0x6a, 0xff, 0x16, 0x1c,
0x9b, 0x53, 0x6d, 0x76, 0xf8, 0x73, 0x13, 0x73, 0x65, 0xa4, 0x24, 0x6c, 0xf4, 0x14, 0xbf, 0xe8,
0x04, 0x9e, 0xe1, 0x1e, 0x31, 0x37, 0x3c, 0xd0, 0xa6, 0x55, 0x8e, 0x29, 0x50, 0xef, 0x09, 0x53,
0x20, 0xce, 0x86, 0x21, 0x8f, 0x99, 0x25, 0x51, 0xcc, 0x29, 0x22, 0x24, 0x11, 0x4f, 0x3b, 0x60,
0x14, 0x6d, 0x22, 0xdd, 0x51, 0xf8, 0x12, 0x5c, 0x9d, 0xa0, 0xc0, 0x28, 0x12, 0x6f, 0xfa, 0x85,
0xef, 0xd4, 0xf4, 0xbf, 0xea, 0x2c, 0x10, 0x44, 0x53, 0x32, 0x9c, 0xc1, 0x26, 0x8a, 0x97, 0xe9,
0xa8, 0x35, 0xc1, 0x4e, 0x4a, 0x9a, 0x43, 0xc6, 0xa1, 0x88, 0x65, 0x80, 0xe3, 0x5a, 0xd8, 0xf1,
0xde, 0x23, 0x0e, 0x1a, 0xf3, 0x22, 0x08, 0xef, 0x93, 0x37, 0xf1, 0x92, 0x47, 0x02, 0xa4, 0x51,
0x4e, 0x95, 0xdc, 0x16, 0xf3, 0x0f, 0x0c, 0x11, 0xe7, 0x14, 0xa1, 0x12, 0xee, 0x84, 0xa9, 0xd8,
0xd6, 0xc9, 0xbc, 0x9e, 0x74, 0xe3, 0x36, 0x56, 0x0b, 0xb5, 0xcd, 0x4e, 0x91, 0xea, 0xbf, 0x6d,
0xad, 0x26, 0xbf, 0x0c, 0xa0, 0x48, 0x07, 0xf8, 0xc3, 0x1a, 0x2f, 0xc1, 0x8e, 0xa7, 0xd4, 0x5b,
0xaa, 0xb7, 0xcc, 0x99, 0x7b, 0x53, 0xc3, 0x56 };
void digest_init()
{
OpenSSL_add_all_digests();
md = EVP_get_digestbyname("SHA256");
if(!md) {
printf("Unknown message digest SHA256\n");
exit(1);
}
mdctx_clean = EVP_MD_CTX_create();
mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx_clean, md, NULL);
EVP_DigestUpdate(mdctx_clean, group, sizeof(group));
}
// calculates SHA256(group + message) in hash
void sha256_hash(const char *message, const size_t len, char hash[32]) {
int md_len;
EVP_MD_CTX_copy_ex(mdctx, mdctx_clean);
EVP_DigestUpdate(mdctx, message, len);
EVP_DigestFinal_ex(mdctx, hash, &md_len);
}
// calculates the hash of pubkey y
void fast_digest(uint8_t hash[32], mpz_t y) {
int md_len;
uint8_t yy[256 + 8] = { 0 }; // 2048 bits + 8 byte prefix
uint8_t *ptr = yy + 8;
size_t words;
mpz_export(ptr, &words, 1 /* most significant word first */,
8, 1 /* most significant byte first */, 0, y);
size_t bits = mpz_sizeinbase(y, 2);
size_t bytes = bits >> 3;
ptr = ptr + (words * 8) - bytes - 1;
if (ptr[0] & 0x80) {
ptr -= 3;
// Prefix 0x00
ptr[0] = (bits >> 8) & 0xFF;
ptr[1] = bits & 0xFF;
//ptr[2] = 0x00;
sha256_hash(ptr, bytes + 4, hash);
} else {
ptr -= 2;
// No prefix
ptr[0] = (bits >> 8) & 0xFF;
ptr[1] = bits & 0xFF;
sha256_hash(ptr, bytes + 3, hash);
}
}
// ***********************************************
// OVERRIDE THIS METHOD TO MATCH YOUR REQUIREMENTS
// ***********************************************
int match(const uint8_t* digest) {
// base64(digest) has prefix "vanity", e.g. matches 0xbd 0xa9 0xe2 0xb7 0x20 in first 36 bits
return digest[0] == 0xbd &&
digest[1] == 0xa9 &&
digest[2] == 0xe2 &&
digest[3] == 0xb7 &&
(digest[4] & 0xf0) == 0x20;
}
int main(int argc, char **argv)
{
digest_init();
// Require a hexadecimal 256 private key as a starting point for the search. The user has to
// ensure it is random enough for his purposes, and we just blindly assume that there won't be
// overflow (e.g. where the privkey, after sequential increments, will be greater than q).
if (argc != 2) {
printf("usage: %s <hex 256 bit privkey starting point>\n", argv[0]);
exit(1);
}
const char *X = argv[1];
unsigned char digest[32];
mpz_t p, q, g, x, y;
mpz_init(p);
mpz_init(q);
mpz_init(g);
mpz_init(x);
mpz_init(y);
mpz_set_str(p, P, 16);
mpz_set_str(q, Q, 16);
mpz_set_str(g, G, 16);
mpz_set_str(x, X, 16);
mpz_powm(y, g, x, p);
long unsigned int rounds = 0;
// Until we have found a match, increment the private key by one. This is efficient: we only
// have to multiply the public key by g (mod p), instead of doing the full exponentiation
// (mod p).
while(1) {
fast_digest(digest, y);
if (match(digest))
{
mpz_add_ui(x, x, rounds);
printf("\nGot a matching private key!\n>>> ");
mpz_out_str(stdout, 16, x);
printf("\nFound after trying %ld keys\n", rounds);
// Uh-oh, we printed the key in hex. Pad it to 256 bits with leading zeroes and base64
// encode the beast (mind you, Freenet uses a custom base64 alphabet). Then you have the
// privkey part of your insert URI. The other parts are trivial to generate.
exit(0);
}
if (!(rounds & 0xfffff)) {
printf("\rTried %ld keys \rTried %ld keys", rounds, rounds);
fflush(stdout);
} else if (!(rounds & 0x3ffff)) {
printf(".");
fflush(stdout);
}
rounds++;
mpz_mul(y, y, g);
mpz_mod(y, y, p);
}
return 0;
}
@mr-fool
Copy link

mr-fool commented Jul 13, 2017

What's the realistic risk of using the code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment