desktopclient-java icon indicating copy to clipboard operation
desktopclient-java copied to clipboard

Private key transfer - Desktop client as receiver

Open shirishag75 opened this issue 9 years ago • 35 comments

Hi all, As per readme, "The Android client version 3.0 is required to export your account-key which is needed by the desktop client " now it would be nice if this could be done by the desktop client itself.

shirishag75 avatar Aug 09 '15 17:08 shirishag75

I'm still unsure about this. Kontalk is a mobile messenger network, the desktop client is (or was) only intended as an addition. The account creation could be integrated (with still a mobile phone number needed for verification) but this will be a lot of work.

Maybe its better to put some effort into improving the key transfer (strong encrypted over the server)?

abika avatar Aug 24 '15 17:08 abika

I was thinking about transferring the key someway between devices, but the problem is you'll need to authenticate first - which is not possible because you don't have the key yet. Besides, sending a private key through network is always a bad idea, despite of any security measure you might take.

In this specific case, we'll need server assistance, in either two way:

  • let the server store an encrypted copy of the private key (I'd rather not do that for obvious reasons)
  • make the server arrange a p2p connection between an already registered device and the new device you're trying to pair and let them exchange the key through a secure channel (I guess plain SSL would be safe enough, I have to evalutate some other options - we might have some difficulties such as NAT traversal, but I think they can be worked around)

What do you think?

daniele-athome avatar Aug 25 '15 07:08 daniele-athome

I get your concerns but if we use a strong symmetric encryption with fixed password length (<=26 chars) shouldn't it be safe? It would be much easier to implement than a p2p approach.

we might have some difficulties such as NAT traversal, but I think they can be worked around)

I have not much experience with p2p communication but can remember that applications like Skype had big trouble to find a reliable way for connecting through all kinds of networks. A lot of work was put into this.

abika avatar Aug 26 '15 15:08 abika

You're right, it will probably be a pain... Let's go through the encrypted exchange then. Shall we open an encrypted session?

Just kidding :-) Ok seriously now: once the password has been determined, do we use an encrypted <message/> to exchange that?

daniele-athome avatar Aug 26 '15 15:08 daniele-athome

Eh, what exactly is your general idea? The desktop client establishes a temporary XMPP connection, and the Android client sends the key?

abika avatar Aug 26 '15 16:08 abika

I have some thoughts about that.

