您的位置:首页 > 移动开发 > Android开发

Android 采用keyStore的方式非对称加密,配合Rxjava2更好用

2017-11-29 11:32 603 查看
加密的代码如下

public class RxSecureStorage {

private static final String AndroidKeyStore = "AndroidKeyStore";
private Context context;
private String alias;
private KeyStore keyStore;
private RxSharedPreferences sharedPreferences;

public RxSecureStorage(Context context, String alias) {
this.context = context.getApplicationContext();
this.alias = alias;
SharedPreferences prefs =
context.getSharedPreferences(
String.format("%s-%s", context.getPackageName(), alias), Context.MODE_PRIVATE);
this.sharedPreferences = RxSharedPreferences.create(prefs);
}

public static RxSecureStorage create(Context context, String alias) {
return new RxSecureStorage(context, alias);
}

private void initIfNecessary() throws Exception {
if (keyStore != null) {
return;
}
try {
keyStore = KeyStore.getInstance(AndroidKeyStore);
keyStore.load(null);
if (!keyStore.containsAlias(alias)) {
// Generate a key pair for encryption
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 30);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context.getApplicationContext())
.setAlias(alias)
.setSubject(new X500Principal("CN=" + alias))
.setSerialNumber(BigInteger.TEN)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", AndroidKeyStore);
kpg.initialize(spec);
kpg.generateKeyPair();
}
} catch (Exception e) {
throw new Exception("Failed to initialize this RxSecureStorage instance.", e);
}
}

public Single<byte[]> encrypt(final byte[] data) {
return Single.fromCallable(
new Callable<byte[]>() {
@Override
public byte[] call() throws Exception {
initIfNecessary();

ByteArrayOutputStream outputStream = null;
CipherOutputStream cipherOutputStream = null;
try {
KeyStore.PrivateKeyEntry privateKeyEntry =
(KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, null);
PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey();

Cipher input = getCipher();
input.init(Cipher.ENCRYPT_MODE, publicKey);

outputStream = new ByteArrayOutputStream();
cipherOutputStream = new CipherOutputStream(outputStream, input);
cipherOutputStream.write(data);
closeQu
e8a8
ietely(cipherOutputStream);

return outputStream.toByteArray();
} catch (Exception e) {
throw new Exception("Failed to encrypt data with alias" + alias, e);
} finally {
closeQuietely(cipherOutputStream);
closeQuietely(outputStream);
}
}
})
.observeOn(Schedulers.computation());
}

public Single<String> encryptString(String text) {
byte[] textBytes;
try {
textBytes = text.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
return Single.error(new Exception("Failed convert text to bytes.", e));
}
return encrypt(textBytes)
.map(
new Function<byte[], String>() {
@Override
public String apply(byte[] encryptedData) throws Exception {
return Base64.encodeToString(encryptedData, Base64.DEFAULT);
}
})
.observeOn(Schedulers.computation());
}

public Single<byte[]> decrypt(final byte[] encryptedData) {
return Single.fromCallable(
new Callable<byte[]>() {
@Override
public byte[] call() throws Exception {
initIfNecessary();

CipherInputStream cipherInputStream = null;
ByteArrayOutputStream bos = null;
try {
KeyStore.PrivateKeyEntry privateKeyEntry =
(KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, null);
PrivateKey privateKey = privateKeyEntry.getPrivateKey();

Cipher output = getCipher();
output.init(Cipher.DECRYPT_MODE, privateKey);

cipherInputStream =
new CipherInputStream(new ByteArrayInputStream(encryptedData), output);
bos = new ByteArrayOutputStream();

byte[] buffer = new byte[512];
int read;
while ((read = cipherInputStream.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}

return bos.toByteArray();
} catch (Exception e) {
throw new Exception("Failed to decrypt data with " + alias, e);
} finally {
closeQuietely(cipherInputStream);
closeQuietely(bos);
}
}
})
.observeOn(Schedulers.computation());
}

public Single<String> decryptString(String encryptedText) {
byte[] textBytes = new byte[0];
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.FROYO) {
textBytes = Base64.decode(encryptedText, Base64.DEFAULT);
}
return decrypt(textBytes)
.map(
new Function<byte[], String>() {
@Override
public String apply(byte[] encryptedData) throws Exception {
return new String(encryptedData, 0, encryptedData.length);
}
})
.observeOn(Schedulers.computation());
}

public Observable<byte[]> getBytes(String name) {
return sharedPreferences
.getString(name)
.asObservable()
.map(
new Function<String, byte[]>() {
@Override
public byte[] apply(String base64Value) throws Exception {
byte[] encryptedValue = Base64.decode(base64Value, Base64.DEFAULT);
return decrypt(encryptedValue).blockingGet();
}
});
}

public Single<Boolean> putBytes(final String name, @Nullable byte[] value) {
if (value == null) {
sharedPreferences.getString(name).delete();
return Single.just(false);
}
return encrypt(value)
.map(
new Function<byte[], Boolean>() {
@Override
public Boolean apply(byte[] encryptedData) throws Exception {
String encryptedString = Base64.encodeToString(encryptedData, Base64.DEFAULT);
sharedPreferences.getString(name).set(encryptedString);
return true;
}
});
}

public Observable<String> getString(String name) {
return sharedPreferences
.getString(name)
.asObservable()
.map(
new Function<String, String>() {
@Override
public String apply(String encryptedValue) throws Exception {
if (encryptedValue == null || encryptedValue.trim().isEmpty()) {
return null;
}
return decryptString(encryptedValue).blockingGet();
}
});
}

public Single<Boolean> putString(final String name, @Nullable String value) {
if (value == null) {
sharedPreferences.getString(name).delete();
return Single.just(false);
}
return encryptString(value)
.map(
new Function<String, Boolean>() {
@Override
public Boolean apply(String encryptedValue) throws Exception {
sharedPreferences.getString(name).set(encryptedValue);
return true;
}
});
}

public void dispose() {
this.context = null;
this.alias = null;
this.keyStore = null;
this.sharedPreferences = null;
}

private static Cipher getCipher() {
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // below android m
// error in android 6: InvalidKeyException: Need RSA private or public key
return Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
} else {
// error in android 5: NoSuchProviderException: Provider not available: AndroidKeyStoreBCWorkaround
return Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidKeyStoreBCWorkaround");
}
} catch (Exception exception) {
throw new RuntimeException("getCipher: Failed to get an instance of Cipher", exception);
}
}

private static void closeQuietely(Closeable c) {
try {
c.close();
} catch (Throwable ignored) {
}
}
}


使用

1,初始化

RxSecureStorage secureStorage =
RxSecureStorage.create(this, "alias_name")


2,加密

secureStorage
.encryptString("string to encrypt")
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
// Use the resulting string
},
error -> {
// Handle error
});


3,解密

secureStorage
.decryptString("9yIfhiwf3eDENxI1XG/XWYZOPc5RH6B9ez9y7I7BtEsig==")
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
// Use the resulting string
},
error -> {
// Handle error
});


4,保存一些隐私数据

secureStorage.putString("key", "hello, world!").subscribe();


获取隐私数据

secureStorage
.getString("key")
.subscribe(
latest -> {
// preference was changed, here's the latest decryped value
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: