Services/KeyExchange

From MozillaWiki
< Services
Revision as of 21:07, 12 October 2010 by Rnewman (talk | contribs) (Fleshing out notes.)
Jump to navigation Jump to search

Overview

Explore using J-PAKE to securely pass credentials to another device.

Tracking bug is bug 601644.

Engineers Involved

  • Tarek (server)
  • Philipp (FxSync)
  • Stefan (FxHome)

User Requirements

  • Setting up a new mobile device should only involve entering a short code on the desktop device
  • Secondary request, not a hard requirement, is that if the user has a mobile device, and is setting up a desktop device, that the flow is similar and still involves entering the key on the desktop

Desired User Flow

  1. User chooses "quick setup" on new device
  2. Device displays a setup key that contains both the initial secret and a channel ID
  3. On a device that is authenticated, user chooses "add another device" and is prompted for that key
  4. The two devices exchange messages to build the secure tunnel
  5. The already-authenticated device passes all credentials (username/password/passphrase) to the new device
  6. New device completes setup and starts syncing

Implementation (draft)

Terminology

  • Desktop: Client that has Fx Sync already set up
  • Mobile: Client that needs to be set up (of course this could be another desktop computer, too)
  • PIN: code that is displayed on Mobile and entered on Desktop
  • Secret: weak secret that is used to start the J-PAKE algorithm
  • Key: strong secret that both clients derive through J-PAKE

Overview

  • Mobile and Desktop complete the two roundtrips of JPAKE messages to agree upon a secret key.
  • The secret key is the sha256 hash of the K number, as returned by python-jpake.
  • In third round trip, Mobile hashes the key using SHA256d (=hash twice with SHA256) and uploads it. Desktop verifies it against its key and uploads the encrypted credentials in turn, adding a SHA256-HMAC hash of the cleartext. Mobile verifies whether Desktop had the right key by checking the decrypted cleartext against the SHA256-HMAC hash.


Mobile                        Server                       Desktop
==================================================================
                                 |
retrieve channel <---------------|
generate random secret           |
show PIN = secret + channel      |                ask user for PIN
upload Mobile's message 1 ------>|
                                 |---> retrieve Mobile's message 1
                                 |<---- upload Desktop's message 1
retrieve Desktop's message 1 <---|
upload Mobile's message 2 ------>|
                                 |---> retrieve Mobile's message 2
                                 |                     compute key
                                 |<---- upload Desktop's message 2
retrieve Desktop's message 2 <---|
compute key                      |
upload sha256d(key) ------------>|
                                 |---------> retrieve sha256d(key)
                                 |          verify against own key
                                 |             encrypt credentials
                                 |<------------ upload credentials
retrieve credentials <-----------|
decrypt credentials              |
verify HMAC                      |

Data format

All request and response bodies are JSON objects as produced by python-jpake (messages 1 and 2) and specified below. An application/json HTTP Content-Type header is optional. Within the JSON objects,

  • the big numbers are encoded as hex strings (messages 1 and 2),
  • the hash in message 3 is hex encoded,
  • the ciphertext, IV and hmac are encoded in Base64 (messages 3)

Server API

The only valid HTTP response codes are 200 and 304 since those are part of the protocol and expected to happen. Anything else, like 404 or 503 must result in a complete termination of the password exchange. The client can retry the exchange then at a later time, starting all over with clean state.

The server API knows three calls:

GET https://server/new_channel

 Returns in the response body a random channel id encoded in JSON composed 
 of 4 chars from  [a-z0-9]. When the API is called, The id returned is 
 guaranteed to be unique. The channel created will have a ttl of 10 minutes.
 
 Return codes:
    - 200: channel created successfully  
    - 503: the server was unable to create a new channel.


GET https://server/channel_id

 Returns in the response body the content of the channel of id channel_id. 
 Returns an ETag response header containing a unique hash.
 
 The request can contain a If-None-Match header containing a hash,
 If the hash is similar to the current hash of the channel, the server 
 will return a 304 and an empty body.
   
 Return codes:
    - 200: data retrieved successfully  
    - 404: the channel does not exists. It was not created by a call 
           to new_channel or timed out.
    - 304: the data was not changed.


PUT https://server/channel_id

 Put in the channel of id channel_id the content of the request body. 
 Returns an ETag response header containing a unique hash.
    
 Return codes:
    - 200: data set successfully  
    - 404: the channel does not exists. It was not created by a call 
           to new_channel or timed out.


DELETE https://server/channel_id

 Delete the channel of id channel_id. 
   
 Return codes:
    - 200: channel deleted successfully  
    - 503: the server was unable to set the content
    - 404: the channel does not exists. It was not created by a call 
           to new_channel or timed out.