Android part:

  • app uploads the encrypted key
  • server replies with a very long identifier (we'll call it a registration token)

Desktop part:

  • app connects to the same server the Android app is connected to (we'll have to make it clear in the Android app: "choose THIS server in the desktop app")
  • without authenticating, it sends a special <iq/> (extension to in-band registration I guess) with the registration token which was manually typed in by the user from the phone screen
  • server replies with the encrypted key which can be used to login

For the key encryption part: we could let the user choose a password, recommending him/her to make it very strong.

What do you think? It might work.

daniele-athome avatar Aug 26 '15 18:08 daniele-athome

Now that I think about it, this protocol could also be used for Android-to-Android account pairing (that is, multiple devices with the same key).

daniele-athome avatar Aug 26 '15 18:08 daniele-athome

[uhh I almost forgot about this thread again]

In general it sounds good. One improvement idea: The Android app should generate a secure password for the user (26chars, lower letters +digits), otherwise its too insecure IMO. And now: create the registration token as the sha1 hash of the password. By doing that the user has only to type in the password in the desktop app.

It sounds like introducing a weak spot in security, but its not. There is no real difference if an attacker has the password hash in addition to the encrypted key file.

abika avatar Sep 01 '15 17:09 abika

@abika the problem with this approach is that the token is client generated. That is not acceptable sorry, the token has to be generated by the server, it's too important (remember: anything that is provided by clients can and will be exploited). We could however "compose" a long token made up of the server token and the client password and show that long string to the user. Of course it will be boring to type in manually on the other side. Unless the other device has a camera, in that case a QR code can be used. Most notebooks and tablets have one, so it will cover the majority of users. The rest will have to type in the string manually. Any other ideas?

daniele-athome avatar Sep 02 '15 08:09 daniele-athome

Hi all, Have people seen yowsup. Yowsup-cli does a similar thing for whatsapp. You register, have to share your phone number credentials, the service sends a string to your mobile no. via a SMS and then you can put in the service to verify that's it you and you're in .

I do see the issue there that just like the web, the SMS service is also public and theoretically a MIM (man-in-middle) attack is possible but there doesn't seem to any other secure way to do it.

shirishag75 avatar Sep 02 '15 09:09 shirishag75

@shirishag75 WhatsApp has no encryption key to exchange between devices. Everything is in cleartext.

daniele-athome avatar Sep 02 '15 09:09 daniele-athome

the problem with this approach is that the token is client generated. That is not acceptable sorry, the token has to be generated by the server, it's too important (remember: anything that is provided by clients can and will be exploited).

Guess you're right, but what exactly is the problem here? The server can check the token format and make sure it wasn't used before. How can a client exploit choosing this string?

Unless the other device has a camera, in that case a QR code can be used. Most notebooks and tablets have one, so it will cover the majority of users.

I can at least say for myself: I'm using a laptop exclusively and never used the camera in the last 10 years, don't even know if it works. Besides that: implementing camera+qr-code scan will be a pain in pure Java (in contrast to Android. Do you know one desktop application that can scan qr codes?).

But all in all: security has priority!

[ Offtopic:

WhatsApp has no encryption key to exchange between devices. Everything is in cleartext.

That's not exactly true. WhatsApp has some kind of encryption and even Axolotls e2e encryption for Android-to-Android communication. But it's closed source, nobody knows exactly. And anyway, no key transfer here. ]

abika avatar Sep 02 '15 13:09 abika

[I was replying by editing your comment. Again. Fortunately I realized that just before pressing the save button]

Guess you're right, but what exactly is the problem here? The server can check the token format and make sure it wasn't used before. How can a client exploit choosing this string?

Maybe not clients directly, but the server will have access to a hashed version of the passphrase. I don't like it. Private key related content should never go through a server (the fact that a private key, even if encrypted, goes through a server, is already dangerous per se - the passphrase is the only thing keeping it somewhat "protected", even if it's hashed).

We could, however, use some encoding (something like Base64, but more user-friendly) to merge into a single string both the server generated ID and the passphrase. The client on the other side will know how to split and use it. However, this could let the user think that the key was not encrypted because he/she didn't have to type in the passphrase again. What do you think?

I can at least say for myself: I'm using a laptop exclusively and never used the camera in the last 10 years, don't even know if it works. Besides that: implementing camera+qr-code scan will be a pain in pure Java (in contrast to Android. Do you know one desktop application that can scan qr codes?).

That is not a priority of course. I could introduce QR code scanning on Android first and take care of the desktop app later (or never :-). As a start, you could use a library to at least generate a QR from your desktop app (e.g. you want to pair a phone/tablet with your desktop account), showing the characters too in the same screen.

daniele-athome avatar Sep 25 '15 09:09 daniele-athome

Maybe not clients directly, but the server will have access to a hashed version of the passphrase. I don't like it. Private key related content should never go through a server (the fact that a private key, even if encrypted, goes through a server, is already dangerous per se - the passphrase is the only thing keeping it somewhat "protected", even if it's hashed).

That's true, the security depends on the hash function used. If you don't want that, then we don't do that.

We could, however, use some encoding (something like Base64, but more user-friendly) to merge into a single string both the server generated ID and the passphrase. The client on the other side will know how to split and use it. However, this could let the user think that the key was not encrypted because he/she didn't have to type in the passphrase again. What do you think?

My experience is that my don't care about that. But the Android app should generate a secure passphrase, anyway. Token & passhrase should be around 160bits, so no matter how encoded (e.g. both a 30 digit string, lower alphabetic characters + numbers for easy typing) it will be looong.

That is not a priority of course. I could introduce QR code scanning on Android first and take care of the desktop app later (or never :-). As a start, you could use a library to at least generate a QR from your desktop app (e.g. you want to pair a phone/tablet with your desktop account), showing the characters too in the same screen.

Well, in the future I can generate QR code in the desktop app, but that doesn't help here for the transfer from phone to pc.

abika avatar Sep 25 '15 17:09 abika

My experience is that my don't care about that. But the Android app should generate a secure passphrase, anyway. Token & passhrase should be around 160bits, so no matter how encoded (e.g. both a 30 digit string, lower alphabetic characters + numbers for easy typing) it will be looong.

