kontalk / desktopclient-java

Kontalk official platform independent desktop client
https://www.kontalk.org
GNU General Public License v3.0
58 stars 24 forks source link

Private key transfer - Desktop client as receiver #51

Open shirishag75 opened 9 years ago

shirishag75 commented 9 years ago

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.

abika commented 9 years ago

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)?

daniele-athome commented 9 years ago

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:

What do you think?

abika commented 9 years ago

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.

daniele-athome commented 9 years ago

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?

abika commented 9 years ago

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

daniele-athome commented 9 years ago

I have some thoughts about that.

Android part:

Desktop part:

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 commented 9 years ago

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).

abika commented 9 years ago

[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.

daniele-athome commented 9 years ago

@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?

shirishag75 commented 9 years ago

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.

daniele-athome commented 9 years ago

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

abika commented 9 years ago

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. ]

daniele-athome commented 8 years ago

[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.

abika commented 8 years ago

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.

daniele-athome commented 8 years ago

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...

abika commented 8 years ago

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.

daniele-athome commented 8 years ago

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:

abika commented 8 years ago

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)

daniele-athome commented 8 years ago

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).

abika commented 8 years ago

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.

daniele-athome commented 8 years ago

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.

abika commented 8 years ago

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).

daniele-athome commented 8 years ago

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?

abika commented 8 years ago

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

daniele-athome commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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.

abika commented 8 years ago

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

-> 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]

webratte commented 8 years ago

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?

sergeevabc commented 7 years ago

Err… Hello?

daniele-athome commented 7 years ago

@sergeevabc other issues are being given higher priority and this one "got shifted" a bit, sorry.

abika commented 7 years ago

I'm afraid I don't have as much time as in the past anymore. I won't abandon this project but it will definitely take a long time for new features. Also, I'm unsure how many people actually use the desktop client and don't want to waste time on something nobody uses.

And in this case it also depends on the Android part of uploading the key. @daniele-athome it's your decision again if you want to work on it or think other stuff is more important.

webratte commented 7 years ago

I'm not @daniele-athome ;-) But I think to make the desktop client more interesting to use would be to integrate "share history among clients": https://github.com/kontalk/desktopclient-java/issues/21

BTW. I use the desktop client very often 👍

abika commented 6 years ago

[Moved the request to register with the desktop client to #103]