Java 如何在Android中使用自签名SSL证书

Java 如何在Android中使用自签名SSL证书,java,android,ssl,https,android-networking,Java,Android,Ssl,Https,Android Networking,这件事已经困扰我好几天了。我已经阅读了很多关于整个问题的其他问题,但仍然无法继续 我创建了一个简单的测试应用程序,只是为了在Android上测试SSL。该应用程序只有一个按钮,单击该按钮时,该应用程序会尝试通过SSL加密连接将“Hello World”发送到我的测试服务器,然后该服务器会使用完全相同的短语进行响应 首先,我使用openssl为我的服务器创建了一个测试密钥和测试证书。然后我一直在按照中显示的说明进行操作。我直接从Bouncy Castle的网站上获得了Bouncy Castle提供

这件事已经困扰我好几天了。我已经阅读了很多关于整个问题的其他问题,但仍然无法继续

我创建了一个简单的测试应用程序,只是为了在Android上测试SSL。该应用程序只有一个按钮,单击该按钮时,该应用程序会尝试通过SSL加密连接将“Hello World”发送到我的测试服务器,然后该服务器会使用完全相同的短语进行响应

首先,我使用openssl为我的服务器创建了一个测试密钥和测试证书。然后我一直在按照中显示的说明进行操作。我直接从Bouncy Castle的网站上获得了Bouncy Castle提供商,创建了一个可信的密钥库,如疯狂鲍勃的博客所示,我相信在这一点上一切都是正确的

当我试图运行我的代码时,我得到了异常“IOException:密钥存储的错误版本”。然后我在StackOverflow上发现。有人建议我应该尝试使用更老的Bouncy Castle提供者,而不是最新的bcprov-jdk15on-147.jar。我考虑到了这一点,实际上最终尝试了从jdk13-146到jdk16-146的每一个bcprovider。但每次我都会收到同样的“IoException:密钥存储的错误版本”例外

然后我在StackOverflow上发现了类似的问题。有人设法通过使用512位大小的密钥而不是1024位大小的密钥来消除该异常。嗯,我试了一下,什么也没做,但还是一样的例外

所以我现在在这里,想知道下一步该做什么。我的想法和谷歌搜索结果都快用完了

我的web代码是crazy bob代码的1对1副本,除此之外,应用程序只有只处理按钮的activity类。我试图在API级别7上实现这一点

任何帮助都将不胜感激。谢谢。

当我试图请求EWS时也是如此。你可以参考和下载,然后像我的答案一样修改它。希望这有帮助

更新
以下命令对我有效(我大约2个月前尝试过):

您可以看到,我使用了bcprov-jdk16-145.jar和openssl库。你可以试试。
创建密钥库的另一个工具:

