记录使用KeyStore的公钥和私钥进行数据加密,使用SharedPreferences进行存储

背景

在业务中,我们可能需要面对在 Android 本地存储用户 token、用户信息等敏感数据进行加密。本文将讲述一种安全系数较高的Android本地存储方案。

思路

整个方案的核心思路围绕 KeyStore 展开,如果不太了解 KeyStore 的小伙伴,请先阅读Android 密钥库系统。

由于 KeyStore 在 Android 6.0 前后差异较大,并且 Android 4.3 以下系统并不支持 KeyStore,方案需要根据不同的 Android 版本做不同的处理,以及需要提供降级方案。加解密算法采用 RSA/ECB/PKCS1Padding。

Android6.0及以上版本

这种情况下方案最简单,随机生成2048位RSA key和iv,key存储在KeyStore中,设置alias,iv存储在SharedPreferences中。需要加解密的时候通过alias从KeyStore中取key,从SharedPreferences中取iv。

1.首先初始化KeyStore

private static final String ANDROID_KEY_STORE = "AndroidKeyStore";

private static final String RSA = "RSA";

try {

mKeyStore = KeyStore.getInstance(ANDROID_KEY_STORE);

mKeyStore.load(null);

} catch (KeyStoreException e) {

e.printStackTrace();

} catch (CertificateException e) {

e.printStackTrace();

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

2.然后就是生成key了

try {

KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias,

KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)

.setCertificateSubject(new X500Principal("CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US"))

.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)

.setBlockModes(KeyProperties.BLOCK_MODE_CBC)

.setKeySize(2048)

.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)

.setRandomizedEncryptionRequired(false)

.build();

KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE);

generator.initialize(spec);

generator.generateKeyPair();

} catch (InvalidAlgorithmParameterException e) {

e.printStackTrace();

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (NoSuchProviderException e) {

e.printStackTrace();

}

Android 4.3 - 5.1

算法采用 RSA/ECB/PKCS1Padding,随机生成2048位RSA key和iv,key存储在KeyStore中,设置alias,iv存储在SharedPreferences中。需要加解密的时候通过alias从KeyStore中取key,从SharedPreferences中取iv。

Calendar endDate = Calendar.getInstance();

endDate.add(Calendar.YEAR, 10);

try {

KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(mContext.getApplicationContext())

.setAlias(alias)

.setSubject(new X500Principal("CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US"))

.setSerialNumber(BigInteger.ONE)

.setStartDate(Calendar.getInstance().getTime())

.setEndDate(endDate.getTime())

.setKeySize(2048)

.build();

KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA, ANDROID_KEY_STORE);

generator.initialize(spec);

generator.generateKeyPair();

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (NoSuchProviderException e) {

e.printStackTrace();

} catch (InvalidAlgorithmParameterException e) {

e.printStackTrace();

}

数据加密

try {

Key key = mKeyStore.getKey(alias, null);

if (null != key) {

//取出密钥

PublicKey publicKey = mKeyStore.getCertificate(alias).getPublicKey();

Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION); cipher.init(Cipher.ENCRYPT_MODE, publicKey);

return cipher.doFinal(data);

} else {

Log.e("KeyStoreUtils", "key==null , 没找到私钥");

}

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (InvalidKeyException e) {

e.printStackTrace();

} catch (UnrecoverableEntryException e) {

e.printStackTrace();

} catch (NoSuchPaddingException e) {

e.printStackTrace();

} catch (KeyStoreException e) {

e.printStackTrace();

} catch (BadPaddingException e) {

e.printStackTrace();

} catch (IllegalBlockSizeException e) {

e.printStackTrace();

}

数据解密

try {

PrivateKey privateKey = (PrivateKey) mKeyStore.getKey(alias, null);

Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);

cipher.init(Cipher.DECRYPT_MODE, privateKey);

return cipher.doFinal(data);

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (InvalidKeyException e) {

e.printStackTrace();

} catch (UnrecoverableEntryException e) {

e.printStackTrace();

} catch (NoSuchPaddingException e) {

e.printStackTrace();

} catch (KeyStoreException e) {

e.printStackTrace();

} catch (BadPaddingException e) {

e.printStackTrace();

} catch (IllegalBlockSizeException e) {

e.printStackTrace();

}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