By all sources I can find, onion / hidden service "domains" are generated by this process:
Generate a 1024-bit RSA keypair
Take the SHA-1 of the public key
Base32 encode the first 80 bytes of the hash
I have tried to replicate it, by first generating a memorable vanity URL with Scallion, "zzzzzzycizaamf47.onion". I then wrote a PHP script to derive the public key from that private key, strip the formatting, hash it, truncate to 10 chars, and base32 encode it. First of all I found three different "encode as base32" functions, all which give different results. This is the code, with results commented after the three functions:
$privKey = 'MIIEpAIBAAKC ~snip~ azScNv5A';
$rsa = new Crypt_RSA();
$rsa->loadKey($privKey);
$pubKey = $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$pubKey = str_replace(array("\r", "\n", ' ', '=', '-----BEGINRSAPUBLICKEY-----',
'-----ENDRSAPUBLICKEY-----'), '', $pubKey); //
$pubKey = sha1($pubKey);
$pubKey = substr($pubKey, 0, 10);
echo base_convert($pubKey, 16, 32).PHP_EOL; //Result: 68s3ii2
echo crockford32_encode($pubKey).PHP_EOL; //Result: 60rkjcb365hp2d1j
$base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE);
echo $base32->encode($pubKey).PHP_EOL; //Result: GAYTSMLDGFRWCNBS
What's going wrong here? Why do the three "base32" functions give different results? Here is the code for crockford32_encode, and here is the code for Base2n. I have tried nearly all combinations of formatting / whitespace stripping and character truncation, and have never gotten close to the desired "zzzzzzycizaamf47". I previously posted this question on StackOverflow and got no answers, only a comment suggesting I ask here.