Different view on security perspective

I did’t say that.

I’m saying you do all manually. ‘Shake’ server only helps to find each other. You do visual check with GUID’s, and accept only if it matches.

Then your solution basically achieves the same as the third point in the post by @calmh:

  • “Sender” requests a “short device ID” from the discovery servers. These are valid for 24 hours, look like “aHyV5” or possibly “cake table orange love blue” depending on what encoding scheme we like.

But implementation wise it seems worse/more complicated than “just” adding that to the discovery server.

After taking another look at the SHA3 contenders as well as current ECC signature algorithms like Ed25519 my first idea unfortunately proofs to be impossible. The idea was to reduce the number of bits required for a full device ID to about 128 from currently 256. If that were possible, we could create an easy to pronounce string of 8 words (7.53 to be precise) with a custom dictionary of ~130k words.

As a comparison: the English language has ~1 million words, of which most can’t be used because they are too long, not widely known or complicated to pronounce. The diceware wordlists use 7776 words, leading to ~12.9 bits of entropy per word, while our hypothetical wordlist would allow for 17 bits of entropy per word.

Unfortunately state of the art hash functions (SHA3 finalists) as well as the latest ECC signature algorithms all have an output size of 256 bit.

This means there is no alternative to making this time based. :confused: I still think a diceware-like encoding is the way to go, because it’s the most user friendly solution out there¹.

However I’d like to propose switching the pin and ID to improve security: With the diceware dictionaries we have 3*12.9=38.7 bits of entropy using three words which leaves us with ~450 billion unique combinations. That’s a lot more than the amount of devices which will ever want to connect to each other in a 24h period. If we use a 5 digit numeric ID we can still support nearly one million devices in 24h. That should be enough for now :wink: And because of the bigger namespace our security margin just improved significantly for free.

Also: We’ll obviously have to rate-limit people from brute forcing the pin, which has become a short auth string (SAS) in my proposal. With the SAS I’d feel that we can allow 5 tries instead of three before blocking any attempt from any IP to connect (which equals scrapping the share offer).

¹:It’s a lot easier to understand words over the phone compared to single characters or digits. That’s why the military alphabet was invented. And I would go with three words as this combination is very easy to remember and recite for several reasons. It’s also the minimum number of points which sound natural when reciting a list.

1 Like

Afaik, you can always take a hash, and only use half of it. Of course that increases the collision risk. I think there’s a wikipedia article about this, I can look for that later.

Sure, truncating the output is always possible. I haven’t looked at the security properties well enough yet. The fact that a 128 bit output isn’t even offered optionally by any of the SHA3 finalists made me think some important property would probably suffer by this. But afaik an sha512 hash truncated to 256 bits is still stronger than a sha256 hash, so maybe that’s why this choice was made. I wouldn’t want to jump to conclusions tough :wink:

Shortening hashes is absolutely fine. It just increases the risk for collisions.

After reading up on it, I agree with the general sentiment, but the main question still stands: are 128 bits enough or not? I wouldn’t have any problems with truncating a 512 bit hash to 256 bits, because there is enough of a security margin.

From the wikipedia article about collision resistance:

So in case of a 128 bit output, one has to calculate only 2^64 hashes to find a collision.

To add some more color: the bitcoin community currently calculates about 2^85 SHA256 hashes every year: cryptanalysis - Is 80 bits of key size considered safe against brute force attacks? - Cryptography Stack Exchange

This means the bitcoin community alone could find over two million collisions to 128 bit hashes every year. And to be honest the investments in bitcoin are a joke compared to the budgets of certain agencies. Other interesting examples/posts, the first one explicitly states that less than 192 bits output size should not be considered safe at this time:

In our usecase these hashes protect the long term identity of a syncthing device and not just the RFID chip on some vegetables. In the worst case scenario this syncthing identity is beeing ported to every new device, leading to several decades of use and possible abuse.

There is obviously more to the picture: the device ID is the hash of the RSA certificate, so an attacker has to create a working RSA certificate which also hashes to the same output. Assessing the added difficulty of such problems in the form of “additional bits of safety margin” is not easily possible tough. But in general the cryptography community is very conservative so that a security margin which can’t be properly calculated/estimated is assumed void and the worst case estimate is used.

