Queer Soy Code

Migrating an onion service key from arti to C tor

I started an onion service using arti and exposed it, but then I realized that arti is too experimental and wanted to move to C tor. According to this page they don’t plan to offer support to migrate from arti keys to C tor ones, so I had to do it manually.

Extract the key:

1docker compose exec arti cat /home/arti/.local/share/arti/keystore/hss/onimages/ks_hs_id.ed25519_expanded_private > hs

Decode it:

1grep -v '^-' hs | tr -d '\n' | base64 -d > hs_decoded

Hex it for a manual split:

1cat hs_decoded | xxd -p > hs_parsed

Edit the hs_parsed file to find the private key. I followed this guide. This is what my key looks like:

 1# magic string "openssh-key-v1" + null byte
 26f70656e7373682d6b65792d763100
 3# length of string = 4
 400000004
 5# cipher = none
 66e6f6e65
 7# length of string = 4
 800000004
 9# kdfname = none
106e6f6e65
11# kdf placeholder
1200000000
13# number of keys = 1
1400000001
15# length of first public key = 76
160000004c
17# length of string = 36
1800000024
19# key type? "ed25519-expanded@spec.torproject.org"
20656432353531392d657870616e64656440737065632e746f7270726f6a6563742e6f7267
21# length of key = 32
2200000020
23# public key (censored)
24xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
25# length of remaining payload = 160
26000000a0
27# misterious 8 bytes
2861f6187a61f6187a
29# length of string = 36
3000000024
31# key type? "ed25519-expanded@spec.torproject.org"
32656432353531392d657870616e64656440737065632e746f7270726f6a6563742e6f7267
33# length of key = 32
3400000020
35# public key again (censored)
36xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
37# length of key = 64
3800000040
39# private key (censored)
40xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
41# length of private key second payload = 0
4200000000
43# padding
4401020304

If you know already the offset you can probably extract the key directly with dd or something.

Copy the private key line (without a newline at the end) into a file named hs_private, then convert it to binary:

1cat hs_private | xxd -p -r > hs_private_bin

Create the tor header and combine it into the final file:

1printf "== ed25519v1-secret: type0 ==\x00\x00\x00" > tor_header.bin
2cat tor_header.bin hs_private_bin > hs_ed25519_secret_key

Copy the private key:

1xxd -p hs_ed25519_secret_key

Add it to the container:

1docker compose exec tor sh -c "echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | xxd -p -r > /var/lib/tor/onion/hs_ed25519_secret_key"

Sanity check to make sure that the keys are the same (compare the outputs):

1docker compose exec tor xxd /var/lib/tor/onion/hs_ed25519_secret_key
2xxd hs_ed25519_secret_key

Remove the old public key and hostname and restart the container:

1docker compose exec tor rm /var/lib/tor/onion/hostname
2docker compose exec tor rm /var/lib/tor/onion/hs_ed25519_public_key
3docker compose restart tor

Sanity check to confirm that your onion service URL was migrated correctly:

1docker compose exec tor cat /var/lib/tor/onion/hostname

Now you can stop arti and wait a few minutes to see that the onion service is still reachable via C tor.

#Hosting #Tor