Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Generating custom .onion names with the WebCrypto API
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/*
* thirty-two
* https://github.com/chrisumbel/thirty-two
*
* Copyright (c) 2011, Chris Umbel
*/
function base32(plain) {
var charTable = "abcdefghijklmnopqrstuvwxyz234567";
plain = new Uint8Array(plain);
var shiftIndex = 0;
var digit = 0;
var encoded = "";
for (var i=0; i<plain.length;) {
var current = plain[i];
if (shiftIndex > 3) {
digit = current & (0xff >> shiftIndex);
shiftIndex = (shiftIndex + 5) % 8;
digit = (digit << shiftIndex) | ((i + 1 < plain.length) ?
plain[i + 1] : 0) >> (8 - shiftIndex);
i++;
} else {
digit = (current >> (8 - (shiftIndex + 5))) & 0x1f;
shiftIndex = (shiftIndex + 5) % 8;
if (shiftIndex == 0) i++;
}
encoded += charTable[digit];
}
return encoded;
}
/*
* base64-arraybuffer
* https://github.com/niklasvh/base64-arraybuffer
*
* Copyright (c) 2012 Niklas von Hertzen
* Licensed under the MIT license.
*/
function base64(arraybuffer) {
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var bytes = new Uint8Array(arraybuffer),
i, len = bytes.length, base64 = "";
for (i = 0; i < len; i+=3) {
base64 += chars[bytes[i] >> 2];
base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
base64 += chars[bytes[i + 2] & 63];
}
if ((len % 3) === 2) {
base64 = base64.substring(0, base64.length - 1) + "=";
} else if (len % 3 === 1) {
base64 = base64.substring(0, base64.length - 2) + "==";
}
return base64;
}
function formatKey(key) {
// Export the DER-encoded ASN.1 private key information.
var promise = crypto.subtle.exportKey("pkcs8", key);
return promise.then(function (pkcs8) {
var encoded = base64(pkcs8);
// Wrap lines after 64 characters.
var formatted = encoded.match(/.{1,64}/g).join("\n");
// Wrap the formatted key in a header and footer.
return "-----BEGIN PRIVATE KEY-----\n" + formatted +
"\n-----END PRIVATE KEY-----";
});
}
function generateRSAKey() {
var alg = {
// This could be any supported RSA* algorithm.
name: "RSASSA-PKCS1-v1_5",
// We won't actually use the hash function.
hash: {name: "SHA-1"},
// Tor hidden services use 1024 bit keys.
modulusLength: 1024,
// We will use a fixed public exponent for now.
publicExponent: new Uint8Array([0x03])
};
return crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
}
function computeOnionHash(publicKey) {
// Export the DER encoding of the SubjectPublicKeyInfo structure.
var promise = crypto.subtle.exportKey("spki", publicKey);
promise = promise.then(function (spki) {
// Compute the SHA-1 digest of the SPKI.
// Skip 22 bytes (the SPKI header) that are ignored by Tor.
return crypto.subtle.digest({name: "SHA-1"}, spki.slice(22));
});
return promise.then(function (digest) {
// Base32-encode the first half of the digest.
return base32(digest.slice(0, 10));
});
}
function findOnionName(pattern) {
var key;
// Start by generating a random key pair.
var promise = generateRSAKey().then(function (pair) {
key = pair.privateKey;
// Generate the .onion hash of the public key.
return computeOnionHash(pair.publicKey);
});
return promise.then(function (hash) {
// Try again if the pattern doesn't match.
if (!pattern.test(hash)) {
return findOnionName(pattern);
}
// Key matches! Export and format it.
return formatKey(key).then(function (formatted) {
return {key: formatted, hash: hash};
});
});
}
findOnionName(/ab/).then(function (result) {
console.log(result.hash + ".onion", result.key);
}, function (err) {
console.log("An error occurred, please reload the page.");
});
@mane

This comment has been minimized.

Copy link

mane commented Mar 15, 2015

Hi there,

Thanks for your code.

May I know what are the dependencies and how I could execute this please?

Cheers
mane

@chris2286266

This comment has been minimized.

Copy link

chris2286266 commented Nov 28, 2016

@neuhaus

This comment has been minimized.

Copy link

neuhaus commented Jan 9, 2018

Has anyone written something for the new longer v3 addresses yet?
https://trac.torproject.org/projects/tor/wiki/doc/NextGenOnions#Howtosetupyourownprop224service

@princeCoolstar

This comment has been minimized.

Copy link

princeCoolstar commented Sep 28, 2019

How can I get onion domain name from the private key?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.