In the end we could probably do it if we didn’t care about the thread model of someone spending millions of dollars to get at your data. Personally I’d like to have this included in the threat model for the cryptography, even tough realistically such an attacker would simply pay someone to install a camera in your home to record your passphrase (in case of hard disc encryption) and copy the harddrive at a later point.

If we could get down to maybe 5 words using the encoding scheme I described earlier, this would be a real win usability wise and living with the attached dangers could be worth it. But the ID would still be 8 words long, even if we decide to truncate the hash to 128 bits and go trough the pain of creating our own wordlist with >130k entries.

As time passes new weaknesses in hash functions are found and advances in manufacturing techniques lead to faster crackers. So we’ll inevitably have to use longer hash outputs again at some point.

The ultimate decision is obviously that of @calmh, but I’d personally prefer to use the future proof solution from the get go.

1 Like

I’m not sure about this, but one possible solution might be to use a slower hash function. We don’t particularly care how long it takes to compute a device ID from a public key, and it would considerably slow down an attacker.

Of course this would be a disadvantage for slow devices. And I don’t know how many bytes that would give us effectively.

I’m not fully following what you guys are discussing, to be honest. The “short ID” I was talking about doesn’t need to be secure, it just needs to be unique enough to be used for easy discovery for a day or two. Think of it as an URL shortener with very short lived tokens. Any security would live in the pin code, which is secure enough to protect your bank account and would be so for our purposes as well. It would be forgotten after one successful or a few unsuccessful attempts.

I thought about the possibility to make the device ID itself more human-readable and memorable. If that were possible (eg. encoded with 5 words diceware-style), we wouldn’t need to implement the short ids, pin and sync across directory servers. But when I did the math it showed that 256 bits simply can’t be encoded in such a way that it’s short enough for humans to read over the phone (~5 words).

Then we dove into the security of a 128 bit output, but it seems questionable if this can be done securely. At some point we’d have to increase it again anyways because of moores law.

So in the end I just proposed to use a number as the id. 5 digits give us ~1 million users which should be enough over a 24 hour period. And upgrading to 6 is always an option. The security of the authentication (“pin”) would be significantly increased with a big namespace, so a three word short authentication string should work well.

This achives the following:

  • ID and authentication token can’t be confused (and leaked), because they don’t look similar
  • enough IDs for 24h
  • great security because the auth token has a big namespace

I wonder if having key servers would be useful.

For example, you use a pin + passphrase to establish a share/trust by encrypting a secret, on the other side the user enters the pin to discover the device, and passphrase to decrypt the secret, then encrypts the secret + own device ID with the sources public key, this way proving that the device can be trusted?

pin + passphrase could be replaced with a longer ping, and probably be valid for a very short time?

Could you describe what the key servers would be doing exactly in your scenario?

If I understand it correctly, this would break a very important feature of the aforementioned mechanism:

Online authentication. If you have to supply the secret to exactly the device you want elevated rights on, this device can make sure that you have only a specified number of tries before the whole offer will be “forgotten”.

This has two drawbacks: it only works when both devices are online and it means that one can prevent new connections via a DOS attack.

But if a possible attacker can get their hands on something they have to decrypt to get at a secret which then gives them elevated rights on another machine, they can brute-force it. And for this attack scenario a short pin or passphrase aren’t strong enough, because an attacker has unlimited tries and is only rate limited by their own hardware. and you have no way to brute-force it.to supply the pre-shared secret without

In order to perform encryption, you’d need the full public key of a device.

You could have maximum 3 attempts per pin. For DoS you could have 3 servers that perform this.

@calmh I think I just found a problem with your proposal. The discosrv should not be trusted, however:

  • Recipient enters the short code and the PIN in an “add connection” dialog.
  • Stuff connects, authenticates using the PIN code (which is then consumed), and the devices are added on both sides. The folders get added on the recipient side at this stage, using our current dialog or something superior.

