The former concept of KeyStore is the place where the app is signed, and if you check Android KeyStore, the information is how to generate signatures for the app, but the meaning here is different. The Android KeyStore system allows you to store encryption keys, and it is difficult to export from the device, and can indicate the use rules of key, such as only after user authentication, can use key and so on.
Methods to prevent export:
- Key material never enters the application process.
- Key material bound to the secure hardware (e.g., Trusted execution Environment (TEE), secure Element (SE)) of the Android OID device.
You can get your keystore through the following code.
try{ KeyStore mKeyStore = KeyStore.getInstance(“YourType");}catch{ return;}
The parameters in the Keystore.getinstance (parameter) can pass the following content:
- "Androidkeystore": here to distinguish between the next Androidkeystore and Android KeyStore, although these two, but the latter is a space, the meaning is not the same, the former is a subset, the latter is the parent set, the latter contains the former. And Androidkeystore is mainly used to store some key key, the key stored in the place can be set keyprotection, for example, only through user authentication to remove key use and so on. These keys exist in the system, not in the app directory, and each app cannot access the key of the other app, if App1 created Key1, and the storage is named Temp,app2 to go through the temp to access key, is not get!!
- Keystore.getdefaulttype (): This function returns a string, in Java, returns the JKs, under Android, the return is BKS (generate Android used BKS certificate). (Note: The certificate used in the Android system requires the BKS library file structure to be saved, and in general, we can only generate JKS certificate libraries using Java's keytool. Read key can be read by the PSW). When you use this keystore, its files are stored in the data (sandbox).
- In other cases, there are some other keystore that I am not currently aware of, but have seen passing some other parameters.
What is the key divided into:
- Symmetric key (symmetric key): Secret key
- Asymmetric key (asymmetric key): Public key && private key
How to generate a key can be done in the following two classes:
- Keygenerator (Keypairgenerator): Generates a new key based on parameters such as the algorithm, the complement pattern, and so on.
- Keyfactory: When the server wants to tell the client key, it simply passes the byte array of key, which can be used to restore key.
Of course, when you generate the key, you have to explain that it can be explained by Keyspec subclasses.
See an example of generating key and restoring key:
//symmetric key is Secretkey created and imported, assuming both parties agree to use DES algorithm to generate symmetric keyKeygeneratorkeygenerator = Keygenerator.getinstance ("DES");//Set the key length. Note that the key lengths supported by each algorithm are not the same. Des supports only 64-bit length keysKeygenerator.init ( -);//Generate a Secretkey object, that is, create a symmetric key and obtain a written representation of the binarySecretkey Secretkey = Keygenerator.generatekey (); byte[] KeyData =secretkey.getencoded ();//daily use, the above binary array is generally converted to a string by BASE64 encoding, and then sent to the userString keyInBase64 =base64.encodetostring (Keydata,base64.default); E (Tag, "==>secret key:encrpted data =" + bytestohexstring (keyData));"==>secrety key:base64code="+ keyInBase64 + "key:alg="+ secretkey.getalgorithm ());//Suppose the other party receives the Base64 encoded key, first of all to get the second binary expression, using a binary array to construct the Keyspec object. Symmetric key uses the Secretkeyspec classByte[] Receivedkeydata =base64.decode (keyinbase64,base64.default); Secretkeyspec keySpec =new secretkeyspec (receivedkeydata, "DES");//Create secretkeyfactory for symmetric key importSecretkeyfactorysecretkeyfactory = Secretkeyfactory.getinstance ("DES");//Restore Key Object According to Keyspec, that is, the written expression of key is converted into a key objectSecretkey receivedkeyobject = Secretkeyfactory.generatesecret (keySpec); byte[]encodedreceivedkeydata = Receivedkeyobject.getencoded (); E (TAG,"==>secret key:received key encoded data ="+bytestohexstring (Encodedreceivedkeydata));
Practical application:
If the app wants to store a character content (like a password or token) at the client, how to use KeyStore to keep it safe from being read by others.
Solution steps:
1. If you deposit content in KeyStore, you can only save content as a key in KeyStore, just say that there are two ways to generate a key, one is to generate a key, One is to restore key (keyfactory), because we already know the content here, then it is to restore key, through keyfactory.
2. This key belongs to Secretkey because there is no concept of a private key and a public key. You should use the PBE algorithm (Password Based encryption based on password encryption) to generate.
3. The next step is the process of generating the key. Just said when generating the key, you need to indicate some parameters of key, through the Keyspec subclass. Check it out, it's just pbekeyspec!.
Code on:
//based on content generation secret Keypbekeyspec KeySpec = new Pbekeyspec (content< Span class= "Hljs-preprocessor" >.tochararray ()) ; Secretkeyfactory keyfactory = Secretkeyfactory.getinstance (" pbewithsha1anddes ") Secretkey key = Keyfactory.generatesecret (KeySpec) Keystore entry = new Keystore (key) ; Storage Keykeystore.setentry (KeyName, entry, new Keystore (Psw.tochararray ()))
Pbewithsha1anddes This is a cryptographic algorithm, the main algorithm is PBE, plus sha1 and Des.
4. The next is which keystore to store. Because we are generating secretkey, if there is a Androidkeystore, an exception is thrown. Because Androidkeystore only supports AES and HMAC for Secretkey.
So at present there can only be bks in this keystore, that is, the data is placed in the sandbox.
Complete the code to generate and store the key:
File File =NewFile (Context.getfilesdir (),"Temp");if(!file.exists ()) {Keystore.load (NULL,NULL); File.createnewfile ();return;} FileInputStreaminch=NewFileInputStream (file); Keystore.load (inch, Psw.tochararray ());inch. Close (); Pbekeyspec KeySpec =NewPbekeyspec (Token.tochararray ()); Secretkeyfactory keyfactory = secretkeyfactory.getinstance ("Pbewithsha1anddes"); Secretkey key = Keyfactory.generatesecret (KEYSPEC); Keystore.secretkeyentry entry =NewKeystore.secretkeyentry (key); Keyprotection.builder Builder =NewKeyprotection.builder (keyproperties.purpose_verify); Builder.setuserauthenticationrequired (true); Mkeystore.setentry ("alias", entry, Builder.build ()); Mkeystore.store (null);
In the above code, a password (Psw.tochararray ()) is specified for the load KeyStore. Password protection is also added to the data when it is stored.
Now the data is saved, but it's not safe, because if you just put the phone root, you can get the data in the sandbox. And the PSW is the app to write dead, if others know our PSW??? At stake!!
5. Add Security Now! As mentioned earlier, if you store key in Androidkeystore, you can set some protection (keyprotection) for the key, such as user authentication before you can use key, then we can use this to increase security.
First we generate a key and specify that the key can be used after the user has been authenticated and stored in the Androidkeystore. Use this key to encrypt the content and then store the encrypted contents in BKS.
When you take out, first use fingerprint verification, then remove the key in the Androidkeystore, and then remove the contents of the BKS, with key decryption.
It's safer with this scheme!
Look at the code:
Generate key in Androidkeystore
void GenerateKey () {Logutil. D("Localandroidkeystore Generate encryption Key ...");Here, AES + CBC + PADDING_PKCS7 is used, and user authentication is required to remove the try {final Keygenerator generator = Keygenerator. getinstance(keyproperties. KEY_algorithm_aes,"Androidkeystore");Mstore. Load(NULL);Final int Purpose = Keyproperties. PURPOSE_decrypt | Keyproperties. PURPOSE_encrypt;Final Keygenparameterspec. BuilderBuilder = new Keygenparameterspec. Builder(Sdkdata. AccountId, purpose);Builder. setuserauthenticationrequired(true);Builder. Setblockmodes(keyproperties. BLOCK_MODE_CBC);Builder. Setencryptionpaddings(keyproperties. Encryption_PADDING_PKCS7);Generator. Init(Builder. Build());Generator. GenerateKey();Logutil. D("Localandroidkeystore generated encryption key succeeded");} catch (Exception e) {Logutil. D("Localandroidkeystore generated encryption key failed");E. Printstacktrace();}}
Remove key for content encryption:
Mkeystore.load (NULL);FinalSecretkey key = (Secretkey) mkeystore.getkey (Aes_key_name,NULL);if(Key = =NULL)return;FinalCipher Cipher = cipher.getinstance (Keyproperties.key_algorithm_aes +"/"+ KEYPROPERTIES.BLOCK_MODE_CBC +"/"+ KEYPROPERTIES.ENCRYPTION_PADDING_PKCS7); Cipher.init (Cipher.encrypt_mode, key);FinalFingerprintmanager.cryptoobject crypto =NewFingerprintmanager.cryptoobject (cipher); Mfingerprintmanager.authenticate (Crypto,NULL,0,NewSimpleauthenticationcallback () {@Override Public void onauthenticationsucceeded(FinalFingerprintmanager.authenticationresult result) {FinalCipher Cipher = Result.getcryptoobject (). Getcipher ();byte[] encrypted = Cipher.dofinal (Token.getbytes ());byte[] IV = Cipher.getiv (); String result= base64.encodetostring (encrypted, base64.url_safe); LOG.D ("Tag", "Result:" + result); } },NewHandler ());
Remove the key to decrypt the encrypted content:
Mkeystore.load (NULL);FinalSecretkey key = (Secretkey) mkeystore.getkey (Aes_key_name,NULL);if(Key = =NULL)return;FinalCipher Cipher = cipher.getinstance (Keyproperties.key_algorithm_aes +"/"+ KEYPROPERTIES.BLOCK_MODE_CBC +"/"+ KEYPROPERTIES.ENCRYPTION_PADDING_PKCS7); Cipher.init (Cipher.decrypt_mode, Key,NewIvparameterspec (MIV));FinalFingerprintmanager.cryptoobject crypto =NewFingerprintmanager.cryptoobject (cipher); Mfingerprintmanager.authenticate (Crypto,NULL,0,NewSimpleauthenticationcallback () {@Override Public void onauthenticationsucceeded(FinalFingerprintmanager.authenticationresult result) {FinalCipher Cipher = Result.getcryptoobject (). Getcipher (); LOG.D ("Tag","Base of data to decrypt is:\n"+ base64.encodetostring (Encryptedtoken, Base64.url_safe) +"\ n");Try{byte[] decrypted = Cipher.dofinal (Mencrypted.getbytes ()); LOG.D ("Tag","decrypted data is:\n"+ base64.encodetostring (decrypted, Base64.url_safe) +"\ n"); }Catch(Illegalblocksizeexception | Badpaddingexception e) {}},NewHandler ());
Android KeyStore Store passwords