package com.klarna.ondemand.crypto; import android.content.Context; import android.content.SharedPreferences; import android.util.Base64; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * This class generates cryptographic keys using java.security package * and stores them using Android's standard storage. */ public class SharedPreferencesCryptoImpl extends CryptoBase { private static final String PUBLIC_KEY = "PublicKey"; private static final String PRIVATE_KEY = "PrivateKey"; private static final int KEYSIZE = 512; protected SharedPreferencesCryptoImpl(android.content.Context context) throws NoSuchAlgorithmException, InvalidKeySpecException { super(); SharedPreferences sharedPreferences = getSharedPreferences(context); if (!isAlreadyInUse(sharedPreferences)) { KeyPair keyPair = generateKeyPair(); persistKeyPair(sharedPreferences, keyPair); } publicKey = readPublicKey(sharedPreferences); privateKey = readPrivateKey(sharedPreferences); publicKeyBase64Str = toBase64(publicKey); } public static KeyPair generateKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM); kpg.initialize(KEYSIZE); return kpg.genKeyPair(); } private static SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences( SharedPreferencesCryptoImpl.class.getPackage().getName(), Context.MODE_PRIVATE); } private void persistKeyPair(SharedPreferences sharedPreferences, KeyPair keyPair) { SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit(); sharedPreferencesEditor.putString(PUBLIC_KEY, toBase64(keyPair.getPublic())); sharedPreferencesEditor.putString(PRIVATE_KEY, toBase64(keyPair.getPrivate())); sharedPreferencesEditor.commit(); } private String toBase64(Key key) { return new String(Base64.encode(key.getEncoded(), Base64.DEFAULT)); } private PublicKey readPublicKey(SharedPreferences sharedPreferences) throws NoSuchAlgorithmException, InvalidKeySpecException { String pubKeyStr = sharedPreferences.getString(PUBLIC_KEY, null); if (pubKeyStr == null) { return null; } byte[] sigBytes = Base64.decode(pubKeyStr, Base64.DEFAULT); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(sigBytes); KeyFactory keyFact = KeyFactory.getInstance(ALGORITHM); return keyFact.generatePublic(x509KeySpec); } private PrivateKey readPrivateKey(SharedPreferences sharedPreferences) throws NoSuchAlgorithmException, InvalidKeySpecException { String privKeyStr = sharedPreferences.getString(PRIVATE_KEY, null); if (privKeyStr == null) { return null; } byte[] sigBytes = Base64.decode(privKeyStr, Base64.DEFAULT); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(sigBytes); KeyFactory keyFact = KeyFactory.getInstance(ALGORITHM); return keyFact.generatePrivate(pkcs8EncodedKeySpec); } public static boolean isAlreadyInUse(android.content.Context context) { SharedPreferences sharedPreferences = getSharedPreferences(context); return isAlreadyInUse(sharedPreferences); } private static boolean isAlreadyInUse(SharedPreferences sharedPreferences) { return sharedPreferences.contains(PUBLIC_KEY) && sharedPreferences.contains(PRIVATE_KEY); } }