2

I have written an API so that my different apps can use it.It simply checks whether app is registered with the server or not.If not then it generates Public/Private keypair,and got a signed certificate by sending CSR to my server. The next time it uses the signed certificate and private key. Initially I have default keystore file in raw ( b/c all my communication is over SSL i.e. initially with default keystore and after registration with user generated keystore)

My API is working fine. The issues I am having are somewhat related to my lack of knowledge or wrong approach and hence I need assistance.

I am using the following class to save/retrieve my Keypair

public class KeyIOHandler { public static void writePublicKeyToPreferences(KeyPair key, Context context) { StringWriter publicStringWriter = new StringWriter(); try { PemWriter pemWriter = new PemWriter(publicStringWriter); pemWriter.writeObject(new PemObject("myapp.PUBLIC KEY", key.getPublic().getEncoded())); pemWriter.flush(); pemWriter.close(); SharedPreferences preferences = context.getSharedPreferences("SHARED_PREFERENCES",0); preferences.edit().putString("RSA_PUBLIC_KEY", publicStringWriter.toString()).commit(); Log.e("Public Key", publicStringWriter.toString()); } catch (IOException e) { Log.e("RSA", e.getMessage()); e.printStackTrace(); } } public static void writePrivateKeyToPreferences(KeyPair keyPair, Context context) { StringWriter privateStringWriter = new StringWriter(); try { PemWriter pemWriter = new PemWriter(privateStringWriter); pemWriter.writeObject(new PemObject("myapp.PRIVATE KEY", keyPair.getPrivate().getEncoded())); pemWriter.flush(); pemWriter.close(); SharedPreferences preferences = context.getSharedPreferences("SHARED_PREFERENCES",0); preferences.edit().putString("RSA_PRIVATE_KEY", privateStringWriter.toString()).commit(); Log.e("Private Key",privateStringWriter.toString()); } catch (IOException e) { Log.e("RSA", e.getMessage()); e.printStackTrace(); } } public static PublicKey getRSAPublicKeyFromString(String publicKeyPEM) throws Exception { publicKeyPEM = stripPublicKeyHeaders(publicKeyPEM); KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SC"); byte[] publicKeyBytes = Base64.decode(publicKeyPEM.getBytes("UTF-8")); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes); return keyFactory.generatePublic(x509KeySpec); } public static PrivateKey getRSAPrivateKeyFromString(String privateKeyPEM) throws Exception { privateKeyPEM = stripPrivateKeyHeaders(privateKeyPEM); KeyFactory fact = KeyFactory.getInstance("RSA", "SC"); byte[] clear = Base64.decode(privateKeyPEM); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear); PrivateKey priv = fact.generatePrivate(keySpec); Arrays.fill(clear, (byte) 0); return priv; } public static String stripPublicKeyHeaders(String key) { //strip the headers from the key string StringBuilder strippedKey = new StringBuilder(); String lines[] = key.split("\n"); for (String line : lines) { if (!line.contains("BEGIN PUBLIC KEY") && !line.contains("END PUBLIC KEY") && !isNullOrEmpty(line.trim())) { strippedKey.append(line.trim()); } } return strippedKey.toString().trim(); } public static String stripPrivateKeyHeaders(String key) { StringBuilder strippedKey = new StringBuilder(); String lines[] = key.split("\n"); for (String line : lines) { if (!line.contains("BEGIN PRIVATE KEY") && !line.contains("END PRIVATE KEY") && !isNullOrEmpty(line.trim())) { strippedKey.append(line.trim()); } } return strippedKey.toString().trim(); } public static boolean isNullOrEmpty(String str) { return str == null || str.isEmpty(); } } 

and by using the following method I am generating my keystore but I am confuse how and where I can store this keystore securely so that i can use it for the rest of app's life.(unless key is stolen). As in shared preferences I cannot store any object, so where to save this keystore.Right now I have static keystore object in my class.(which is worst I know but just to make it working i have made it static)

private boolean addToStore(){ try { Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1); clientPkcs12 = KeyStore.getInstance("PKCS12"); clientPkcs12.load(null, null); clientPkcs12.setKeyEntry("clientCert", keyPair.getPrivate(), "123456".toCharArray(), chain); } catch(Exception ex){ Log.e("",ex.getCause().getMessage()); } return false; } 

I have gone through few posts,among them this is noticeable one nelenkov.blogspot but not getting how can I achieve my target or am I wrong at saving keystore? I mean do I have to create keystore every time?

3 Answers 3

3

I don't know why you want to keep your credentials in shared preferences when you have Keystore. Once you load your keystore file to memory you can add/retrieve keys anytime you want. And when you finished with just save it in file by calling:

FileOutputStream out = new FileOutputStream(keystoreFile); keystore.store(out, password); out.close(); 

load from file:

keystore.load(new FileInputStream(keystoreFile, password); 

@answer to comment

You should only use Keystore. Data from shared preferences are not secured and it's very easy to retrieve private key from it. You did not use any kind of encryption so your key is stored in plain PEM text. But if you use Keystore your key is password protected (on key level and on keystore level) so if anybody gets the Keystore file without passwords it will be much harder for him to break it. Best place to keep Keystore file is your app internal space disk which cannot be accessed without rooted phone (Context.MODE_PRIVATE when creating file).

Sign up to request clarification or add additional context in comments.

3 Comments

thnx for the reply , i have already mentioned that may be I am taking this wrong, so as you said I have two things to ask, 1# Do I need to save my keys in SP as I am doing or only keystore is enough? 2# Where to save this file so that nobody else can access it?
thnx again , testing with this, will accept your answer once i'll get success
Nikolay Elenkov blog is great source of information for all things related to Security in Android. I recommend to look through all his blog posts to get a lot of knowledge about that. You can checkout his book as well: nelenkov.blogspot.com/2014/04/android-security-internals.html
0

You've answered your own question. Save them in a KeyStore, not in a preferences file.

Comments

0

The KeyStore get saved by itself unless it is being recreated. We can always extract the keys using getKeys() from the key store even after restarting the app. To do this first check if any of the privateKey or secretKey is already present or not. If present don't recreate the KeyPair(which indiretly creates a new KeyStore). Notice:The way I implemented the keyStore gets deleted after the app gets uninstalled.

public KeyStore createKeyStore(){ try { KeyStore ks = KeyStore.getInstance(ANDROID_KEYSTORE); ks.load(null); return ks; } catch (KeyStoreException e){} return null; } public KeyPair getAsymmetricKeyPair() throws NoSuchPaddingException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException { KeyStore ks=createKeyStore(); KeyPair keyPair; try { PrivateKey privateKey= (PrivateKey) ks.getKey(KEY_ALIAS, null); //privateKey is null it means that there is no keyStore Available if(privateKey==null){ //Creating a new KeyStore while creating a KeyPair using keyPairGenerator keyPair=this.createAsymmetricKeyPair(); return keyPair; } else //When the keyStore is already available { PublicKey publicKey=(PublicKey) ks.getCertificate(KEY_ALIAS).getPublicKey(); //Creating a KeyPair After retrieving them from KeyStore return new KeyPair(publicKey,privateKey); } } catch (UnrecoverableEntryException e){} return null; } public KeyPair createAsymmetricKeyPair(){ try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE); keyPairGenerator.initialize( new KeyGenParameterSpec.Builder( KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT|KeyProperties.PURPOSE_ENCRYPT) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) .setBlockModes(KeyProperties.BLOCK_MODE_ECB) .build()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); return keyPair; } catch(Exception e){} return null; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.