→ Recipient can be given wrong IP by maliciuos discovery server. The same entity which modified the discovery server runs an evil node at the IP given to the recipient by the discosrv. Recipient connects, the evil node accepts all pins and waits for files to be shared by the recipient. This is no MITM, but bad enough. The evil node can also put a trojan inside an image/media file which is shared with B. Once B (or his indexer) opens the file (eg. to create a preview), a rootkit is installed. From here all devices B is connected to can be compromised as well.

@AudriusButkevicius I still don’t really understand the advantages of the mechanism you proposed. Your proposal removes the problem I described above, if the passphrase is long enough. But then we are at the beginning, because now the partners have to communicate a long passphrase out of band instead of a long device ID.

To make sure I understand your proposal correctly:

Device A and B want to establish a connection, and there is a keyserver K.

  1. A asks K for a short temporary ID (“pin”)
  • K hands out a short ID which maps to A’s full device ID or IP
  • A uploads a container to K which is encrypted with the pre-shared passphrase and contains A’s public key as well as the latest IP and some non-static secret.
  • B sends the short id (“pin”) to K, which hands over the container.
  • B decrypts the container with the passphrase
  • B tries to connect to the supplied IP, encrypting the secret + it’s own ID to A’s public key.
  • A accepts the connection and adds B’s public key if the secret is correct.

This could work, but I can’t see the advantages over the current system:

  • The passphrase would have to be very complex. If it’s not, everybody controlling the network or the key server can brute force it, or attack it with rainbow tables. Once the secret is known, they can MITM the connection, resulting in a long term compromise which is barely noticeable, because all files are correctly synced across devices.
  • If the passphrase is long and complex enough to be secure, we have the same problem which we have right now, but instead of sharing a long and complex ID out of band, we share a long and complex passphrase.
  • Anybody with knowledge of A’s full public key - which is every device A ever connected to as well as the discovery server and everyone doing a TLS handshake on A’s IP - can DOS the connection by using all X allowed tries. B won’t be able to connect anymore, because the secret is not valid anymore. This isn’t really a problem for now, because currently everybody can spoof the discosrv anyways and no data loss occurs.
  • If K can somehow create a container which decrypts to every passphrase/a big subset of possible passphrases, they can make B connect to a malicious node. This is basically the same attack as I’ve described above for @calmh’s proposal. I’m not sure how difficult this would be, but it’s probably not a danger which can be properly assessed without looking at the exact implementation of the code doing the decryption.
1 Like

So here is how it works.

A wants to share something with B, via key/introduction server K.

  1. A generates a 8-10 digit PIN.
  2. A uses first 4 chars as salt, last 4-6 chars as the password. Uses bcrypt with 5 second cost to get a longer hash which could be used as an AES key.
  3. A creates a container, puts something (it’s own device ID + folder name to be shared + nounce + timestamp), encrypts it with an AES key.
  4. A uploads the container to K under the first 4 digits of the pin.
  5. A starts long polling K waiting for answer from B for up to 2 minutes.
  6. A tells B the PIN.
  7. B contacts K, provides the first 4 digits of the PIN, retrieves container.
  8. B adds device ID and folder specified in the container.
  9. B decrypts the container, checks if timestamp is recent, appends it’s own device ID + nounce, re-encrypts the container, uploads to K.
  10. A downloads B’s container, checks timestamps, if all good, add’s B’s device ID and shares the folder initially advertised.

PIN could be a combination of letters and numbers to make it less prone to rainbow table attacks?

This has very limited benefit, apart from changing 64 characters + folder name to something smaller.

So you want to trade in a long passphrase with a long standing (~24h) “invitation” for one which only works a few minutes but is less complex.

But a malicious K can still precompute a huge number of containers where:

  • only several of the 10000 sets of the first 4 digits of the “PIN” are actually computed, because at 4. the discosrv needs to be able to deny short ids which already exist.
  • but for those sets the whole namespace of the latter 4-6 chars is hashed

