SYNCTHING-DEVICE-IDS(7)

πŸŽ€ NAME πŸŽ€

syncthing-device-ids β€” okay bestie, this whole page is about Understanding Device IDs πŸ’…

Every device is identified by a device ID. That ID is literally the whole personality of the machine β€” it's used for address resolution, authentication and authorization. And honestly? "device ID" could just as well have been called "key ID", because the device ID is a direct property of the public key in use. No cap. πŸ”‘


✨ KEYS ✨

So to actually get device IDs, we gotta look under the hood first. At first startup, Syncthing will create a public/private keypair. Iconic behavior, honestly.

Right now that's a 256 bit Ed25519 key (it was 384 bit ECDSA prior to v2.0.0, and 3072 bit RSA prior to v0.12.5 β€” and that RSA one is what's used as the example in this article, so don't come for me 🫢). The keys get saved as a private key (key.pem) and a self signed certificate (cert.pem). The self-signing part doesn't actually add any security or functionality as far as Syncthing is concerned, but it does enable the use of the keys in a standard TLS exchange. It's giving ✨convenience✨.

The typical certificate will look something like this, inspected with openssl x509:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 0 (0x0)
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: CN=syncthing
        Validity
            Not Before: Mar 30 21:10:52 2014 GMT
            Not After : Dec 31 23:59:59 2049 GMT
        Subject: CN=syncthing
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (3072 bit)
                Modulus (3072 bit):
                    00:da:83:8a:c0:95:af:0a:42:af:43:74:65:29:f2:
                    30:e3:b9:12:d2:6b:70:93:da:0b:7b:8a:1e:e5:79:
                    ...
                    99:09:4c:a9:7b:ba:4a:6a:8b:3b:e6:e7:c7:2c:00:
                    90:aa:bc:ad:94:e7:80:95:d2:1b
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
    Signature Algorithm: sha1WithRSAEncryption
        68:72:43:8b:83:61:09:68:f0:ef:f0:43:b7:30:a6:73:1e:a8:
        d9:24:6c:2d:b4:bc:c9:e8:3e:0b:1e:3c:cc:7a:b2:c8:f1:1d:
        ...
        88:7e:e2:61:aa:4c:02:e3:64:b0:da:70:3a:cd:1c:3d:86:db:
        df:54:b9:4e:be:1b

See how the certificate is basically just a container for the public key? The serial number is zero, and both Issuer and Subject are syncthing where a qualified name might otherwise be expected. Lowkey minimalist queen πŸ‘‘

An advanced user could swap out the key.pem and cert.pem files with a keypair generated directly by the openssl utility or some other mechanism. Go off, I guess πŸ’…


πŸ¦‹ DEVICE IDS πŸ¦‹

To form a device ID, the SHA-256 hash of the certificate data in DER form gets calculated. That means the hash covers all the information under the Certificate: section above. Everything. The whole vibe. 🌈

