我是Android平台上的新手,来自.NET世界。我需要在我的应用程序中编写一个TCP/SSL客户端类,该类使用某些Java服务器发送/接收文本消息。我还需要在该通信中使用服务器公共证书(.cer文件)。在 C# 中,我有 SSLStream 类来完成所有工作,以及很多示例。但是对于Android(Lolipop),我找不到任何关于这个主题的好例子,尤其是在没有http协议的情况下。任何提示将不胜感激。
在Android中创建SSL连接的基本步骤:
第 1 步:获取您已经拥有的服务器的公钥(.cert 文件)。
第 2 步:通过充气罐创建密钥库
下面是命令:
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
验证证书是否已正确导入到密钥库中:
keytool -list -keystore "res/raw/myKeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
应输出整个链:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
现在,您可以在 res/raw/下将密钥库作为原始资源复制到 android 应用程序中
第 3 步:
像下面这样创建 Https客户端,并仅使用此客户端查询您的服务:
public class HttpsClient extends DefaultHttpClient {
final Context context;
public HttpsClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(
R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted
// certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is
// responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
上述情况适用于通过http的连接,如果您需要在没有http的情况下进行连接,则密钥库过程保持不变,并且需要使用套接字来打开和关闭连接:
String keyStorePath = "absolute path to your JKS keystore file";
String keyStorePass = "keystore password";
System.setProperty("javax.net.ssl.keyStore", keyStorePath);
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket serverSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(port_number);
while (true) {
new ClientThread((SSLSocket) serverSocket.accept()).start();
}
KOTIOS的答案有效!
对于 SSL 套接字(不是 http)
使用此代码:
Socket socket = null;
SSLContext context = null;
char[] passphrase = "mysecret".toCharArray();
try{
KeyStore keystore = KeyStore.getInstance("BKS");
keystore.load(this.getApplication().getResources().openRawResource(R.raw.mykeystore), passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
context = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init(null, trustManagers, null);
}catch (Exception e){
e.printStackTrace();
}
SSLSocketFactory sf = context.getSocketFactory();
socket = (SSLSocket) sf.createSocket(InetAddress.getByName(IP), DEFAULT_PORT);
并像普通插座一样使用此插座。