Detailed Flow

  1. Mobile asks server for new channel ID (3 characters a-z0-9)
    C: GET /new_channel HTTP/1.1
    S: "a7id"
  2. Mobile generates PIN from random weak secret (4 characters a-z0-9) and the channel ID, computes and uploads J-PAKE msg 1
    C: PUT /a7id HTTP/1.1
    C: 
    C: {
    C:    'type': 'receiver1',
    C:    'payload': {
    C:       'gx1': '45...9b',
    C:       'zkp_x1': {
    C:          'b': '09e22607ead737150b1a6e528d0c589cb6faa54a',
    C:          'gr': '58...7a'
    C:          'id': 'receiver',
    C:       }
    C:       'gx2': 'be...93',
    C:       'zkp_x2': {
    C:          'b': '222069aabbc777dc988abcc56547cd944f056b4c',
    C:          'gr': '5c...23'
    C:          'id': 'receiver',
    C:       }
    C:    }
    C: }
    
    S: HTTP/1.1 200 OK
    S: ETag: "444b424cbc84805b40bcd35c8ebe4524"
    
  3. Desktop asks user for the PIN, extracts channel ID and weak secret, fetches Mobile's msg 1
    C: GET /a7id HTTP/1.1
    
    S: HTTP/1.1 200 OK
    ...
    
  4. Desktop computes and uploads msg 1
    C: PUT /a7id HTTP/1.1
    C: 
    C: {
    C:    'type': 'sender1',
    C:    'payload': {
    C:       'gx1': '45...9b',
    C:       'zkp_x1': {
    C:          'b': '09e22607ead737150b1a6e528d0c589cb6faa54a',
    C:          'gr': '58...7a'
    C:          'id': 'sender',
    C:       }
    C:       'gx2': 'be...93',
    C:       'zkp_x2': {
    C:          'b': '222069aabbc777dc988abcc56547cd944f056b4c',
    C:          'gr': '5c...23'
    C:          'id': 'sender',
    C:       }
    C:    }
    C: }
    
    S: HTTP/1.1 200 OK
    S: Etag: "209a424cbc8480465abcd35c8ebe4524"
    
  5. Mobile polls for Desktop's msg 1
    C: GET /a7id HTTP/1.1
    C: If-None-Match: "444b424cbc84805b40bcd35c8ebe4524"
    
    S: HTTP/1.1 304 Not Modified
    

    Mobile tries again after 1s

    C: GET /a7id HTTP/1.1
    C: If-None-Match: "444b424cbc84805b40bcd35c8ebe4524"
    
    S: HTTP/1.1 200 OK
    ...
    

    Mobile computes and uploads msg 2

    C: PUT /a7id HTTP/1.1
    C: 
    C: {
    C:    'type': 'receiver2',
    C:    'payload': {
    C:       'A': '87...82',
    C:       'zkp_A': {
    C:          'b': '6f...08',
    C:          'id': 'receiver',
    C:          'gr': 'f8...49'
    C:       }
    C:    }
    C: }
    
    S: HTTP/1.1 200 OK
    S: ETag: "111a424cbc8480465abcd35c8ebe4524"
    
  6. Desktop polls for and eventually retrieves Mobile's msg 2
    C: GET /a7id HTTP/1.1
    C: If-None-Match: "209a424cbc8480465abcd35c8ebe4524"
    
    S: HTTP/1.1 200 OK
    ...
    

    Desktop computes key, computes and uploads msg 2

    C: PUT /a7id HTTP/1.1
    C: 
    C: {
    C:    'type': 'sender2',
    C:    'payload': {
    C:       'A': '87...82',
    C:       'zkp_A': {
    C:          'b': '6f...08',
    C:          'id': 'sender',
    C:          'gr': 'f8...49'
    C:       }
    C:    }
    C: }
    
  7. Mobile retrieves Desktop's msg 2
    C: GET /a7id HTTP/1.1
    C: 
    
    S: HTTP/1.1 200 OK
    ...
    

    Mobile computes key, uploads hash of key to prove its knowledge (msg 3)

    C: PUT /a7id HTTP/1.1
    C: 
    C: {
    C:    'type': 'receiver3',
    C:    'payload': {
    C:       'hash': "aa...ff"
    C:    }
    C: }
    
  8. Desktop retrieves Mobile's msg 3 (hashed key)
    C: GET /a7id HTTP/1.1
    C: 
    
    S: HTTP/1.1 200 OK
    ...
    

    verifies it against its own version. If the hash matches, it encrypts and uploads Sync credentials.

    C: PUT /a7id HTTP/1.1
    C: 
    C: {
    C:    'type': 'sender3',
    C:    'payload': {
    C:       'ciphertext': "base64encoded=",
    C:       'IV': "base64encoded=",
    C:       'hmac': "base64encoded=",
    C:    }
    C: }
    

    If the hash does not match, the Desktop deletes the session.

    C: DELETE /a7id HTTP/1.1
    
    S: HTTP/1.1 200 OK
    ... 
    

    This means that Mobile will receive a 404 when it tries to retrieve the encrypted credentials.

  9. Mobile retrieves encrypted credentials
    C: GET /a7id HTTP/1.1
    C: If-None-Match: "111a424cbc8480465abcd35c8ebe4524"
    
    S: HTTP/1.1 200 OK
    ... 
    

    decrypts Sync credentials and verifies HMAC.

  10. Mobile deletes the session [OPTIONAL]
    C: DELETE /a7id HTTP/1.1
    
    S: HTTP/1.1 200 OK
    ... 
    