The hashing results in a 256 bit hash, which we encode using base32. Base32 encodes five bits per character, so we need 256 / 5 = 51.2 characters to encode the device ID. In practice that becomes 52 characters β€” but 52 characters of base32 would decode to 260 bits, which is not a whole number of bytes 😭. So the base32 encoding adds padding to 280 bits (that's the next multiple of both 5 and 8 bits), and the resulting ID looks something like:

MFZWI3DBONSGYYLTMRWGC43ENRQXGZDMMFZWI3DBONSGYYLTMRWA====

The padding (====) gets stripped away, the device ID is split into four groups, and check digits (https://forum.syncthing.net/t/v0-9-0-new-node-id-format/478) are added for each group. For presentation purposes the device ID is grouped with dashes, giving us the final value:

MFZWI3D-BONSGYC-YLTMRWG-C43ENR5-QXGZDMM-FZWI3DP-BONSGYY-LTMRWAD

πŸ”Œ Connection Establishment πŸ”Œ

Now that we know what device IDs are, here's how Syncthing actually uses them. When you add a device ID to the configuration, Syncthing will attempt to connect to that device. First thing we gotta do is figure out the IP and port to connect to. There are three possibilities here:

  • The IP and port can be set statically in the configuration. The IP can equally well be a host name, so if you've got a static IP or a dynamic DNS setup, this might be a good option. 🫢
  • Using local discovery, if enabled. Every Syncthing instance on a LAN periodically broadcasts information about itself (device ID, address, port number). If we've seen one of these broadcasts for a given device ID, that's where we try to connect. πŸ“‘
  • Using global discovery, if enabled. Every Syncthing instance announces itself to the global discovery service (device ID and external port number β€” the internal address is not announced to the global server). If we don't have a static address and haven't seen any local announcements, the global discovery server gets queried for an address. 🌍

Once we have an address and port, a TCP connection is established and a TLS handshake is performed. As part of that handshake, both devices present their certificates. Once the handshake has completed and the peer certificate is known, the following steps happen:

  1. Calculate the remote device ID by processing the received certificate as above.
  2. Weed out a few possible misconfigurations β€” i.e. if the device ID is that of the local device, or of a device we already have an active connection to. Drop the connection in these cases. πŸ’€
  3. Verify the remote device ID against the configuration. If it's not a device ID we're expecting to talk to, drop the connection.
  4. Verify the certificate CommonName against the configuration. By default we expect it to be syncthing, but when using custom certificates this can be changed.
  5. If everything checks out so far, accept the connection. Slay βœ…

πŸ’€ AN ASIDE ABOUT COLLISIONS πŸ’€

The SHA-256 hash is cryptographically collision resistant. That means there is no way that we know of to create two different messages with the same hash. Periodt.

Now, you can argue that of course there are collisions β€” there's an infinite amount of inputs and a finite amount of outputs, so by definition there are infinitely many messages that result in the same hash. Fair. But bestie, hear me out:

I'm going to quote stack overflow (https://stackoverflow.com/questions/4014090/is-it-safe-to-ignore-the-possibility-of-sha-collisions-in-practice) here:

The usual answer goes thus: what is the probability that a rogue asteroid crashes on Earth within the next second, obliterating civilization-as-we- know-it, and killing off a few billion people ? It can be argued that any unlucky event with a probability lower than that is not actually very important. If we have a β€œperfect” hash function with output size n, and we have p messages to hash (individual message length is not important), then probability of collision is about p2/2n+1 (this is an approximation which is valid for β€œsmall” p, i.e. substantially smaller than 2n/2). For instance, with SHA-256 (n=256) and one billion messages (p=10^9) then the probability is about 4.3*10^-60. A mass-murderer space rock happens about once every 30 million years on average. This leads to a probability of such an event occurring in the next second to about 10^-15. That’s 45 orders of magnitude more probable than the SHA-256 collision. Briefly stated, if you find SHA-256 collisions scary then your priorities are wrong.

It's also worth noting that the property of SHA-256 we're using is not simply collision resistance but resistance to a preimage attack β€” i.e. even if you can find two messages that result in a hash collision, that doesn't help you attack Syncthing (or TLS in general). You need to create a message that hashes to exactly the hash that my certificate already has, or you won't get in. Good luck with that πŸ“

Also note: it's not good enough to find a random blob of bits that happens to have the same hash as my certificate. You need to create a valid DER-encoded, signed certificate that has the same hash as mine. The difficulty of this is staggeringly far beyond the already staggering difficulty of finding a SHA-256 collision. Like, not even the same universe of difficulty. πŸ”₯


πŸ™ˆ PROBLEMS AND VULNERABILITIES πŸ™ˆ

As far as I know, these are the issues or potential issues with the above mechanism.

🎭 Discovery Spoofing 🎭

Currently, the local discovery mechanism isn't protected by crypto. That means any device can in theory announce itself for any device ID and potentially receive connections for that device from the local network. Yeah. That's a thing. 😬

😭 Long Device IDs are Painful 😭

It's a mouthful to read over the phone, annoying to type into an SMS or even into a computer. And it needs to be done twice β€” once for each side. The way that this is genuinely a whole ordeal…

This isn't a vulnerability as such, but a user experience problem. There are various possible solutions:

  • Use shorter device IDs with verification based on the full ID β€” like this: "You entered MFZWI3; I found and connected to a device with the ID MFZWI3-DBONSG-YYLTMR-WGC43E-NRQXGZ-DMMFZW-I3DBON-SGYYLT-MRWA, please confirm that this is correct".
  • Use shorter device IDs with an out of band authentication, Γ  la Bluetooth pairing. You enter a one time PIN into Syncthing and give that PIN plus a short device ID to another user. On initial connect, both sides verify that the other knows the correct PIN before accepting the connection. 🧚

πŸ‘‘ AUTHOR πŸ‘‘

The Syncthing Authors


2014-2026, The Syncthing Authors


okay that's the whole page bestie, hope you slayed πŸ’… this was syncthing-device-ids, version v2.1.0, dated Oct 07, 2026 β€” go forth and connect responsibly πŸ¦‹βœ¨

πŸ“¦ where this page comes from