flake/helpers/tor-hostname.nix

84 lines
2.4 KiB
Nix

{pkgs ? import <nixpkgs> {}}:
pkgs.python3Packages.buildPythonApplication rec {
pname = "tor-hostname";
version = "1.0.0";
format = "other";
propagatedBuildInputs = with pkgs.python3Packages; [
pynacl
cryptography
];
dontUnpack = true;
installPhase = ''
mkdir -p $out/bin
cat > $out/bin/tor-hostname <<'EOF'
#!/usr/bin/env python3
"""Convert Tor v3 secret key to .onion hostname"""
import hashlib
import base64
import sys
def onion_address_from_public_key(public_key):
"""Generate .onion address from ed25519 public key"""
version = b'\x03'
checksum = hashlib.sha3_256(b'.onion checksum' + public_key + version).digest()[:2]
onion_address = base64.b32encode(public_key + checksum + version).decode().lower()
return f"{onion_address}.onion"
def read_tor_secret_key(filepath):
"""Read Tor hs_ed25519_secret_key file"""
with open(filepath, 'rb') as f:
content = f.read()
header = b'== ed25519v1-secret: type0 ==\x00\x00\x00'
if not content.startswith(header):
raise ValueError("Invalid Tor secret key file format")
expanded_key = content[32:96]
return expanded_key
def derive_public_from_expanded_secret(expanded_key):
"""Derive ed25519 public key from 64-byte expanded secret key"""
from nacl.bindings import crypto_scalarmult_ed25519_base_noclamp
secret_scalar = expanded_key[:32]
public_key = crypto_scalarmult_ed25519_base_noclamp(secret_scalar)
return public_key
def main():
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <path_to_hs_ed25519_secret_key>")
sys.exit(1)
secret_key_path = sys.argv[1]
try:
expanded_key = read_tor_secret_key(secret_key_path)
public_key = derive_public_from_expanded_secret(expanded_key)
hostname = onion_address_from_public_key(public_key)
print(hostname)
except FileNotFoundError:
print(f"Error: File not found: {secret_key_path}")
sys.exit(1)
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
if __name__ == '__main__':
main()
EOF
chmod +x $out/bin/tor-hostname
'';
meta = with pkgs.lib; {
description = "Convert Tor v3 secret key to .onion hostname";
license = licenses.mit;
platforms = platforms.unix;
};
}