Android生成可导入keystore的秘钥文件

Android中的keystore可以帮我们保管秘钥,调用其方法可以进行加解密 签名等操作,其支持直接生成keystore,也支持外部导入,下面介绍如何生成一个可导入的外部keystore文件:

/**
     * @param password  密码
     * @param issuerStr 颁发机构信息
     * @param subjectStr 使用者信息
     * @param certificateCRL 颁发地址
     * @return
     */
    public Map<String, byte[]> createCert(Context context, String alias, String password,
                                                 String issuerStr, String subjectStr, String certificateCRL) {
        Log.d(TAG,"createCert : "+alias);
        Map<String, byte[]> result = new HashMap<String, byte[]>();
        ByteArrayOutputStream out = null;
        try {
            //  生成JKS证书
            //  KeyStore keyStore = KeyStore.getInstance("JKS");
            //  标志生成PKCS12证书
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(null, null);
            KeyPair keyPair = getKey();
            //  issuer与 subject相同的证书就是CA证书
            Certificate cert = generateCertificateV3(issuerStr, subjectStr,  keyPair, result, certificateCRL, null);
            // cretkey随便写,标识别名
            keyStore.setKeyEntry(alias,  keyPair.getPrivate(),  password.toCharArray(),  new Certificate[] { cert });
            out = new ByteArrayOutputStream();
            cert.verify(keyPair.getPublic());
            keyStore.store(out, password.toCharArray());
            byte[] keyStoreData = out.toByteArray();
            result.put("keyStoreData", keyStoreData);
            Log.d(TAG,"keyStoreData= "+new String(Base64.encode(keyStoreData, Base64.DEFAULT)));
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
        }
        return result;
    }

    private KeyPair getKey() throws NoSuchAlgorithmException {
        // 密钥对 生成器,RSA算法 生成的  提供者是 BouncyCastle
        KeyPairGenerator generator = null;
        KeyPair keyPair = null;
        generator = KeyPairGenerator.getInstance("RSA",new BouncyCastleProvider());
        generator.initialize(2048);  // 密钥长度 2048
        // 证书中的密钥 公钥和私钥
        keyPair = generator.generateKeyPair();
        return keyPair;
    }

    /**
     * @param issuerStr
     * @param subjectStr
     * @param keyPair
     * @param result
     * @param certificateCRL
     * @param extensions
     * @return
     */
    public Certificate generateCertificateV3(String issuerStr, String subjectStr, KeyPair keyPair, Map<String, byte[]> result,
                                                    String certificateCRL, List<Extension> extensions) {
        Log.d(TAG,"generateCertificateV3");
        ByteArrayInputStream bout = null;
        X509Certificate cert = null;
        try {
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            Date notBefore = new Date();
            Calendar rightNow = Calendar.getInstance();
            rightNow.setTime(notBefore);
            // 日期加10年
            rightNow.add(Calendar.YEAR, 10);
            Date notAfter = rightNow.getTime();
            // 证书序列号
            BigInteger serial = BigInteger.probablePrime(256, new Random());
            X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
                    new X500Name(issuerStr), serial, notBefore, notAfter,new X500Name(subjectStr), publicKey);
            JcaContentSignerBuilder jBuilder = new JcaContentSignerBuilder( "SHA1withRSA");
            SecureRandom secureRandom = new SecureRandom();
            jBuilder.setSecureRandom(secureRandom);
            ContentSigner singer = jBuilder.setProvider(  new BouncyCastleProvider()).build(privateKey);
            // 分发点
            ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier( "2.5.29.31");
            GeneralName generalName = new GeneralName( GeneralName.uniformResourceIdentifier, certificateCRL);
            GeneralNames seneralNames = new GeneralNames(generalName);
            DistributionPointName distributionPoint = new DistributionPointName( seneralNames);
            DistributionPoint[] points = new DistributionPoint[1];
            points[0] = new DistributionPoint(distributionPoint, null, null);
            CRLDistPoint cRLDistPoint = new CRLDistPoint(points);
            builder.addExtension(cRLDistributionPoints, true, cRLDistPoint);
            // 用途
            ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier( "2.5.29.15");
            // | KeyUsage.nonRepudiation | KeyUsage.keyCertSign
            builder.addExtension(keyUsage, true, new KeyUsage( KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
            // 基本限制 X509Extension.java
            ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
            builder.addExtension(basicConstraints, true, new BasicConstraints(true));
            // privKey:使用自己的私钥进行签名,CA证书
            if (extensions != null){
                for (Extension ext : extensions) {
                    builder.addExtension(
                            new ASN1ObjectIdentifier(ext.getOid()),
                            ext.isCritical(),
                            ASN1Primitive.fromByteArray(ext.getValue()));
                }
            }
            X509CertificateHolder holder = builder.build(singer);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            bout = new ByteArrayInputStream(holder.toASN1Structure() .getEncoded());
            cert = (X509Certificate) cf.generateCertificate(bout);
            byte[] certBuf = holder.getEncoded();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            // 证书数据
            result.put("certificateData", certBuf);
            Log.d(TAG,"certificateData= "+new String(Base64.encode(certBuf, Base64.DEFAULT)));
            //公钥
            result.put("publicKey", publicKey.getEncoded());
            Log.d(TAG,"publicKey= "+new String(Base64.encode(publicKey.getEncoded(), Base64.DEFAULT)));
            //私钥
            result.put("privateKey", privateKey.getEncoded());
            Log.d(TAG,"privateKey= "+new String(Base64.encode(privateKey.getEncoded(), Base64.DEFAULT)));
            //证书有效开始时间
            result.put("notBefore", format.format(notBefore).getBytes("utf-8"));
            Log.d(TAG,"notBefore= "+new String(Base64.encode(format.format(notBefore).getBytes("utf-8"), Base64.DEFAULT)));
            //证书有效结束时间
            result.put("notAfter", format.format(notAfter).getBytes("utf-8"));
            Log.d(TAG,"notAfter= "+new String(Base64.encode(format.format(notAfter).getBytes("utf-8"), Base64.DEFAULT)));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bout != null) {
                try {
                    bout.close();
                } catch (IOException e) {
                }
            }
        }
        return cert;
    }

