8

I would like to implement a "Remember Me" time-limited auto-login type feature on a mobile application (on Android). To start the app, the user must type in a username and password. For convenience,

EDIT

I would like to save the last inputted username and/or password into a file on the phone to avoid having the user re-type it each time.

I looked at this, but it seems to be more browser-oriented..

Questions:

  • How would I go about encrypting the file or password? I can't just use a hard-coded key to encrypt it, can I? I'd have to generate the key somehow. However, if the user exits and restarts - I'm assuming a separate key would be generated - so I have to save the key somehow?
  • Should I bother encrypting? (I think I should, however only the user would have access to this file anyway...)

EDIT 2

Am I over-complicating these things with surrogate keys and/or public key authentication with ssl/tsl? I mean, Firefox saves my passwords, and surely they are encrypted in some way? I was thinking to encrypt the user/pass in a similar fashion? Is that a bad idea?

f20k
  • 183
  • 1
  • 1
  • 6
  • 1
    I'm a bit puzzled by this. E.g. you say "to start the app, the user must type in a username and password". Do you mean they must enter that any time they start the app? In which case what is being remembered? Or are you talking about them being remembered on an associated web site, and how to manage the login credentials? In which case it seems to me that there are other questions about that here. – nealmcb Jun 03 '11 at 04:23
  • @nealmcb - By 'start' the app, I mean to logon and do something useful. They must enter their login details which are authenticated by the server before they can do anything. I want to save these details (on the phone) so they would not have to type it each time. – f20k Jun 03 '11 at 15:15

4 Answers4

6

I like symcbean's suggestion of creating a random mapped value on login that is related to the account separately from the username and password. To answer your question specifically, though, there are also ways of encrypting the data without a static mapped key. I'd look at generating a key using bits of information unique to the phone and retrievable via OS API calls.

Edit: At the behest of @D.W., I'll elaborate: The UDID, serial number, and other identifying information may be of sufficient cryptographic quality and secrecy without access to the phone to prevent decryption of the stored data. However, access to the stored data implies likely access to the phone as well. Thus, any level of security through device-local encryption is simple obscurity.

Other respondents have suggested storing a random value as is done in HTTP sessions. It seems the original asker isn't using HTTP and doesn't believe that this method applies to his software. However, the logical implementation of storing and transmitting a random value is applicable to any transport protocol. I strongly suggest it.

Alternately, credentials can be stored on the phone using public key encryption. The application can encrypt the username and password upon entry with the server's public key. The login data would thus be unreadable even if the device were compromised.

Where the goal is to prevent retrieval of login credentials, I feel the use of a random temporal identifier is best. This precludes any issues of keeping server data (a private key) secret and available. If that key were disclosed, the protection is marginal to useless. If it is lost, the app must be redeployed with new keying. If the temporal login data were lost, everybody would be forced to login, but it would not result in any appreciable interruption to service.

Also, do use public key encryption of the transport (SSL or simple PGP key embedded into the app) for both the initial login and any other possible authentication data whether it is the username and password or a random value.

AviD
  • 72,708
  • 22
  • 137
  • 218
