Here's what I just deployed:
HMAC secret is now derived from your password hash (sha512) and a "device salt", using PBKDF2 with 1024 iterations. The salt is generated randomly on the device, and stored on the server. As of right now, the salt is only generated and stored once. I'll revisit regenerating that salt in the future, trying to avoid the back-and-forth right now.
I do like the idea of generating the salt on the server and sending it in the PublicKeyMessage, however, that means we would have to send the sha512 hash of the password up to the server so it can derive the HMAC key. We are trying to avoid ever sending the unsalted hashed password, which is why the salt is generated on the device and sent to the browser.
I'll see about adding HMAC with the AES encrypted message exchange, should be dead simple. I'm not sure we need separate keys for each direction, as we are using AES CBC and generating a random initialization vector for each message, which I understand helps prevent replay attacks. These sessions are very short lived anyway, though I do have a TODO to expire the AES keys on the device, so that is moot until that is done.
Agreed that it would be a good move to generate some random bytes on the server and client (web/android) and use a combination of both.
- The OAuth token is exactly that. It is an OAuth token. It is saved on the server, and they expire after 1h. I meant to change this to 15m, but it seems I totally forgot to do that. I'll deploy a change here in a few minutes. If you get ahold of my OAuth token, you can impersonate me when making API requests, so an hour is a bit too long. The access token is a hex UUID4.
- The server matches password hash with the hash that is stored on the server, correct. The hash that we store is salted a server salt, as well as a per-user salt before it is stored. Note that we never send your plaintext password, so we are just salting the hash that is sent to us.
- RE: session keys in the DB. I'm not an Android framework/app expert by any means, but my understanding is that an Android process can go away at any time. Storing the key in memory is risky, as the process may not actually be running after the key exchange is done, and before the "begin_locate" message comes in, causing the key to disappear.
- GCM is something that I would like to get rid of eventually. We shouldn't need to rely on Google for this, however, for right now this is the best solution without engineering something completely new from the ground up. GCM requires an API key to send messages. A third party could send messages to our devices if they have our API key the registration ID for a device.
Thanks for your input, really appreciate it. I'm bad at G+, so if you want to take this discussion offline, please feel free to email me at email@example.com.