里面的Extension是自建的实体类,如下

public class Extension {
    private String oid;
    private boolean critical;
    private byte[] value;

    public String getOid() {
        return oid;
    }
    public byte[] getValue() {
        return value;
    }
    public boolean isCritical() {
        return critical;
    }
}

需要导入org.bouncycastle包,Android studio在manifest中加入

implementation group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.62'

如不可使用可直接下载资源文件中的jar包放入lib中,gradle版本不能小于3.3.2,否则编译不通过

使用方法

File file = new File("/sdcard/test.p12");
String issuerStr = "CN=China,OU=Software,O=Test,L=Beijing,ST=Beijing,C=CN";
String subjectStr = "CN=China,OU=Software,O=Test,L=Beijing,ST=Beijing,C=CN";
String certificateCRL  = "https://test.cn";
Map<String, byte[]> result = createCert(context,"Test","123456", issuerStr, subjectStr, certificateCRL);
if(!result.isEmpty()){
    FileOutputStream outPutStream = null; // ca.jks
    try {
        outPutStream = new FileOutputStream(file);
        outPutStream.write(result.get("keyStoreData"));
        outPutStream.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

生成keystore文件了,那么如何导入到系统中呢,接着往下看

public void loadPKCS12(File keyStoreFile,String password){
        Log.d(TAG,"loadPKCS12");
        if (!keyStoreFile.exists()) {
            Log.e(TAG,keyStoreFile.getAbsolutePath()+" does not exist");
            return ;
        }
        KeyStore fileKeyStore = null;
        try (InputStream in = new FileInputStream(keyStoreFile)) {
            fileKeyStore = KeyStore.getInstance("PKCS12");
            fileKeyStore.load(in, password.toCharArray());

            Enumeration<String> aliases = fileKeyStore.aliases();
            while (aliases.hasMoreElements()) {
                String alias = aliases.nextElement();
                Log.d(TAG,"Load Keystore : "+alias);
                //加载进keystore
                KeyStore.Entry entry = fileKeyStore.getEntry(alias, null);
                keyStore.setEntry(alias, entry, null);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (UnrecoverableEntryException e) {
            e.printStackTrace();
        }
    }

只需传入之前生成的p12文件,和密码(123456),就可以将此秘钥文件加载如系统

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值