Encrypt passwords as securely as possible

Asked

Viewed 1,965 times

1

I wonder how to encrypt passwords on Android and what are the best practices.

I am using Eclipse, Sqlite database to store the password locally and Mysql with PHP to store on the server via HttpClient. My application will be for online and offline use. Therefore any registration or alteration of user data, is done on the server and only then locally, that is, only online that the user can register or change his data.

An alternative I think would be to encrypt the password, generate a hash to prevent it from being changed while sending to the server and generate a sort of device signature hash so the server knows that the password came from a device with the application installed and concatenate everything would look like this:

"Encrypted Password" + "Integrity Hash" + "Authenticity Hash"

And the server would check all this and store in the database all this together also locally and externally.

  • Duplicate(?), related: How to hash passwords securely?

  • 1

    Is it really necessary to store the password on the user’s device? If your application will be able to decrypt the password, so will a malicious user. Ideal in this case is to use a web service.

  • @André Ribeiro I know this, but my application will be of online and offline use, in this case I have a suggestion that may be useful, but I do not know how I could implement it, I will edit the question with my suggestion.

  • 1

    @Renan Duplicate not that link refers to the use of hash and mine is encryption that is a well improved hash.

  • I don’t understand what the app has to do with saving passwords locally and offline.

  • @Pablo It has to do because the user will be able to login to the application even without internet (offline), he will be able to login and login even if offline understands?

  • And in case I will save on the server because as the application will have a desktop version the user will be able to download his server profile and use on desktop and mobile.

  • @Gustavoalmeidacavalcante Cryptography is not "a well-improved hash", the function of the hash is from an input to generate a unique value that represents it but it is not possible to do the reverse process (get the original data from the hash). The function of cryptography is to transform one data into another, unreadable, and then turn it back into the original data with the aid of a secret value (password or key). They are different techniques, applicable in different situations. Usually to protect passwords is using hashes, encryption is useless in this sense (see André Ribeiro’s comment).

    1. Do not save the user password, just save the Hash generated from that password. 2. Store the hash generated in the application if the user is valid on the server (online) 3. When the user places the login offline, generate the login hash and validate if the hash transformation matches the stored one, when online, ignore the local validation and ask the server.
Show 4 more comments

2 answers

2


An alternative I think would be to encrypt the password, generate a hash to prevent it from being changed while sending to the server and generate a sort of device signature hash so the server knows that the password came from a device with the application installed and concatenate everything would look like this:

Never invent your own encryption! The chances of something going wrong are huge. Instead, use a well-established protocol for what you want:

  1. Connect to your server using SSL/TLS. So the data you send to it will already be confidential and intact, it is not necessary to encrypt the password or generate a hash (incidentally, a hash does not prevent it from being changed during sending; a MAC maybe, but this is another story). And if you combine this with a customer authentication using certificates, you already guarantee the authenticity too, just send only the same simple password and ready!

  2. If you need to store the user password on the device (it is not clear in the question if the user will have to type it every time you connect to your server, or if it will be saved on the device), look for some feature of the system itself to help you. I have no experience with Android, but a quick search brought me the AccountManager - which seems to me to be a centralized means of managing the accounts that the user has in various services. I suggest to study it.

Detailing

If what I explained above was not clear, let me break the problem down into smaller pieces to make it easier to understand the proposed solution (and maybe present some alternatives):

Saving passwords on the device

Unless you want the user to enter their password every time they connect to your server, you need some method of authentication to be stored on the device. In this case, you cannot hash the password because you need the password in its original format to send to the server (otherwise hash becomes the password, and any attacker who gets a copy of the hash already has the credentials necessary to authenticate with the server). Encryption is an idea, but where to keep the key? This is a complicated situation, hence my suggestion to use what you already have ready on Android and get it out of your head...

Communicating safely with the server

If you do not use SSL/TLS (e.g., HTTPS), you cannot guarantee that communication with the server will not be intercepted and even modified (particularly on open networks). Trying to "turn around" without TLS will leave you with an unsafe solution and/or force you to reinvent many wheels. So I strongly suggest using this protocol.

When creating a secure channel via TLS, you can send the user credentials in flat format without the need to encrypt. Because the protocol guarantees the confidentiality (i.e. no one can read the communication) and the integrity (no one can change the communication) of both, in addition to the authenticity of the server (the client knows he is communicating with the right server).

Authenticating the device

In the question you show concern about the device that originated the request ("...so the server knows that the password came from a device with the application installed..."). That is, in addition to authenticating the user with the server, you also want to authenticate the device with the server.

At first, this can also be done via SSL/TLS, using customer certificates. Roughly, when installing the application it would generate a certificate for that device, register that certificate on the server (or simply have that certificate signed by an CA that the server trusts)and then when communicating via TLS would use that certificate with the protocol. So both client and server would be authenticated to each other, and it would be enough then you authenticate the user (sending the password in its normal format).

If all this is too complicated, a simpler alternative would be to generate a random password to be the "device password", and register it on the server next to the user’s password. This password would then be sent during authentication, also under the previously established secure channel.

Saving passwords on the server

