如何在 android 应用程序上存储 RSA 私钥
How to store RSA Private Key on android app
我确实看过这个 post:Cannot generate RSA private Key on Android 但它对我不起作用。
我的想法是使用 RSA 加密来加密访问令牌并将私钥存储在设备上。我已经使用 RSA 成功加密了令牌,但我不知道存储此密钥的最佳位置。我尝试使用 KeyStore 存储它,但是我对此知之甚少,无法调试它为什么不起作用。不断收到错误:java.security.UnrecoverableKeyException:不匹配。
我的钥匙确实匹配,但同样,我不知道有什么问题,因为我对此了解不够。我正在使用 setEntry 并以奇怪而美妙的方式存储私钥,我敢肯定,如果它有效,返回时就不会是同一个密钥。
存储此私钥的最佳方式是什么?存储在哪里???
我不是安全专家,所以如果我宁愿使用 AES,我将不胜感激任何对此的建议?
我的代码在下面,我只使用 1 activity。
package com.example.rsatest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.LoadStoreParameter;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.ProtectionParameter;
import java.security.KeyStore.SecretKeyEntry;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.DropBoxManager.Entry;
import android.util.Base64;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends Activity {
String keyStoreFile;
Key privateKey = null;
boolean isUnlocked = false;
KeyStore keyStore = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
keyStoreFile = this.getFilesDir() + "/bpstore.keystore";
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
startActivity(new Intent("android.credentials.UNLOCK"));
isUnlocked = true;
} else {
startActivity(new Intent("com.android.credentials.UNLOCK"));
isUnlocked = true;
}
} catch (ActivityNotFoundException e) {
Log.e("TAG", "No UNLOCK activity: " + e.getMessage(), e);
isUnlocked = false;
}
if(isUnlocked){
privateKey = GetPrivateKey();
try{
char[] pw =("123").toCharArray();
keyStore = createKeyStore(this,keyStoreFile, pw);
PasswordProtection keyPassword = new PasswordProtection("pw-secret".toCharArray());
SecretKey sk = new SecretKey() {
@Override
public String getFormat() {
// TODO Auto-generated method stub
return privateKey.getFormat();
}
@Override
public byte[] getEncoded() {
// TODO Auto-generated method stub
return privateKey.getEncoded();
}
@Override
public String getAlgorithm() {
// TODO Auto-generated method stub
return privateKey.getAlgorithm();
}
};
System.out.println(sk.getEncoded());
System.out.println(privateKey.getEncoded());
KeyStore.SecretKeyEntry ent = new SecretKeyEntry(sk);
keyStore.setEntry("pk", ent, keyPassword);
keyStore.store(new FileOutputStream(keyStoreFile), pw);
KeyStore keyStore2;
keyStore2 = KeyStore.getInstance("BKS");
keyStore2.load(new FileInputStream(keyStoreFile), pw);
KeyStore.Entry entry = keyStore2.getEntry("pk", keyPassword);
KeyStore.SecretKeyEntry entOut = (KeyStore.SecretKeyEntry)entry;
}catch(Exception ex){
System.out.println("Error: " + ex.toString());
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private KeyStore createKeyStore(Context context, String fileName, char[] pw) throws Exception {
System.out.println("[DIR]:" + fileName);
File file = new File(fileName);
keyStore = KeyStore.getInstance("BKS");
if (file.exists())
{
keyStore.load(new FileInputStream(file), pw);
} else
{
keyStore.load(null, null);
keyStore.store(new FileOutputStream(fileName), pw);
}
return keyStore;
}
private Key GetPrivateKey(){
String theTestText = "This is just a simple test!";
Key publicKey = null;
Key privateKey = null;
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
} catch (Exception e) {
Log.e("", "RSA key pair error");
}
// Encode the original data with RSA private key
byte[] encodedBytes = null;
try {
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.ENCRYPT_MODE, privateKey);
encodedBytes = c.doFinal(theTestText.getBytes());
} catch (Exception e) {
Log.e("", "RSA encryption error");
}
// Decode the encoded data with RSA public key
byte[] decodedBytes = null;
try {
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.DECRYPT_MODE, publicKey);
decodedBytes = c.doFinal(encodedBytes);
} catch (Exception e) {
Log.e("", "RSA decryption error");
}
return privateKey;
}
}
提前致谢,
沃伦
我们没有尝试将 RSA 私钥添加到密钥库,而是最终使用 AES 并使用密码对其进行包装。我们还为我们的 Android 项目添加了 ProGuard,以增加反编译 APK 的难度。
感谢 Maarten Bodewes 的回答和帮助。
That other post was a pretty specific error. It didn't have the correct tags so everybody missed it. About your code; why are you trying to store an asymmetric key as a symmetric key (SecretKey)? That will certainly not work. Note that the Java keystore interface is pretty much aimed at storing keys + certificates. You may want to use another storing method for just RSA private keys (e.g. wrap them yourself using Cipher).
我确实看过这个 post:Cannot generate RSA private Key on Android 但它对我不起作用。
我的想法是使用 RSA 加密来加密访问令牌并将私钥存储在设备上。我已经使用 RSA 成功加密了令牌,但我不知道存储此密钥的最佳位置。我尝试使用 KeyStore 存储它,但是我对此知之甚少,无法调试它为什么不起作用。不断收到错误:java.security.UnrecoverableKeyException:不匹配。
我的钥匙确实匹配,但同样,我不知道有什么问题,因为我对此了解不够。我正在使用 setEntry 并以奇怪而美妙的方式存储私钥,我敢肯定,如果它有效,返回时就不会是同一个密钥。
存储此私钥的最佳方式是什么?存储在哪里???
我不是安全专家,所以如果我宁愿使用 AES,我将不胜感激任何对此的建议?
我的代码在下面,我只使用 1 activity。
package com.example.rsatest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.LoadStoreParameter;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.ProtectionParameter;
import java.security.KeyStore.SecretKeyEntry;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.DropBoxManager.Entry;
import android.util.Base64;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends Activity {
String keyStoreFile;
Key privateKey = null;
boolean isUnlocked = false;
KeyStore keyStore = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
keyStoreFile = this.getFilesDir() + "/bpstore.keystore";
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
startActivity(new Intent("android.credentials.UNLOCK"));
isUnlocked = true;
} else {
startActivity(new Intent("com.android.credentials.UNLOCK"));
isUnlocked = true;
}
} catch (ActivityNotFoundException e) {
Log.e("TAG", "No UNLOCK activity: " + e.getMessage(), e);
isUnlocked = false;
}
if(isUnlocked){
privateKey = GetPrivateKey();
try{
char[] pw =("123").toCharArray();
keyStore = createKeyStore(this,keyStoreFile, pw);
PasswordProtection keyPassword = new PasswordProtection("pw-secret".toCharArray());
SecretKey sk = new SecretKey() {
@Override
public String getFormat() {
// TODO Auto-generated method stub
return privateKey.getFormat();
}
@Override
public byte[] getEncoded() {
// TODO Auto-generated method stub
return privateKey.getEncoded();
}
@Override
public String getAlgorithm() {
// TODO Auto-generated method stub
return privateKey.getAlgorithm();
}
};
System.out.println(sk.getEncoded());
System.out.println(privateKey.getEncoded());
KeyStore.SecretKeyEntry ent = new SecretKeyEntry(sk);
keyStore.setEntry("pk", ent, keyPassword);
keyStore.store(new FileOutputStream(keyStoreFile), pw);
KeyStore keyStore2;
keyStore2 = KeyStore.getInstance("BKS");
keyStore2.load(new FileInputStream(keyStoreFile), pw);
KeyStore.Entry entry = keyStore2.getEntry("pk", keyPassword);
KeyStore.SecretKeyEntry entOut = (KeyStore.SecretKeyEntry)entry;
}catch(Exception ex){
System.out.println("Error: " + ex.toString());
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private KeyStore createKeyStore(Context context, String fileName, char[] pw) throws Exception {
System.out.println("[DIR]:" + fileName);
File file = new File(fileName);
keyStore = KeyStore.getInstance("BKS");
if (file.exists())
{
keyStore.load(new FileInputStream(file), pw);
} else
{
keyStore.load(null, null);
keyStore.store(new FileOutputStream(fileName), pw);
}
return keyStore;
}
private Key GetPrivateKey(){
String theTestText = "This is just a simple test!";
Key publicKey = null;
Key privateKey = null;
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
} catch (Exception e) {
Log.e("", "RSA key pair error");
}
// Encode the original data with RSA private key
byte[] encodedBytes = null;
try {
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.ENCRYPT_MODE, privateKey);
encodedBytes = c.doFinal(theTestText.getBytes());
} catch (Exception e) {
Log.e("", "RSA encryption error");
}
// Decode the encoded data with RSA public key
byte[] decodedBytes = null;
try {
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.DECRYPT_MODE, publicKey);
decodedBytes = c.doFinal(encodedBytes);
} catch (Exception e) {
Log.e("", "RSA decryption error");
}
return privateKey;
}
}
提前致谢, 沃伦
我们没有尝试将 RSA 私钥添加到密钥库,而是最终使用 AES 并使用密码对其进行包装。我们还为我们的 Android 项目添加了 ProGuard,以增加反编译 APK 的难度。
感谢 Maarten Bodewes 的回答和帮助。
That other post was a pretty specific error. It didn't have the correct tags so everybody missed it. About your code; why are you trying to store an asymmetric key as a symmetric key (SecretKey)? That will certainly not work. Note that the Java keystore interface is pretty much aimed at storing keys + certificates. You may want to use another storing method for just RSA private keys (e.g. wrap them yourself using Cipher).