で開始するActivity
と、 KeyManager
取得していますjava.lang.NullPointException
public class KeyManager extends Activity implements OnClickListener{
public KeyManager() {
super();
}
public KeyPair createKeyPair(Context c)
{
KeyPairGenerator kpg;
KeyPair kp=null;
try
{
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);//1024 bits
kp = kpg.genKeyPair();
this.savePrivateKeyInKeyChain(kp, c);
this.savePublicKeyInSharedPreferences(kp, c);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return kp;
}
///////////////////////////////////////
//////////// KEY CHAIN ////////////////
///////////////////////////////////////
public void savePublicKeyInSharedPreferences(KeyPair kp, Context c)
{
SharedPreferences sharedPreferences = c.getSharedPreferences("Keys", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
PublicKey pk=kp.getPublic();
byte [] pkEncoded=pk.getEncoded();
Log.i("Public Key", "original encoded:"+pkEncoded);
String publicKeyString=Base64.encodeToString(pkEncoded,false);
Log.i("Public Key", "encodeToString:"+publicKeyString);
editor.putString("public", publicKeyString);
editor.commit();
}
public static void savePrivateKeyInKeyChain (KeyPair kp, Context c) throws CertificateException
{
Intent intent = KeyChain.createInstallIntent();
byte [] cert=this.getCertificateForPrivateKey(kp);
Log.i("CERT",""+cert);
intent.putExtra(KeyChain.EXTRA_CERTIFICATE, cert);
intent.putExtra(KeyChain.EXTRA_PKCS12, kp.getPrivate().getEncoded());
c.startActivity(intent);
}
public static byte [] getCertificateForPrivateKey(KeyPair kp) throws CertificateException
{
X500Name name=new X500Name("CN=" + "setichat" + ", OU=None, O=None L=None, C=None");
BigInteger num=new BigInteger("1");
Date now=new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30);
Date after=new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365*10));
PublicKey pubk=kp.getPublic();
PrivateKey prik = kp.getPrivate();
X509v3CertificateBuilder builder= new X509v3CertificateBuilder(name, num, now, after, name, SubjectPublicKeyInfo.getInstance(pubk.getEncoded()));
byte[] certBytes=null;
try
{
certBytes = builder.build(new JCESigner(prik,"SHA256withRSA")).getEncoded();
} catch (IOException e)
{
e.printStackTrace();
}
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certBytes));
return certificate.getEncoded();
}
public void saveAliasInSharedPreferences(String alias)
{
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("Alias", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("alias", alias);
Log.i("Alias saved", alias);
editor.commit();
}
public String getAliasFromSharedPreferences()
{
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("Alias", Context.MODE_PRIVATE);
String a=sharedPreferences.getString("alias", null);
Log.i("Alias get", a);
return a;
}
public String getPrivateKeyFromAlias()
{
String alias=getAliasFromSharedPreferences();
PrivateKey pk=null;
String result=null;
try
{
pk = KeyChain.getPrivateKey(getApplicationContext(), alias);
byte [] pkEncoded=pk.getEncoded();
result=Base64.encodeToString(pkEncoded,false);
Log.i("Private Key Alias", "encodeToString:"+result);
} catch (KeyChainException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
public boolean hasKeys(Context c)
{
boolean result=false;
SharedPreferences sharedPreferences = c.getSharedPreferences("Alias", Context.MODE_PRIVATE);
String p=sharedPreferences.getString("alias", null);
if(p!=null)
result=true;
return result;
}
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
KeyChain.choosePrivateKeyAlias(this,
new KeyChainAliasCallback() {
public void alias(String alias) {
//Remember the alias selection for future use.
if (alias != null) saveAliasInSharedPreferences(alias);
}
},
null, // List of acceptable key types. null for any
null, // issuer, null for any
null, // host name of server requesting the cert, null if unavailable
-1, // port of server requesting the cert, -1 if unavailable
null); // alias to preselect, null if unavailable
}
public X509Certificate[] getCertificateFromAlias(String alias) throws KeyChainException, InterruptedException
{
X509Certificate[] chain= KeyChain.getCertificateChain(getApplicationContext(), alias);
return chain;
}
}
class JCESigner implements ContentSigner {
private static final AlgorithmIdentifier PKCS1_SHA256_WITH_RSA_OID = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.1.1.11"));
private Signature signature;
private ByteArrayOutputStream outputStream;
public JCESigner(PrivateKey privateKey, String signatureAlgorithm) {
if (!"SHA256withRSA".equals(signatureAlgorithm)) {
throw new IllegalArgumentException("Signature algorithm \"" + signatureAlgorithm + "\" not yet supported");
}
try {
this.outputStream = new ByteArrayOutputStream();
this.signature = Signature.getInstance(signatureAlgorithm);
this.signature.initSign(privateKey);
} catch (GeneralSecurityException gse) {
throw new IllegalArgumentException(gse.getMessage());
}
}
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
if (signature.getAlgorithm().equals("SHA256withRSA")) {
return PKCS1_SHA256_WITH_RSA_OID;
} else {
return null;
}
}
@Override
public OutputStream getOutputStream() {
return outputStream;
}
@Override
public byte[] getSignature() {
try {
signature.update(outputStream.toByteArray());
return signature.sign();
} catch (GeneralSecurityException gse) {
gse.printStackTrace();
return null;
}
}
KeyChain.createInstallIntent()
返される値は次のとおりです。
04-21 18:31:41.054: I/Intent(1645): Intent { act=android.credentials.INSTALL cmp=com.android.certinstaller/.CertInstallerMain }
SettingsFragment.onListItemClick のコードは次のとおりです。
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
CheckedTextView textview = (CheckedTextView)v;
textview.setChecked(!textview.isChecked());
if(position==0)
{
if(textview.isChecked())
{
encrypted=true;
System.out.println("Encrypted true");
}
else
{
encrypted=false;
System.out.println("Encrypted false");
}
}
else if(position==1)
{
if(textview.isChecked())
{
signed=true;
System.out.println("Signed True");
if(!KeyManager.hasKeys(l.getContext())){
KeyManager.createKeyPair(l.getContext());
SeTIKeyUpload upload = new SeTIKeyUpload();
String setiUpload = upload.keyUploadString(l.getContext());
SeTIChatService mService = SeTIChatServiceBinder.getService();
mService.sendMessage(setiUpload);
}
}
else
{
signed=false;
System.out.println("Signed False");
}
}
System.out.println(position+"position"+", encrypted: "+encrypted+", signed: "+signed);
SharedPreferences sharedPreferences = v.getContext().getSharedPreferences("Settings", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean("encrypted", encrypted);
editor.putBoolean("signed", signed);
editor.commit();
}
Certificate と PKCS12 が空でないことを確認したので、Intent は空ではありません。
エラーコンソール:
04-21 17:17:31.524: E/AndroidRuntime(927): FATAL EXCEPTION: main
04-21 17:17:31.524: E/AndroidRuntime(927): java.lang.NullPointerException
04-21 17:17:31.524: E/AndroidRuntime(927): at android.app.Activity.startActivityForResult(Activity.java:3370)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.app.Activity.startActivityForResult(Activity.java:3331)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.app.Activity.startActivity(Activity.java:3566)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.app.Activity.startActivity(Activity.java:3534)
04-21 17:17:31.524: E/AndroidRuntime(927): at es.uc3m.setichat.utils.KeyManager.savePrivateKeyInKeyChain(KeyManager.java:288)
04-21 17:17:31.524: E/AndroidRuntime(927): at es.uc3m.setichat.utils.KeyManager.createKeyPair(KeyManager.java:188)
04-21 17:17:31.524: E/AndroidRuntime(927): at es.uc3m.setichat.activity.SettingsFragment.onListItemClick(SettingsFragment.java:102)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.app.ListFragment$2.onItemClick(ListFragment.java:160)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.widget.AdapterView.performItemClick(AdapterView.java:298)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.widget.AbsListView.performItemClick(AbsListView.java:1100)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.widget.AbsListView$PerformClick.run(AbsListView.java:2749)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.widget.AbsListView$1.run(AbsListView.java:3423)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.os.Handler.handleCallback(Handler.java:725)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.os.Handler.dispatchMessage(Handler.java:92)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.os.Looper.loop(Looper.java:137)
04-21 17:17:31.524: E/AndroidRuntime(927): at android.app.ActivityThread.main(ActivityThread.java:5039)
04-21 17:17:31.524: E/AndroidRuntime(927): at java.lang.reflect.Method.invokeNative(Native Method)
04-21 17:17:31.524: E/AndroidRuntime(927): at java.lang.reflect.Method.invoke(Method.java:511)
04-21 17:17:31.524: E/AndroidRuntime(927): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-21 17:17:31.524: E/AndroidRuntime(927): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-21 17:17:31.524: E/AndroidRuntime(927): at dalvik.system.NativeStart.main(Native Method)
そして、次のように AndroidManifest でクラスを定義しました。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="es.uc3m.setichat"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<application
android:allowBackup="true"
android:icon="@drawable/setichat_icon"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
.
.
.
<activity android:name=".utils.KeyManager"></activity>
</application>
</manifest>
編集:
インテントを起動できるようになりましたが、アプリケーションは「証明書の抽出」ウィンドウでパスワードを要求し、証明書の作成時にパスワードを設定していません。それに関するヒントはありますか?
KeyStore で保存しようとしましたが、パスワードを入力しても違いはありません。
KeyStore ks = KeyStore.getInstance("BKS");
char [] password={'P', 'A', 'S', 'S'};
ks.load(new ByteArrayInputStream(certBytes), password);
ks.setKeyEntry("hostname", kp.getPrivate(), password, new java.security.cert.Certificate[] { certificate });
File keystore = new File("keystore");
FileOutputStream fos = new FileOutputStream(keystore);
ks.store(fos, password);
fos.close();