On the server, of course, you will not store the password(s) in flat format, but a hash(s) of the same(s). See the question "How to hash passwords securely?" for more details.

  • Your idea for server application authentication and vice versa is great, however regarding sending the password in plain text and having to hash the server I will have to do the same hash on the device and store in the local database if that is possible then it would be great since even if a hacker has access to the local database he would have that send the password in plain text and not the hash pro server even if it could pass through the device using the same protocols.

  • But since we know that there is nothing 100% safe to add the encryption in the password being sent would not be bad as long as not only the password is encrypted, but the entire login, this way if for some reason the hacker get access to what is being sent he will not know what is user or password of the encrypted string and in addition could add in this string a kind of counter of last access this way if the hacker use this encrypted string again to authenticate will not get, because the access counter will no longer be valid.

  • The problem in this case would be to decrypt the string on the server using a key that is not being sent, as the hacker could have access to the key. In that case I could make a single, fixed key in that encryption, of course that shape still leaves a vulnerability if the hacker discovers a single key, it will have access to the password of all users just by capturing the string that is being sent when the user is logging in, but this would bring a greater difficulty than sending the data in plain text.

  • Regarding the hash I will search more to implement in both client and server environments. Thanks for the help.

  • Regarding server authentication the user will not need to type anything the device itself will generate your unique authentication key based on the user and password.

  • I repeat: don’t invent your own encryption! Your arguments make sense, but they are many little details that are easy to go unnoticed, so my recommendation to stick to the standard protocols. Also, it’s good to have the threat model clear in mind: are you worried about a hacker intercepting communication? about stealing the device itself? both? Applicable defenses (if any) depend on this threat model. Fortunately, SSL/TLS and AccountManager seem to cover all cases treatable satisfactorily, and the intractable the way is to let go...

  • Some comments on what you proposed: 1) hash is irreversible, hashing in the local database will make it impossible for that same password to be used as credential. I’m afraid I don’t have any 100% secure means of storing credentials on a device, so either you just authenticate the device (and anyone who owns it is authenticated) or you authenticate the device and the user (requiring the user to enter their password or PIN; see also two-factor authentication). 2) Encrypting on the device is useless if you cannot...

  • ...protect the key! In that case the additional security of the encryption is zero, is more "security theater" than security itself. And to protect data in transit, you don’t need any of this, the SSL/TLS channel is already secure from this account. 3) actually use a symmetric key for the server and all clients is complicated because as you spoke a single cracked device reveals data from all users. Either you have one key per user, or you use asymmetric encryption (private key on the server, public key on the devices). I just didn’t understand how this would help with security, because...

  • ...the encrypted data would still be the same access pass (i.e. what the device has and can be used to log in, the hacker can steal and also use to log in... there is no "magic" that protects in this case). Anyway, do you notice how complex the problem is? I study cryptography a few years ago, but I still know little about it, and I still do a lot of nonsense. So I reaffirm my opinion that this sort of thing is best left to the experts whenever possible. A "handmade" protocol has a great chance of going wrong, and ending up worse than using nothing.

  • I will apply the simplest and most used, as you yourself recommended. What I want for this application is that if a hacker can get hold of someone’s device, they won’t be able to access the user’s data locally or in the cloud. In addition, if he manages to intercept what the user is sending over the network, he will not be able to know what it is. In any case, his reply and his comments were of great help. I see that this is a very complex subject and it needs to be studied more deeply to try to do something of its own as was what I wanted to do.

  • Thank you for your attention I will close by leaving your reply as chosen, because what I want to do is something that at the moment will not be possible.

Show 6 more comments

0

After some research I found a ready example using AES on this site: http://www.iai.art.br/radar/android-development-criptografia-baseada-em-senha/

It worked well it encryption and decryption too, for me I just wanted one that only encrypted without possibility of decryption, but this one fits for now. My doubt in this code is in relation to this method of encryption that I do not know if it will generate some code encrypted with this character "#", because I am using it and this " " to separate the string and mount the fields to store in the bank. The method is this:

public static String encrypt(String plainText, String password)    throws
  NoSuchAlgorithmException,
  InvalidKeySpecException,
  NoSuchPaddingException,
  InvalidParameterSpecException,
  IllegalBlockSizeException,
  BadPaddingException,
  UnsupportedEncodingException,
  InvalidKeyException,
  InvalidAlgorithmParameterException
{
  byte[] saltBytes = salt.getBytes("UTF-8");
  byte[] ivBytes = initializationVector.getBytes("UTF-8");
  SecretKeyFactory factory =   SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

  PBEKeySpec spec = new PBEKeySpec(
       password.toCharArray(),
       saltBytes,
       pswdIterations,
       keySize
  );
  SecretKey secretKey = factory.generateSecret(spec);
  SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  cipher.init(Cipher.ENCRYPT_MODE, secret, new       IvParameterSpec(ivBytes));
  byte[] encryptedTextBytes =  cipher.doFinal(plainText.getBytes("UTF-8"));
  return Base64.encodeToString(encryptedTextBytes, 0);
}

And if anyone has a better suggestion, it would be very helpful.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.