The attacker can then do the same attack I described above by making B add it. This requires a bit of computation, but the timestamp is worthless, because once the bcrypt calculation has been done, it’s safed in a rainbow table. The containers with different timestamps can then be created very quickly.

PIN could be a combination of letters and numbers to make it less prone to rainbow table attacks?

Unfortunately only passwords with a huge number of possible characters/symbols is secure at 8-10 chars:

So even if we included all ASCII printable symbols except space we’d get only ~66 bits of entropy at 10 chars. And the first four chars are basically void, because the attacker can limit A to use short ids for which he has already precomputed the hashes. That’s ~ 2⁴⁰ possible combinations. And that’s if we use all possible ASCII symbols. For usability reasons the PIN should be limited to either (a-z or A-Z, 0–9) or (a-z, A-Z, 0–9) which give us 2³¹ and 2³⁶ combinations respectively.

If the attacker doesn’t necessarily want to attack a certain user, they can spoof all exchanges happening in the timeframes he created containers for. And encrypting stuff is cheap, once the bcrypt hashes are created.

One more thing: why does B upload an encrypted container instead of using the discosrv to find A’s IP and authenticating itself to A directly?

I can’t see a real problem apart from overhead and lost time with this right now, but it’s another possibility for a nefarious K to do evil stuff.

To behonest I don’t think we should reinvent the wheel here. We are having the problem that we want to initiate a secure (authenticated, encrypted) conversation over an insecure channel. Usually this is solved via a PKI, but we don’t have one and probably don’t want to start one either.

One of the very few protocols accomplishing what we want is ZRTP, even tough it has a few flaws. But those can be mediated:

It’s basically diffie hellman with a little hack. Then both parties create an HMAC over the key exchange and the results from earlier key exchanges. Then a 32 bit hash of this is created, encoded as a short authentication string (aka 2-3 words from a diceware-style wordlist). A and B then communicate those 2-3 words via the (still unauthenticated) voice channel. In our case this can be a phone call or a secure instant messenger/PGP encrypted mail session. If the strings match, there was no MITM.

This uses the same trust on first use (TOFU) security model as SSH. ZRTP can get away with a 32 bit value because the attacker has only one try to get it right. ZRTP also uses input from older sessions and mixes it into the key derivation function. Thus someone would have to mitm every single session, which is very difficult, especially with smartphones using different networks all the time.

It’s obviously vulnerable against a voice imitation algorithm because the words are compared via an unauthenticated channel. And in a time where one can easily overlay one persons emotions over another persons face, I’m sure the same for voice has been collecting dust in some basements for a decade or two. (OMOTE / REAL-TIME FACE TRACKING & PROJECTION MAPPING on Vimeo I have seen some better & scarier examples before, but couldn’t find them right away.) But as this currently requires targeted attacks by a very high skilled & well funded entity, it’s outside of syncthings threat model.

I guess we could probably use a better hash like bcrypt and use more bits if we wanted to, but it’s not an incredibly pressing matter if the attacker has a one in 2^32 chance of success. Instead of starting an encrypted voice chat we would probably just exchange device IDs after both parties confirmed that the SAS match tough, because we don’t want to run a second identity&authentication scheme forever.

This does require writing or at least verifying a ZRTP go library tough, which is a pain. That’s a shitload of very sensitive work tough, so maybe using a well tested C lib would be better here, despite of C’s drawbacks?

On a sidenote I have also found this, which could do exactly what we want and it’s (partly) written in GO. But haven’t really looked into it apart from buzzword checking:

So I know that what I suggested is weak, I guess I should leave crypto to others :wink:

Well, that wasn’t my plan at all :anguished:

The problem I see is that any improvement which minimizes the information exchange to make it easier to do an out-of-band authentication means we’ll have to do proper authentication on an insecure channel. This is a difficult problem in a field with very little trusted and high quality libraries and the number one rule beeing “don’t roll your own”. So we should probably wait for others to solve it while working on other ways to make the setup as easy as possible.

This is the best paper I’ve found during a quick search: “Authentication protocols based on low-bandwidth unspoofable channels: a comparative survey”

