This is a sort of design review question that I'm hoping is suitable for this site.
I am designing a system that uses a cloud service to establish a secure connection between a PC and a mobile device. Security matters hugely, but so does ease of set up. The current idea is to set the entire account up on the PC completely automatically by creating a long random access key and caching it in encrypted storage on the PC, without ever asking the user to pick a password. Then asking the user to launch the mobile app and essentially have the PC generate a QR code that provides all the information needed for the mobile device to connect and authenticate against the cloud service.
The authentication mechanism is a simple user ID + access key, where the key is hashed on the cloud service using a standard HMAC, etc.
Where it gets unique is that I want the PC to generate the access key and somehow hand over the username and access key to the mobile device using the QR code, without users having to do anything on the mobile device, and without them having to memorize another password. I like this approach cause it guarantees long, random, secure access keys. No guessable passwords, and everything on the cloud service will be hashed, salted passwords that originated from random, 32-character keys.
So obviously we don’t want the credentials in the QR code in case someone just snaps a photo of it or something, so we need the QR code to be single use but still be able to provide the access credentials.
Here’s the current design I’ve developed:
PC generates login credentials: account ID (in my case the user’s email address, which I already have) and that randomly created access key. PC calls cloud service with those credentials to create an account. Account ID is stored in database, access key is hashed, salted, and stored in database as we typically do.
In the cloud service, we setup another database table (or even an in-memory dictionary), for temporary storage of the credentials (for one time use). We take the account key and encrypt it using AES-256 using a randomly generated key, and store that in that table. We send the PC the encryption key.
Then the PC generates a QR code that contains the account ID and the encryption key used to encrypt the account access key on the cloud service. The mobile app scans that and sends a request with those items to the cloud service. The cloud service looks up the entry using the account ID and then decrypts the password using the provided encryption key, thereby retrieving the access key, and then immediately deletes the entry. Then the cloud service transmits the access key back to the mobile device. This is obviously a one-time thing. In order to repeat that process you have to upload the credentials again from the PC.
Now the mobile device caches the credentials and the process is completed (the client side security risks are acceptable for this specific application as I can't require users to log in on the mobile device).
So what are the vulnerabilities here? Obviously, if someone views the QR code before our user does, they could theoretically take over the account, but we could fairly easily make this a two step process where the cloud service doesn’t hand over the decrypted access key until the user on the PC authorizes their device by name (“John’s iPad Mini”, etc.)
Obviously, the data encoded in the QR code is useless after a single use because the entry is deleted. An attacker could try to use the lookup table to download random user login credentials but they’d have to correctly guess a 256-bit decryption key… We’ll need to checksum the access key in the temporary retrieval table so we’ll detect invalid decryption keys sent by attackers. Really all we do is take the supplied key, decrypt the data using it, and check the checksum. If it matches, the data is valid and we can send back the decrypted access key.
Even if the cloud service is hacked, that table wouldn’t be useful cause the access keys are all encrypted and the keys are held on user systems, never on the cloud service. We would periodically (once a day, once an hour) delete older entries that weren’t successfully scanned by users.
I realize this falls under that infamous category of home-made authentication schemes, but this is somewhat dictated by requirements. Am I missing some obvious security flaws here?
Several additional details based on comments:
Timing Attack: Actually covered in my original question -- we will ask the user the confirm the client device by name ("Joe's iPad Mini") before providing the client with the access key. Obviously the request is kind of impossible to guess, so that would only be an issue if the QR code is seen by an attacker who immediately attempts to scan it before our user does.
Bruteforce: This design means that an attacker would have to guess a 256-bit key in order to get the credentials. Given that we're talking about an average lifetime of maybe a minute for these entries (with a maximum lifetime of maybe 1 hour), is that really an issue?
Replay attack: Since the retrieval entry is created during account creation, replay would be impossible as the account already exists and therefore the whole sequence would fail. I think...
Secure connection: YES, obviously all connections to service would use properly certified SSL connections.