Security Considerations

Discuss potential design and implementation threats & mitigations here.

Brian's Notes

  • J-PAKE paper appears to have limited peer review. It was a workshop paper and it appears to only recently have been sent to a peer-reviewed journal. I could not find any citations of the paper except in papers by the author.
  • We would be the first and only known production deployment of J-PAKE (AFAICT).
  • 3 character channel ID means that there can be a maximum of 46,646 active channels.
  • Very easy to DoS. How do we stop DoS?
  • How long do channels live? Long enough to start the process at work, then drive home and complete the process on my home computer means at least 2 hours? If we allow users a day or half a day to travel to their other computer, then we're looking at a limit of about 50K-100K transactions per day, worst case, assuming no DoS. Most likely channels will live just a minute or two.
  • Length of PIN determines resistance to online attacks by the server (Theorem 5 in the J-PAKE paper).
  • 3 character PIN => 1/46,646 chance of server guessing password correctly per sync attempt.
  • Attackers cannot hide attack from the user, but users are likely to retry many times. Is it possible to reliably detect an attack vs. user error, server failure, or network error?
  • If we assume the user is willing to retry 10 times, there is a 1/4,664 chance of a successful online attack by the server.
  • What is an acceptable rate of successful online attack?
  • Do we need mutual authentication? It seems one-way authentication and/or key transport ala PKCS#12 would suffice.
  • It isn't obvious to me what modulus/order is appropriate. The paper used p=1024 and q=160 in a sample implementation, but that wasn't even a recommendation.
  • A full 128-bit AES key can be entered in 25 characters (base 36). Using PBKDF2 or similar, we can (probably) safely reduce that to ~23.
  • Key transport (ala PKCS#12) has equal complexity for online and offline attacks.
  • Increasing the channel ID length and/or the password length reduces the usability benefit of J-PAKE. How much more usable is a 12 or 16 character password vs a 23 character password?
  • J-PAKE server legal juristiction? Separate server from data?
  • J-PAKE server doesn't need to know / should not know the identity (email/username) of the user?
  • Stefan Arentz wrote: "For example, I was just reading a discussion about J-PAKE and found out that there is a possible weakness in the password hashing that we currently use. (Where Hash(password) % q might be 0). See discussion in http://www.lightbluetouchpaper.org/2008/05/29/j-pake/

Meeting Notes

  1. Easy setup (substantially easier than now) is a blocker for Fennec 4 since Sync will be marketed as **the** feature for Firefox Mobile. We need a solution for Firefox + Fennec 4.
  2. J-PAKE algorithm as proposed here allows exchange by only requiring typing of relatively short PIN on device that's already set up (though a trivial change could allow the typing to always be on the desktop machine, no matter whether it's the receiving or sending end).
  3. Did we look at alternatives to J-PAKE?
    1. QR codes: necessary platform work not possible on all platforms in the given time frame
    2. Bonjour/Zeroconf: same as above
  4. Concerns
    1. Confidence in J-PAKE: paper submitted to journal for official publication only recently, no peer review yet.
    2. Short PIN as proposed by UX makes channel hijacking, guessing easier
      1. Additionally, large quantities of channels to support user volume will either significantly lengthen this string, or reduce PIN space and strength
    3. Firefox 4 timeframe short for implementation + crypto review
    4. DoS
    5. Changes to marketing messages necessary, are we willing to qualify our statements about Sync security + privacy?
  5. Proposals to prevent simple attacks
    1. Connections to the PAKE server should be over SSL, eliminates man-in-the-middle attacks.
    2. Channel exhaustion from DoS: need effective IP blocker
    3. Only allow client that requests channel + the next client that connects to it to use the channel (limits eavesdropping/manipulation attacks)
    4. Only allow a limited number of attempts to use transfer via J-PAKE, fall back to traditional account setup.
    5. Client flags channel deletes that happen because of an abort.
  6. Potential attacks (after above measures)
    1. Compromised server does an online attack
    2. Hijack channel before user enters the PIN. Need to guess whole PIN (channel + secret) to do harm.
  7. Alternative suggestions
    1. Various word or sentenced based methods, all of which are pretty much impossible to localize.
      1. Maybe: could localize the PGP bio word list (http://en.wikipedia.org/wiki/PGP_word_list)
    2. Have the mobile display a ~20 a-z character key (~100 bits of entropy) which user enters on the desktop. This 20 char key is used to make a 128 bit AES key, the hash of the key is the channel ID on the server. Mobile encrypts data, uploads to channel, desktop downloads and decrypts. UX is worse (but still better because you enter ~20 chars on desktop rather than email + password + Sync Key on mobile), security is better.
      1. Arguable that users are already familiar with entering separated alphanumeric sequences: WEP keys, registration keys, license codes, phone numbers, ZIP codes, credit card numbers...