Android SSL单双向认证逻辑学习笔记

2019-09-29  本文已影响0人  XBYoung

头一次听说要做双向认证的时候一脸懵逼,不清楚啥玩意是双向认证,破APP干嘛要认证,有啥重要信息吗,单向行不行,好吧你说双向就双向,赶紧一波学习。

先记录下啥是单向,啥是双向

有些运营会提供多个证书,刚开始有点懵逼,运营提供了一个公钥一个公钥一个中间件证书,公钥私钥好理解,直接套用SSL流程,中间件证书一段时间内懵逼,如果公钥私钥由官方认证的CA机构签发,那么中间件证书可以不要,Android集成主流CA公钥证书,HTTPS通信中会默认使用,之所有很多App还是集成中间件证书是因为用户可以手动关闭这些证书认证,集成中间件证书可以防止该类情况(设置搜索“信任的凭证“查看已有的证书)。

上面提到第二步Server会向App发送他自己的公钥,这里可能被贼人窃取,虽然Server保证信任通过他自己的公钥加密后的数据,但是这人是谁~可能是隔壁老王,用他自己的公钥给App,用拦截下的公钥给Server写信(狗东西看了就看了还要改),为了防止隔壁老王窃取公钥伪装自己发消息,CA就有用了,再给公钥加个密,老王即使解了密,看了Server的公钥(玛德有被看了),但是,能伪装,能改吗,不能,因为老王没有CA的私钥,他即使还是牛逼到偷看了信息,但是已经没有机会再修改信息,如果用了自己的私钥加密给了App,App也解不开他那套,自然认证不过。那么问题来了,如果CA私钥也被老王窃取了怎么办???凉拌,这么牛的老王认命。

元素

 public SSLSocketFactory getSocketFactory(
            AssetManager assetManager,
            final String caCrtFile,
            final String crtFile,
            final String keyFile,
            final String password)
            throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        X509Certificate caCert = null;
        X509Certificate clientCert = null;

        BufferedInputStream caBis = new BufferedInputStream(assetManager.open(caCrtFile));
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        int i = 0;
        while (caBis.available() > 0) {
            caCert = (X509Certificate) certificateFactory.generateCertificate(caBis);
            Log.d("X509Certificate", "" + i++);
        }
        caBis = new BufferedInputStream(assetManager.open(crtFile));
        while (caBis.available() > 0) {
            clientCert = (X509Certificate) certificateFactory.generateCertificate(caBis);
        }
        // load client private key
        PEMParser pemParser = new PEMParser(new InputStreamReader(assetManager.open(keyFile)));
        Object object = pemParser.readObject();
        PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter()
                .setProvider("BC");
        KeyPair key;
        if (object instanceof PEMEncryptedKeyPair) {
            Log.e("TSPAPP", "Encrypted key - we will use provided password");
            key = converter.getKeyPair(((PEMEncryptedKeyPair) object)
                    .decryptKeyPair(decProv));
        } else {
            Log.e("TSPAPP", "Unencrypted key - no password needed");
            key = converter.getKeyPair((PEMKeyPair) object);
        }
        pemParser.close();

        KeyStore trustManagerFactoryKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        Log.d("hashcode 1", trustManagerFactoryKeyStore.hashCode()+"");

        trustManagerFactoryKeyStore.load(null, null);
        trustManagerFactoryKeyStore.setCertificateEntry("ca-certificate", caCert);

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
        trustManagerFactory.init(trustManagerFactoryKeyStore);

        KeyStore keyManagerFactoryKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        Log.d("hashcode 2", keyManagerFactoryKeyStore.hashCode()+"");
        keyManagerFactoryKeyStore.load(null, null);
        keyManagerFactoryKeyStore.setCertificateEntry("certificate", clientCert);
        keyManagerFactoryKeyStore.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[]{clientCert});

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyManagerFactoryKeyStore, password.toCharArray());

        SSLContext context = SSLContext.getInstance("TLSv1.2");
        context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
        return context.getSocketFactory();
    }

相关概念仍有问题的可以直接参考谷歌官方文档

上一篇 下一篇

猜你喜欢

热点阅读