This presents several interesting protocols, I suggest reading at least the conclusions on page 37ff. There are even nice tables comparing the number of bits which have to be transferred over the human channel.

But unless one of the core devs is willing to implement one of those and to deal with the fallout if the impementation was weaker than the proposal, we’ll probably have to wait until someone capable needs it more than we do and open-sources it.

So while this is the best solution, because it actually solves the underlying problem, we can at least alleviate the pain caused by the current implementation with little effort. @calmh @AudriusButkevicius @Nutomic: if you want me to open tickets for any of those, just tell me.

  • Nowadays we can ask the browser to hand over control of the webcam to scan the other devices QR code. By now every laptop has a webcam and the desktop market is basically dead, so the amount of users who can profit from this is huge. There is also a FOSS JS lib ready to do all of that: QCodeDecoder. The only GO lib I found is this wrapper, and it’s not really feature rich: GitHub - shezadkhan137/go-qrcode: A light golang wrapper around zbar, used for qr code processing

  • Create a wizard where noobs are led trough the necessary steps to choose/add a device + folder in the right order. It’s automatically shown on first run and then available from the “actions” dropdown. User education is very important. Basically all of the most popular apps with a hunch of UI complexity do this. And for a reason.

  • We can think about linking the “add device” dialog from the “Shared With” and “Share With Devices” sections in the folder overview and the folder settings respectively. The source folder would be checkmarked automatically in the opened “add device” dialog. This deals with the case where a user either accidentally created the folder first, or wants to add a new device, but needs to add it to only one folder. This is making it easier for beginners, because more of the avenues they explore for getting done what they want to achieve actually work.

  • A simple “mail:” link in the “show ID” dialog to enable desktop users to email the device ID. This isn’t very secure by default, but neither are phone calls. And security concious users can use GPG/PGP.

  • The Android app still has room for improvements from a UI perspective:

  • there should be a “share with” icon next to the device ID (your own and others), which opens the “share with” intent. There the user can choose their preferred means of communication.

  • the “click to copy” functionality might be hinted at, because it deviates from the Android default (selectable text can be copied by long click). As the default action (long click) also works, only the case where people don’t even try to click the ID is problematic tough.

  • (Encoding the current IDs diceware-style is pretty straight-forward and gets us down to 20 words people have to communicate. Not great, but better than 56 chars and with less room for errors. One caveat: ideally the users language preference would determine the diceware list used, because unknown words can’t be pronounced. This necessitates a big red warning & dropdown with language choices next to each ID tough. :-/ Not sure if it’s worth it usability wise.)

1 Like

Definitely agree about a first start wizard. If you can make a list of things that should be explained (or even some kind of mockup), I can code it up for Android.

I’m pretty sure we had a share icon in the app, but I guess it got lost at some point. I guess we could add an extra button to copy the device ID.

Please open issues for those suggestions, otherwise we’ll just forget about them :wink:

Edit: Not sure if encoding the device ID as words is worth the trouble. It takes longer to type, and you’ll run into problems with typos and different languages.

Definitely agree about a first start wizard. If you can make a list of things that should be explained (or even some kind of mockup), I can code it up for Android.

Awesome, will do mockups when I get the time! I think some explanation of the interface based on arrows and circles, where people only have to follow some very simple instructions to add a device, create a folder and share it with the device which was just added (or others). The text should describe that syncthing uses devices to make sure your data only goes where it should, so they’ll have to be added first. Maybe I’ll create a video of the workflow-wizard I imagine.

I’m pretty sure we had a share icon in the app, but I guess it got lost at some point. I guess we could add an extra button to copy the device ID.

Bisschen Schwund ist immer :smiley:

Please open issues for those suggestions, otherwise we’ll just forget about them :wink:

Only the android ones, or all of them?

Edit: Not sure if encoding the device ID as words is worth the trouble. It takes longer to type, and you’ll run into problems with typos and different languages.

Yeah after thinking about it, the language specific stuff is probably too much clutter UI-wise. But when using one of the SAS schemes from the paper I linked earlier, that’s not a problem, because there is only one place to make language-aware and it doesn’t touch the IDs at all.