Storing symmetric key for offline usage - android

I'm making an app that will require a password to be entered before the main app will load. I plan to get the user to create a password when they first run the app and then store the password on the local device and encrypt it using a local symmetric key (which will be generated when the app first runs). This is so someone can't simply read the file where the password is stored.
How can I store the key used securely? Or is there a better way of hiding stored passwords to be used in local verification?
The app is designed for offline usage so I can't add any networking capabilities.

You can use SharedPreferences in private mode to store the password. It is secure as far as the phone is not rooted but you can use Cryptography techniques to store the password. The approach which I follow to store the passwords locally is to add a SALT to the password while storing.
You can read more about it here

A secure way for passwords - hashing. A hash can never be decrypted as the password is lost during the hashing process. I'm using MD5 hashing process in the following code -
public String StringToMD5(String s) {
try {
// Create MD5 Hash
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i=0; i<messageDigest.length; i++)
M hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
Use this code to hash your password and then store it using Private SharedPreferences. When the user enters the password again, hash it again and check if it is the same as previous hash. If the hashes match, then access is granted.

Please start by reading Thomas Pornin's canonical answer to How to securely hash passwords?.
PBKDF2 options are listed in the question PBKDF2 function in Android, but include a native SecretKeyFactory method as well as Spongycastle, bouncycastle, rtner.de, etc.
Long, cryptographically random per-password salt is required (make room for more than one password for future growth!).
Never ask PBKDF2 for more key length than the native function supports - that 64 bytes for PBKDF2-HMAC-SHA-512, and 20 bytes for PBKDF2-HMAC-SHA-1.
Always use as high an iteration count as your users can stand. Even for android devices, for a single user on their own device, done only once at application start, that's in the hundreds of thousands or more for PBKDF2-HMAC-SHA-1 and the tens to hundreds of thousands for PBKDF2-HMAC-SHA-512.
Note that PBKDF2's primary use is in creating encryption keys - you can use the same password entered to generate the encryption key for files you encrypt using AES (NOT in ECB mode); just use a different salt and a different number of iterations. If you're only doing that, then you don't even need the password hash; simply try decrypting the file with the key generated and a stored salt and number of iterations - if it works, it was the right password. If it fails, it wasn't.

Related

We need to encrypt a product serial number, which has to be decrypted in an App

We have a physical product with an QRCode, like this:
http://example.com/product/[encryptedProductKey]
We need to check in an app when the qrcode is scanned if the product key is valid and was made by us.
The qrcode will be lasered onto the product and cannot be changed afterwards.
Unfortunately we are a small startup and noone here really knows about encryption. Is there some kind of dummy approach to this?
You probably don't actually need encryption but rather a MAC: Message Authentication Code or a Digital Signature.
If you are both generating and verifying the codes then a MAC is sufficient (I assume this is the case?).
In which case, the product code can be a random set of characters (cryptographically strong random number) and the HMAC (Hash based Message Authentication Code). It could be quite long but would be a simple solution.
The steps would be something like (the below is pseudo code):
Generate a strong secret key that you use to generate and verify codes (don't share this)
Generate a product code:
code = cryptoRandom(16) // 16 strong random bytes
tag = HMAC(code, secretKey)
Encode the key say with Base64
Give the resulting base64 string to your customer
To verify the key:
Split the decoded product customer key string into the code and tag
Generate the tag from the code
tag = HMAC(code, secretKey)
Check that the tag that you generate matches the tag in the customer key
secureCompare(tag, tagFromCustomer)
Note that you must not use == to compare the tags as this will be vulnerable to timing attacks. Your language should have a secure compare library. See What's the difference between a secure compare and a simple ==(=)
As an alternative, if you want to keep the customer key to 32-bytes in length you could take the below approach. However, this would require that you keep a secret key for every customer.
Generate a secret key for the customer
Use that key to generate a customer key by using the HMAC of a zero string (say 16)
code = HMAC("0000000000000000", customerSecretKey)
Give the customer the code
To verify, use the customers secret key to verify
secureCompare(customerCode, HMAC("0000000000000000", customerSecretKey))
For this to be secure, the customer keys must be secret AND unique.

Using the Android hardware-backed KeyStore

I wish to use the Android hardware-backed KeyStore, but I'm concerned about security and usability.
From what I've read here, KeyStore gets wiped when the user changes the device lock, unless setEncryptionRequired() is omitted. For usability sake, it seems this needs to be done, otherwise all hardware-backed keys would get wiped once the device lock is modified.
However, I've also read here that hardware-backed keys are not actually stored in the TEE, but rather, stored as key files in /data/misc/keystore/user_0/, encrypted by a device specific key that is stored within the TEE. Since a change in device lock wipes the KeyStore, it seems that the device specific key is derived from the device lock.
For security reasons, it makes sense to encrypt the key file, otherwise any root user would be able to read the key files and extract the private key, since they'd presumably be in they clear.
So I'm kind of in a dilemma. For usability sake, I should omit setEncryptionRequired(), but for security sake, I should set setEncryptionRequired().
Lastly, is it possible import a private key into the hardware-backed KeyStore using setKeyEntry()? I'm able to do so with no errors but I'm not sure if it's hardware-backed.
Is my understanding correct?
setEncryptionRequired() was deprecated in Android 6.0 (Marshmallow), and never really accomplished very much. The security of Android KeyStore depends on the TEE, not the password.
The blog post you linked to is out of date, at least on devices running Android 6.0 or later. On those devices, you should not use setEncryptionRequired(), and your keys will not be deleted until your app is uninstalled (or a factory reset is done, or your app deletes them). Your keys will be securely wrapped by secret keys that never leave the TEE. In fact, your keys will never leave the TEE in plaintext. When you use your keys, the data is passed into the TEE along with the encrypted key. The TEE unwraps the key then processes and returns the encrypted/signed/whatever data.
Yes, you can import private keys using setKeyEntry(). If you want to be sure that your key is hardware-backed, use KeyInfo.isInsideSecureHardware(). For example (this is from the documentation):
PrivateKey key = ...; // Android KeyStore key
KeyFactory factory = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
KeyInfo keyInfo;
boolean isHardwareBacked = false;
try {
keyInfo = factory.getKeySpec(key, KeyInfo.class);
isHardwareBacked = keyInfo.isInsideSecureHardware();
} catch (InvalidKeySpecException e) {
// Not an Android KeyStore key.
}

Android Keystore's password protection

We used Anroid Keystore to store some confidential data and set up a password for Keystore. This passwords are used in conjunction with the KeyStore class in the load, getKey and setKeyEntry methods.
The Keystore itself is encrypted and app can only view and query its own data so we can say that data are somewhat secure inside Keystore but how we can secure the password that associated with keystore account? I found many example online and most of them having hardcoded password in code or use null parameter.
Please see in below example. I want to know what is the best approach to secure hardcoded password?
Want to find a safe way in android device itself to store this hardcoded password. Assume that moving it to external place like database, service call etc. options are NOT available.
Context context;
KeyStore ks;
KeyStore.PasswordProtection prot;
static readonly object fileLock = new object ();
const string FileName = "Xamarin.Social.Accounts";
static readonly char[] Password = "3295043EA18CA264B2C40E0B72051DEF2D07AD2B4593F43DDDE1515A7EC32617".ToCharArray ();
public AndroidAccountStore (Context context)
{
this.context = context;
ks = KeyStore.GetInstance (KeyStore.DefaultType);
**prot = new KeyStore.PasswordProtection (Password);**
try {
lock (fileLock) {
using (var s = context.OpenFileInput (FileName)) {
ks.Load (s, Password);
}
}
}
catch (FileNotFoundException) {
//ks.Load (null, Password);
LoadEmptyKeyStore (Password);
}
}
Assume that moving it to external place like database, service call etc. is NOT possible
You want to securely store sensitive information on the local user's machine.
The only way to do that is encrypting it. The most popular encryption algorithm is AES, and luckily Microsoft included an implementation of it in C#.
However, encryption uses a secret key to encrypt/decrypt the data, so we're basically moving the problem back - now we need to store that encryption key securely.
You could hard-code that key in the app, but a dedicated attacker could still get it and decrypt the password.
Instead, get that password from the user. Ask them to provide a password, hash it (using e.g. SHA256) and use the hash as the key for the encryption.

How to use public-key encryption in Py4A scripts?

I'm developing an Py4a (Python in SL4a) application running on an Android phone.
The application collects some sensitive data, and then sends it via e-mail, using the smtplib module.
To assure necessary protection, I need to encrypt that information.
As phone is considered to be unsafe device, I have to use the public-key encryption, and only recipient's public key should be stored in the phone.
The standard Py4a distribution contains two packages supporting public key cryptography:
the ssl and gdata.
Unfortunately none of them provides a ready to use function, allowing me to encrypt longer information with the private key.
Well, I know that in fact I should generate a random temporary symmetric key, encrypt my information with that key, and finally encrypt only this key with the recipient's public key. However there are some details which must be considered to obtain secure solution...
So here my question comes. Is there any simple encryption library, well suited to Py4a (ie. based on the cryptographic libraries already available in Py4a - like ssl and gdata.Crypto) providing easy to use public key encryption?
Update 2013.06.13
I have performed some experiments with the gdata library in Py4a.
Finally I have get the following "quick&dirty" solution:
import gdata.tlslite.utils.keyfactory as rk
#Generate the recipient's RSA key
sec=rk.generateRSAKey(1024)
#obtain the publickey, which will be stored
#in the sender mobile phone
pubxml=sec.writeXMLPublicKey()
print pubxml
#Create the public key from XML
pub=rk.parseXMLKey(pubxml)
#
#Now lets simulate the sender
#It has only access to "pub"
#
import gdata.tlslite.utils.PyCrypto_AES as sk
import gdata.tlslite.utils.cipherfactory as cf
#Generate random key and initioalization vectors
key=sk.getRandomBytes(32)
iv=sk.getRandomBytes(16)
#Here we should check if the key and iv are reasonable
#Now we accept them as they are
#Text to encrypt
txt1="Strictly secret unknown text!"
#Pad the text to the length N*16
padlen=16-(len(txt1) % 16)
if padlen:
txt1=txt1.ljust(len(txt1)+padlen, " ")
#Create the AES key
ak=cf.createAES(key.tostring(),iv.tostring())
#Encrypt text
ctxt1=ak.encrypt(txt1)
#Encrypt key and initialization vector with recipients publickey
ckey1=pub.encrypt(key+iv)
#
# Now we simulate the recipient
# It has its secret key 'sec', and received encrypted key
# and iv from the sender in ckey1. It also receives ctxt1
#
pkey1=sec.decrypt(ckey1)
pkey=pkey1[0:32]
piv=pkey1[32:48]
# Now we decipher the text
pak=cf.createAES(pkey.tostring(),piv.tostring())
ptxt1=pak.decrypt(ctxt1)
# Print the deciphered text
print ptxt1
Probably this solution is far from being optimal, but it at least works.
Because the phone is an unsecure device, you cannot trust anything that is computed on the phone. If you want something done securely, do it on your server.
As for your question, this is just how public cryptography (at least RSA) works: you cannot encrypt any data that is longer than the key. The reason there are not libraries for this is that it is impossible. If you need secure email use S/MIME or GPG and don't try to reinvent the wheel. Also note that since the key needs to be in the app, anyone can extract it and decrypt your data. If you just want to send data securely, a better approach might be so send the data over HTTPS. Then you don't need to manage client keys and your data will be protected in transit.

how to encrypt and decrypt a message by using RSA with signature in android

no key distribution, public and private keys will be known by users (random key generator will not be used). I have to encrypt hashed message with private key in order to provide signature
message will only 10-20 characters, so system can be as simple as it is possible
For generating a digital signature, you don't need to encrypt the hash. Signing is a separate crypto primitive; the hash is not encrypted raw anyway, there's some padding. That said, the code is:
Signature Signer = Signature.getInstance("SHA1withRSA");
Signer.initSign(MyKey, new SecureRandom()); //Where do you get the key?
byte []Message = MyMessage(); //Initialize somehow
Signer.update(Message, 0, Message.length);
byte [] Signature = Sign.sign();
Okay, back up and tell us what you want. Are you trying to get privacy by protecting the contents of the message, or guarantee authenticity by showing that the message really came from the originator?
If you're looking for privacy, RSA isn't the way to go: use RSA to generate a private/public pair, and then use them to excahnge keys -- or exchange keys out of band. Use a streaming algorithm like AES to encrypt the message.
If you just want signature to show the message was originated by who you think it was, then have a look at the Wiki article on digital signature -- it's reasonably straightforward.

Categories

Resources