2个选项:

  • 您可以按照自己的方式创建自己的密钥存储,我已经这样做了,下面是我存储的代码中的说明(因为让它工作起来非常耗时):

    要生成PKS,请执行以下操作:

  • 在IIS7中创建证书,然后导出为pfx。请遵循有关SelfSSL的说明: 1a。下载工具: 1b。Run:SelfSSL/N:CN=mydomainname/V:1000/S:1/P:8081 我在服务器上使用端口8181 1c。从IIS管理器导出到cert.pfx
  • 在SSL中运行命令行以将文件转换为X.509: openssl pkcs12-in C:\cert.pfx-out C:\cert.cer-nodes
  • 编辑文件并删除除------开始。。。。结束证书------重要!当我得到适当数量的破折号并将标记和数据放在单独的行上时,它就开始工作了
  • 使用键盘工具。C:\Java\JDK\bcprov.jar单独下载 C:\Users>keytool-import-v-trustcacerts-alias key\u alias-file C:\cert.cer-keystore C:\mystore.bks-storetype bks-provider org.bouncycastle.jce.provider.BouncyCastleProvider-provider路径C:\Java\JDK\bcprov.jar-storepass 123456
  • 创建信任所有密钥库并忘记所有这些。基本上,您可以无错误地使用任何SSL。只要在生产中禁用它,如果你真的在乎的话。下面是我用来准备SSL客户端的代码(假设您使用ApacheHTTP客户端)


  • 我也遇到了同样的情况,为了解决这个问题,我从R4j引用的同一篇博文()中获得了帮助。涉及的步骤如下:

  • 创建自定义信任库:我使用Portecle创建密钥库,并将公钥证书从服务器导入其中
  • 使用密钥对创建自定义密钥库:keytool-genkeypair-alias sample-keyalg RSA-sigalg SHA1withRSA-dname“CN=Nazgul,OU=sautch,O=Sauron Enterprises,L=Mordor,ST=Middle Earth,C=ME”—密钥传递welcome123-有效期365-存储类型pkcs12-密钥库g:\Mordor_key\u store.pfx-存储传递welcome123-密钥大小2048
  • 然后,您可以按照内尔科夫的博客中所述使用它们。您可能还需要创建自己的自定义AbstractVerifier,以防您遇到为abc.com颁发证书而验证者拒绝www.abc.com的情况
  • 最后,要创建安全的HTTPClient,您可以执行以下操作:

            public static DefaultHttpClient getSecureHttpClient(){
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        SSLContext sslContext = null;
        try {
            sslContext = createSslContext(true);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        final X509HostnameVerifier delegate = new BrowserCompatHostnameVerifier();
        MySSLSocketFactory socketFactory = new MySSLSocketFactory(sslContext, delegate);
        schemeRegistry.register(new Scheme("https", socketFactory, 443));
    
        DefaultHttpClient client = new DefaultHttpClient();
        HttpParams params = client.getParams();
        client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
                schemeRegistry), params){
            protected HttpParams determineParams(HttpRequest req) {
                HttpParams params = req.getParams(); // req is an HttpRequest object
                HttpConnectionParams.setSoTimeout(params, 60000);
                HttpConnectionParams.setConnectionTimeout(params, 60000);
                return params;
            }
        };
    
        return client;
    }
    

  • 关于我选择的详细原因,您可以参考本文。

    如果您将目标API移动到10或14左右,它是否开始工作?在旧的API级别上工作时,在新的API级别上测试并不是一个坏主意,只是为了确保它不存在兼容性问题。我需要为我的Android brain tree项目创建“.pem”文件。我安装了openssl并运行以下cmd:openssl>s|u client-connect$2>&1 |\sed-ne'/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'>mycert.pem,但我在s|u client中遇到错误。请帮帮我。我从疯狂鲍勃的博客中得到了这个命令。谢谢你的链接,但仍然无法克服“密钥存储错误版本”的异常。我不确定我是否真的了解你在第一行中所做的事情,因为在我看来,你从来没有使用过你在那里创建的PEM。你能解释一下吗?否则,您的解决方案看起来与我尝试过的非常相似。我已经尝试过bcprov-jdk16-145.jar(以及其他版本)和openssl。我建议您检查您的证书文件,因为我与您的问题相同。然后我尝试使用另一个文件,它成功了。如果我使用“信任所有”选项,是否意味着我的应用程序是唯一信任所有站点的应用程序?换句话说,我只是想确保它不会以任何方式影响手机上的其他应用程序。我的应用程序正在使用的URL是硬编码的,因为它从不更改,因此允许应用程序信任所有站点可能是安全的
    private HttpClient getHttpClient()
    {
        HttpParams params = new BasicHttpParams();
    
        //Set main protocol parameters
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
        HttpProtocolParams.setUseExpectContinue(params, true);
    
        // Turn off stale checking.  Our connections break all the time anyway, and it's not worth it to pay the penalty of checking every time.
        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        // FIX v2.2.1+ - Set timeout to 30 seconds, seems like 5 seconds was not enough for good communication
        HttpConnectionParams.setConnectionTimeout(params, 30 * 1000);
        HttpConnectionParams.setSoTimeout(params, 30 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);
    
        // Don't handle redirects -- return them to the caller.  Our code often wants to re-POST after a redirect, which we must do ourselves.
        HttpClientParams.setRedirecting(params, false);
    
        // Register our own "trust-all" SSL scheme
        SchemeRegistry schReg = new SchemeRegistry();
        try
        {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
    
            TrustAllSSLSocketFactory sslSocketFactory = new TrustAllSSLSocketFactory(trustStore);
            sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
            Scheme sslTrustAllScheme = new Scheme("https", sslSocketFactory, 443);
            schReg.register(sslTrustAllScheme);
        }
        catch (Exception ex)
        {
            LogData.e(LOG_TAG, ex, LogData.Priority.None);
        }
    
        ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg);
        return new DefaultHttpClient(conMgr, params);
    }
    
            public static DefaultHttpClient getSecureHttpClient(){
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        SSLContext sslContext = null;
        try {
            sslContext = createSslContext(true);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        final X509HostnameVerifier delegate = new BrowserCompatHostnameVerifier();
        MySSLSocketFactory socketFactory = new MySSLSocketFactory(sslContext, delegate);
        schemeRegistry.register(new Scheme("https", socketFactory, 443));
    
        DefaultHttpClient client = new DefaultHttpClient();
        HttpParams params = client.getParams();
        client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
                schemeRegistry), params){
            protected HttpParams determineParams(HttpRequest req) {
                HttpParams params = req.getParams(); // req is an HttpRequest object
                HttpConnectionParams.setSoTimeout(params, 60000);
                HttpConnectionParams.setConnectionTimeout(params, 60000);
                return params;
            }
        };
    
        return client;
    }