提取证书 - 未知密码

时间:2013-04-21 17:38:29

标签: android certificate x509certificate keystore keychain

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();
}

我已经检查过证书和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>

修改

现在我可以启动Intent,但应用程序会在&#34; Extract Certificate&#34;中提出密码。窗口,我在创建证书时没有设置任何密码。有关于此的任何提示吗?

我曾尝试使用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();

1 个答案:

答案 0 :(得分:1)

您的活动上下文可能会在执行savePrivateKeyInKeyChain()时消失。我猜测你的函数是通过后台线程的回调执行的,或者它是在活动的生命周期准备好它的上下文之前执行的。

您可以通过调试该函数的getContext()结果来轻松检查是否属于这种情况。如果它正在给null,那就是你的问题。