Jeff Ferland
  • 38,170
  • 9
  • 94
  • 172
  • 1
    I think this should be made more concrete. What information precisely would you use? It is not enough that this information be unique to the phone; it also has to be unguessable to an adversary, and has to have sufficient entropy to ensure that. The key question is whether there is enough secret, unguessable information on the phone, that is both suitable for generating a crypto key, yet will not be available to attackers -- the answer is not clear, but it determines whether this approach will be viable. – D.W. Jun 04 '11 at 05:25
  • I just wouldn't do it. DRM design is not an area I get into, and encrypting things in a way that would prevent somebody with access to the system is something that fails time and again. I'm also not familiar enough with the iPhone system to get an answer without digging through the API. This was probably better left as a comment, but was copied to an answer at the behest of the asker. – Jeff Ferland Jun 04 '11 at 13:10
  • huh? In your answer, you said "use bits of information unique to the phone"; in your comment, you say "I just wouldn't do it". That is awfully confusing. – D.W. Jun 04 '11 at 18:49
  • I assume you meant that the username and password should be encrypted with the server's *public* key, not it's private key... I took the liberty and fixed that. – AviD Jun 07 '11 at 15:17
  • 1
    On some platforms (e.g. iOS, you'd want to check for Android) the device identifier and serial number are public data. Using them as source material for an encryption key would be folly at best. –  Jun 07 '11 at 20:50
5

Don't store the username and password on the phone.

Instead, I suggest you follow one of the following two strategies:

  • Use a persistent cookie. This is the easy solution. If you are connecting to a web site, have the server authenticate the user the first time they log on, and then set a persistent cookie on the user's phone containing a (cryptographically) random 128-bit string that is associated with the user's account. Every subsequent time the user launches the application, when it contacts the server over HTTP/HTTPS, the client will send its persistent cookie, which the server can use to authenticate the client. Ideally, you'd use HTTPS and use secure cookies.

  • Use public key authentication. This is the trickier solution. You could have the phone application generate its own public/private keypair. When the user logs on for the first time, the application can send the public key, and the server can associate the public key with that account. Every subsequent time the user launches the application, the application can authenticate itself to the server using the private key.

    • For instance, if you are using web technology, you might have the client generate a self-signed cert, connect to the server using HTTPS, and authenticate itself using its client cert. You would have to test whether web views on Android support client certs well.

    • Alternatively, if you connect to the server using your own custom protocol, tunnel it over SSL or TLS, and use the client certs feature of SSL/TLS.

D.W.
  • 98,860
  • 33
  • 271
  • 588
  • So for strategy #2, does that mean I store this public key instead of user/pass? And read it in when the program starts to automatically log myself in? – f20k Jun 04 '11 at 14:15
  • @f20k, you store the private key on the phone and the public key on the server. – D.W. Jun 04 '11 at 18:48
4

Do not use the username / password for the token!

If it is possible to decrypt, then there is a risk that it will be decrypted. And even though most peolpe know they shouldn't, they use the same passwords for multiple services - so even if your service is not particularly valuable, you have a responsibility to protect any passworsd given to you.

The way to solve the problem is the same as managing HTTP sessions - use a surrogate identifier (which may hold the same value as the session cookie - but with a longer lifespan) then maintain a lookup table of the surrogate identifier, the user it was issued to and the expiry time.

symcbean
  • 18,418
  • 40
  • 74
  • I am not using http sessions - I have a custom network protocol to send custom packets to a server. Regardless, I am looking to store and encrypt the details offline (on the phone). – f20k Jun 03 '11 at 15:23
  • The point he's trying to make, and the cause for my +1 vote, is that the same logic there is sensible here. A temporal secret value prevents storage of credentials and saves a lot of programming overhead with drm / crypto. That said, if I were to encrypt it, I'd do by generating a key using bits of information unique to the phone and retrievable via OS API calls. – Jeff Ferland Jun 03 '11 at 16:36
  • @Jeff Ferland - using the unique phone info never occurred to me. You should add it as an answer so I can accept it – f20k Jun 03 '11 at 20:00
3

D.W.'s 2nd option is best implemented with the following corrections & extra details:

  • generate a keypair on the App, after the User has successfully authenticated using the normal authentication mechanism and while in that authenticated session.
  • generate a UUID on the phone (don't use the OS/API's inbuilt device ID nor any other unique identifiers that any other App can also retrieve), encrypt it*, and store it (*see below for encryption best practices for App data on a mobile phone).
  • programatically use a combination of the UUID and some available phone details, mashed together a little (rather than simply concatenating them) to generate an AppDeviceId that only your App knows.
  • send the public key + AppDeviceId to the server over a secure channel (SSL/TLS signed by a really trusted CA), no compromises, to register the device and public key.
  • now for encryption: programmatically generate an encryption key using a combination of a UUID (not the one you use to make AppDeviceId) and some available phone details, mashed together a little (rather than simply concatenating them). If you can tie in the phone's lockscreen password/pin that's even better (on iOS this is done under the hood with the keychain, IFF the user in fact uses a lockscreen password/pin).
  • store the UUID you created for generating the encryption key in storage that only your App is "allowed" to access (keeping in mind that a rooted device means any App or User can probably access it anyway...and this is the weakest point).
  • encrypt and store the UUID you created for the AppDeviceId and encrypt and store the encrypted private key. Again , use storage that only your App is "allowed" to access (keeping in mind that a rooted device means any App or User can probably access it anyway).
  • to authenticate in future the App should sign a payload that is known to both App and server, e.g. the AppDeviceId, using the private key and send that over a secure channel (SSL/TLS etc.) to the server. The server must verify the signature using the public key.
  • If the server ever receives an attempted authentication, using a given AppDeviceId, that fails then remove/delete/forget the registered public key and block any further attempts to authenticate using this keypair mechanism until the User authenticates using some other, (typically) more secure, tried-and-tested technique (such as the authentication process you're augmenting with this new one, or in person with the right documents, etc).
  • adding time-limit on the keypair is even better (mitigates prolonged hijacking), that way the User must authenticate using a more secure, tried-and-tested technique from time to time.

Via the above, it would take decompilation and reverse engineering of code + access to the stored data on the device ( physical access to device OR malicious App on rooted device ) + knowledge of the device ( fingerprinting via some trick OR physical access to device OR control of an App on device ) to be able to use that keypair and AppDeviceId to authenticate.

straya
  • 131
  • 2