Let's say the token is a SHA-1 hash, so 160 bits exactly, 40 hex digits. Reducing it to a 32-based number (we could use letters from G to V to put one more bit in), we'd go down to 32 digits (I'm just throwing ideas here). The passphrase, however, is pure ASCII so no easy way to encode it without introducing more characters (that I can think of).

Good security is indeed a pain...

daniele-athome avatar Sep 26 '15 09:09 daniele-athome

back to the beginning: have you thought about the protocol for uploading the key data? A very simple data upload is enough, but I haven't found a suitable XEP.

So, all that is needed: Client sends key...

<iq type="set" id="123">
  <query xmlns="http://kontalk.org/extensions/message#key_share">
    <key>lQP...Nw==</key>
  </query>
</iq>

...and server replies...

<iq type="result" id="123">
   <query xmlns="http://kontalk.org/extensions/message#key_share">
    <token>f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b</token>
  </query>
</iq>

I could try implementing this, but have to start with understanding the Tigase server first.

abika avatar Nov 05 '15 17:11 abika

I was thinking of using the jabber:iq:register namespace. It supports custom forms (we can use a new form field to include the private key) and the Tigase module I wrote handles pretty much everything related to personal key management: registration, key rollover, etc. We can put it there. I can work on the server part - I just need to release 3.1.1 first.

<iq id="80zgA-25" from="prime.kontalk.net" type="set">
  <query xmlns="jabber:iq:register">
    <x xmlns="jabber:x:data" type="form">
      <field var="FORM_TYPE" type="hidden">
        <value>http://kontalk.org/protocol/register#privatekey</value>
      </field>
      <field label="Private key" var="privatekey" type="text-single">
        <value>[Base64-encoded very-much-encrypted private key]</value>
      </field>
    </x>
  </query>
</iq>

Response:

<iq id="80zgA-26" from="prime.kontalk.net" type="result">
  <query xmlns="jabber:iq:register">
    <x xmlns="jabber:x:data" type="form">
      <field var="FORM_TYPE" type="hidden">
        <value>http://kontalk.org/protocol/register#privatekey</value>
      </field>
      <field label="Private key identification token" var="token" type="text-single">
        <value>[key identification token]</value>
      </field>
    </x>
  </query>
</iq>

You can see some Java form creation code here: https://github.com/kontalk/androidclient/blob/master/app/src/main/java/org/kontalk/client/NumberValidator.java

Methods createRegistrationForm() and createValidationForm().

Some security notes:

  • Because the private key is encrypted, it won't be possible for the server to check if the private key is linked to the public key being used by the client. We'll accept that blindly I guess (actually we'll accept any data the client is giving us at this point)
  • Let's be wise when choosing the encryption method. Honestly I didn't make much research on that yet, what about you? I'm guessing some sort of key derivation would be safe among other things.

daniele-athome avatar Nov 07 '15 12:11 daniele-athome

wow, great!

Setting up a server and testing with it would be a pain, so I'm glad you can help here. Instead I will implement uploading/downloading for both clients. I also found the RegisterKeyPairListener is doing something very similar, so will use this as a reference.

  • Because the private key is encrypted, it won't be possible for the server to check if the private key is linked to the public key being used by the client. We'll accept that blindly I guess (actually we'll accept any data the client is giving us at this point)

That's true. The sending client could upload a different private key to the server. But is there an attack scenario here?

  • Let's be wise when choosing the encryption method. Honestly I didn't make much research on that yet, what about you? I'm guessing some sort of key derivation would be safe among other things.

eh, were using AES256 for private key encryption right now. Don't you think that's fine? (The password needs to be 160bit, though. But we already discussed that)

abika avatar Nov 10 '15 19:11 abika

Sorry if I'm delaying this, I'm working to release 3.1.2 with some stuff to not appear dead as a project :-) Just a simple notification reconnecting to kontalk/androidclient#505. I'm including trusted keys information into the archive (in a simple properties file with JID=fingerprint records), we might want to consider adding this information also to the private key exchange protocol discussed here. However, I suggest using a different protocol for trusted keys information because that way it can be synchronized among clients easily (trusted keys can change it time, personal key will change much less often - hopefully). I've opened kontalk/androidclient#628 for that (I've assigned low priority for the moment, but it will change).

daniele-athome avatar Jan 16 '16 13:01 daniele-athome

Oh, the idea with trusted key sharing is new to me, but I just found XEP 0049. Wouldn't that fit here?

And yes, I guess the personal key transfer would need another mechanism.

abika avatar Jan 16 '16 16:01 abika

No, trusted keys information is a client-side thing. XEP-0049 stores information on the server. The mechanism I'm talking about is just to exchange that information between clients.

daniele-athome avatar Jan 16 '16 16:01 daniele-athome

But if the upload content is encrypted (with public key+signing)? Even for client-to-client transfer the content should be encrypted. And once implemented it could be uses for anything (it would be basically a small, secured cloud space).

abika avatar Jan 16 '16 16:01 abika

We could use XEP-0049 but retrieval should be done once and the content be deleted afterwards, for both security and resource reasons. However, no random unique ID would be needed: private XML data is just one and only, no need to know a shared secret (even if it's encrypted). Or I am being too paranoid here?

daniele-athome avatar Jan 16 '16 16:01 daniele-athome

The server does only allow access for the same account. And plus: the clients would use their personal keys for the de- and encryption. So it has the same security as sending a message to one-self: very strong and no need for a secret ID

abika avatar Jan 16 '16 17:01 abika

Of course, because trusted keys information can be accessed after login. I'll have to trick the XEP-0049 Tigase implementation (if there is one) to delete the data on first access. For real-time updates I think we can link this to message synchronization? Or think about it another time anyway. We are already doing a lot of stuff at the same time, I don't want us to mess up :-) Let's focus on this specific issue first.

daniele-athome avatar Jan 16 '16 17:01 daniele-athome

Ok back to this once more (hopefully for the last time because I've started implementation). I'm going on with your commits (thanks by the way, all was quite good, despite some of my initial comments) and implementing the UI parts and at the same time implementing the server-side part. For now I'm using the infamous N-digits random string, but it's weird and hard to type. Very hard to type. Very boring. Very everything :-)

So I started doing some search in CAPTCHA strings generation: CAPTCHA challenges must be random in a certain degree (not word CAPTCHAs, I'm talking about random alphanumeric CAPTCHAs), but also easy and quick to type. I stumbled upon this [1] page which defines a simple yet very effective algorithm to generate random strings which are "easy to type". Maybe it's not the best way to do this, but it's something I think it's worth looking into (in fact, I'm still researching). What do you think?

[1] http://cully.biz/2013/01/29/the-tale-of-two-random-string-functions/

daniele-athome avatar Jan 26 '16 21:01 daniele-athome

Little sidenote: since I'm following a few things at a time, I might have got lost on some things, but I read our previous comments, if I got it correctly, private key password is decided by the app (random) and the token is given by the server (still random). I've said that previously I think, we could use something like a Base64-encoded concatenated string of passphrase+token which the app could parse (in that case, the CAPTCHA thing is out of question).

daniele-athome avatar Jan 26 '16 21:01 daniele-athome

Oh my... if we use 160 bits each (token and passphrase), in Base64 it's going to be 56 bytes!

I am now sleeping over it :-) tomorrow is another day, fresh mind.

daniele-athome avatar Jan 26 '16 21:01 daniele-athome

This discussion is getting confusing, I try to summarize what we have now (about the key transfer):

  • usage of the jabber:iq:register protocol
  • private key will be encrypted before upload with a client generated passphrase: entropy >= 160bits; this corresponds to a string with 31 chars when using (case-insensitive) alphanumeric characters (see a nice overview on wikipedia)
  • download secured with server generated token with same entropy, so again 31 chars

-> user has to enter 62 chars in the receiving client, that's the price for security.

I don't think "easy-to-type" strings will help here. They need to be longer to contain the same amount of entropy and are harder to generate (or need some extra library). Same for captchas if I understand you correctly.

[Please don't loose sight of group chat. This is the one thing my friends constantly asking me about:) - everything else is "only" nice-to-have]

abika avatar Jan 27 '16 16:01 abika

I agree completely with @abika. Groupchat is currently the most importent thing to catch users.

BTW, what about the developer who offered his help in Google devel group?

webratte avatar Jan 27 '16 16:01 webratte