Android HTTPS detailed

Source: Internet
Author: User
Tags generate ssl certificate how to generate ssl certificate ssl certificate

Foreword recently has an HTTPS related problem need to solve, so take time to learn about the use of Android platform HTTPS, but also see some of the principle of HTTPS, here to share the learning experience.
HTTPS principle HTTPS (Hyper Text Transfer Protocol Secure) is a SSL/TLS-based HTTP that all HTTP data is transmitted on top of the SSL/TLS protocol package. HTTPS protocol is based on the HTTP protocol, the addition of SSL/TLS handshake and data encryption transmission, also belongs to the application layer protocol. So, studying the principle of HTTPS protocol is the ultimate research of SSL/TLS protocol. SSL/TLS protocol function does not use SSL/TLS HTTP communication, is unencrypted communication, all the information is transmitted in plaintext, bringing three major risks: 1. Eavesdropping risk: Third parties can learn the content of the communication. 2. Tamper risk: Third parties may modify the notification content. 3. Impersonation risk: A third party may participate in the communication by impersonating another person. The SSL/TLS protocol is designed to address these three risks and is expected to reach: 1. All information is encrypted and cannot be tapped by third parties. 2. With a calibration mechanism, once tampered with, both sides of the communication will be immediately discovered. 3. Equipped with identity card to prevent identity from being impersonated. Basic operation process of SSL/TLS protocol is the basic idea is to use public key cryptography, that is, the client to the server side of the public key, and then encrypt the information with the public key, the server received ciphertext, with its own private key decryption. But here you need to understand the solution to two problems. 1. How can I ensure that the public key is not tampered with? WORKAROUND: Place the public key in the digital certificate. As long as the certificate is trustworthy, the public key is trustworthy. 2. Public key encryption calculation is too large, how to reduce the elapsed time? WORKAROUND: Every session, the client and server generate a "conversation key" (Session key), which is used to encrypt the information. Because the "conversation key" is symmetric encryption, the operation is very fast, and the server public key is used only to encrypt the "conversation key" itself, which reduces the time spent on cryptographic operations. Therefore, the basic process of the SSL/TLS protocol is this: 1. The client requests and validates the public key from the server side. 2. Both parties negotiate to generate a "dialog key". 3. Both parties use the "dialogue key" for encrypted communication. The first two cloths of the above process, also known as the "handshake phase." Detailed process of the handshake phase
The "handshake phase" involves four communications, and it is important to note that all communication in the "handshake phase" is clear text. Client makes a request (ClientHello) First, the client (usually the browser) first sends a request for encrypted communication to the server, which is called the ClientHello request. In this step, the client mainly provides the following information to the server: 1. Supported protocol versions, such as TLS version 1.0 2. A random number generated by a client that is later used to generate a "conversation key". 3. Supported encryption methods, such as RSA public key cryptography. 4. Supported compression methods. It is important to note that the server's domain name is not included in the information sent by the client. That is, theoretically the server can contain only one Web site, otherwise it will not be able to tell which Web site the application provides the client with a digital certificate. This is why there is usually only one digital certificate for a single server. The server response (Serverhello) server responds to the client after it receives the client request, which is called Serverhello. The server response contains the following: 1. Confirm the version of the encrypted communication protocol used, such as the TLS 1.0 version. If the browser does not match the version supported by the server, the server turns off encrypted communication. 2. A random number generated by a server that is later used to generate a "conversation key". 3. Confirm the encryption method used, such as RSA public key encryption. 4. Server certificate. In addition to the above information, if the server needs to confirm the identity of the client, it will include a request to provide the client with a "client certificate". For example, financial institutions often allow only authenticated customers to connect to their network, and they will provide a USB key to the official customer, which contains a client certificate. After the client responds to the client receiving the server response, the server certificate is first validated. If the certificate is not issued by a trusted authority, or if the domain name in the certificate does not match the actual domain name, or if the certificate has expired, a warning is displayed to the visitor to choose whether or not to continue communicating. If there is no problem with the certificate, the client will remove the server's public key from the certificate. Then, send the following three messages to the server. 1. A random number. This random number is encrypted with the server public key to prevent eavesdropping. 2. The code changes the notification, indicating that the subsequent information will be sent with mutually agreed encryption method and key. 3. Client handshake end Notification indicates that the client's handshake phase has ended. This is usually the hash value of all the content that was sent earlier, and is used for server verification. The first random number above is the third random number that appears throughout the handshake phase, also known as "Pre-master key". With it, the client and server have three random numbers at the same time, and then the two parties use the previously agreed encryption method to generate the same "session key" used for this session. After the server's last response server receives the client's third random number Pre-master key, theSession key that is used to generate this session. Then, the following message is sent to the client at the end. 1. The code changes the notification, indicating that the subsequent information will be sent with mutually agreed encryption method and key. 2. The server handshake end notification indicates that the server's handshake phase has ended. This is also the hash value of all the contents that occurred before, which is used for client verification. When the handshake is over, the entire handshake phase is complete. Next, the client and the server into encrypted communication, it is completely using the normal HTTP protocol, but with "session key" encryption content.
Server based on Nginx built HTTPS virtual site before an article in detail on how to generate SSL certificate on the server side, and based on Nginx build HTTPS server, Link: nginx build HTTPS server
Android for HTTPS communication for a variety of reasons, use the Httpclicent class to explain how Android establishes an HTTPS connection. The code demo is as follows. Mainactivity.java
Package Com.example.photocrop;import Java.io.bufferedreader;import Java.io.inputstreamreader;import Org.apache.http.httpresponse;import Org.apache.http.httpstatus;import Org.apache.http.statusline;import Org.apache.http.client.httpclient;import Org.apache.http.client.methods.httppost;import Org.apache.http.client.methods.httpurirequest;import Android.app.activity;import Android.os.AsyncTask;import Android.os.bundle;import Android.os.asynctask.status;import Android.text.textutils;import Android.util.Log;import Android.view.view;import Android.widget.button;import Android.widget.textview;public class MainActivity extends Activity {private Button httpsbutton;private TextView contextview;private createhttpsconntask httpstask;@ overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview ( R.layout.activity_main); Httpsbutton = (Button) Findviewbyid (R.id.create_https_button); Httpsbutton.setonclicklistener (New View.onclicklistener () {@OverridepublIC void OnClick (View v) {runhttpsconnection ();}}); Contextview = (TextView) Findviewbyid (R.id.content_textview); Contextview.settext ("Initially empty");} private void Runhttpsconnection () {if (Httpstask = = NULL | | httpstask.getstatus () = = status.finished) {httpstask = new Cre Atehttpsconntask (); Httpstask.execute ();}} Private class Createhttpsconntask extends Asynctask<void, Void, void> {private static final String Https_example_ur L = "Custom";p rivate stringbuffer sbuffer = new StringBuffer (), @Overrideprotected void Doinbackground (void ... params) {HTTPU Rirequest request = new HttpPost (Https_example_url); HttpClient HttpClient = httputils.gethttpsclient (); try {HttpResponse HttpResponse = Httpclient.execute (request); if ( HttpResponse = null) {Statusline statusline = Httpresponse.getstatusline (); if (statusline! = null&& Statusline.getstatuscode () = = HTTPSTATUS.SC_OK) {BufferedReader reader = null;try {reader = new BufferedReader (New InputS Treamreader (Httpresponse.getentity (). GetContent (), "UTF-8")); String line = null;while (line = Reader.readline ())! = null) {sbuffer.append (line);}} catch (Exception e) {log.e ("https", E.getmessage ()),} finally {if (reader! = null) {reader.close (); reader = null;}}}}} catch (Exception e) {log.e ("https", E.getmessage ());} finally {}return null;} @Overrideprotected void OnPostExecute (void result) {if (! Textutils.isempty (Sbuffer.tostring ())) {Contextview.settext (sbuffer.tostring ());}}}}
Httputils.java
Package Com.example.photocrop;import Org.apache.http.httpversion;import Org.apache.http.client.httpclient;import Org.apache.http.conn.clientconnectionmanager;import Org.apache.http.conn.scheme.plainsocketfactory;import Org.apache.http.conn.scheme.scheme;import Org.apache.http.conn.scheme.schemeregistry;import Org.apache.http.conn.ssl.sslsocketfactory;import Org.apache.http.impl.client.defaulthttpclient;import Org.apache.http.impl.conn.tsccm.threadsafeclientconnmanager;import Org.apache.http.params.BasicHttpParams; Import Org.apache.http.params.httpprotocolparams;import Org.apache.http.protocol.http;import Android.content.context;public class Httputils {public static HttpClient gethttpsclient () {basichttpparams params = new B Asichttpparams (); Httpprotocolparams.setversion (params, httpversion.http_1_1); Httpprotocolparams.setcontentcharset (params, HTTP. Default_content_charset); Httpprotocolparams.setuseexpectcontinue (params, true); Schemeregistry Schreg = new Schemeregistry (); Schreg.register (New scheme ("http", Plainsocketfactory.getsocketfactory (), +)), Schreg.register ("https", Sslsocketfactory.getsocketfactory (), 443)); Clientconnectionmanager connmgr = new Threadsafeclientconnmanager (params, schreg); return new Defaulthttpclient ( Connmgr, params);} public static HttpClient Getcustomclient () {basichttpparams params = new Basichttpparams (); Httpprotocolparams.setversion (params, httpversion.http_1_1); Httpprotocolparams.setcontentcharset (params, HTTP. Default_content_charset); Httpprotocolparams.setuseexpectcontinue (params, true); Schemeregistry Schreg = new Schemeregistry () Schreg.register (New Scheme ("http", Plainsocketfactory.getsocketfactory ( ), Schreg.register (New Scheme ("https", Mysslsocketfactory.getsocketfactory (), 443)); Clientconnectionmanager connmgr = new Threadsafeclientconnmanager (params, schreg); return new Defaulthttpclient ( Connmgr, params);} public static HttpClient Getspecialkeystoreclient (context context) {Basichttpparams params = new Basichttpparams ();Httpprotocolparams.setversion (params, httpversion.http_1_1); Httpprotocolparams.setcontentcharset (params, HTTP. Default_content_charset); Httpprotocolparams.setuseexpectcontinue (params, true); Schemeregistry Schreg = new Schemeregistry () Schreg.register (New Scheme ("http", Plainsocketfactory.getsocketfactory ( ), Schreg.register ("https", customersocketfactory.getsocketfactory (context), 443)); Clientconnectionmanager connmgr = new Threadsafeclientconnmanager (params, schreg); return new Defaulthttpclient ( Connmgr, params);}}
Activity_main.xml
<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"    xmlns:tools= "http// Schemas.android.com/tools "    android:layout_width=" match_parent "    android:layout_height=" Match_parent "    android:orientation= "vertical" >    <button        android:id= "@+id/create_https_button"        android: Layout_width= "Match_parent"        android:layout_height= "wrap_content"        android:text= "@string/hello_world"        android:textsize= "16sp"/>    <textview        android:id= "@+id/content_textview"        android: Layout_width= "Match_parent"        android:layout_height= "wrap_content"        android:gravity= "center"        Android:textsize= "16SP"/></linearlayout>
Android uses defaulthttpclient to establish an HTTPS connection, and the key is to add support for https:
Schreg.register (New Scheme ("https", Sslsocketfactory.getsocketfactory (), 443));
With the support of HTTPS, it is possible to establish an HTTPS connection effectively, such as "https://www.google.com.hk", but not to access its own Nginx-based HTTPS server, because it uses a custom certificate that is not recognized by the system, The following questions will be reported: No Peer certificate. Use a custom certificate and ignore the authenticated HTTPS connection method to resolve the certificate is not recognized by the system, is to skip the system check. To skip the system check, you can no longer use the system standard SSL socketfactory, you need to customize one. Then, in order to skip the checksum in this custom SSL socketfactory, you also need to customize a trustmanager that ignores all the checks, that is, Trustall. The Mysslsocketfactory.java implementation code is as follows:
Package Com.example.photocrop;import Java.io.ioexception;import Java.net.socket;import Java.net.unknownhostexception;import Java.security.keymanagementexception;import Java.security.KeyStore;import Java.security.keystoreexception;import Java.security.nosuchalgorithmexception;import Java.security.unrecoverablekeyexception;import Java.security.cert.certificateexception;import Java.security.cert.x509certificate;import Javax.net.ssl.sslcontext;import Javax.net.ssl.trustmanager;import Javax.net.ssl.x509trustmanager;import Org.apache.http.conn.ssl.sslsocketfactory;public class MySSLSocketFactory Extends Sslsocketfactory {Sslcontext sslcontext = sslcontext.getinstance ("TLS");p ublic mysslsocketfactory (KeyStore Truststore) throws NoSuchAlgorithmException, Keymanagementexception,keystoreexception, unrecoverablekeyexception { Super (Truststore); TrustManager TM = new X509trustmanager () {@Overridepublic x509certificate[] getacceptedissuers () {return null;} @Overridepublic void checkservertrusted (x509ceRtificate[] chain,string authtype) throws certificateexception {} @Overridepublic void checkclienttrusted ( X509certificate[] chain,string authtype) throws certificateexception {}};sslcontext.init (null, new trustmanager[] {TM} , null);} @Overridepublic Socket Createsocket () throws IOException {return sslcontext.getsocketfactory (). Createsocket ();} @Overridepublic socket Createsocket (socket socket, String host, int Port,boolean autoClose) throws IOException, Unknownho stexception {return sslcontext.getsocketfactory (). Createsocket (socket, host, port,autoclose);} public static Sslsocketfactory Getsocketfactory () {try {KeyStore Truststore = keystore.getinstance ( Keystore.getdefaulttype ()); Truststore.load (null, NULL); Sslsocketfactory factory = new Mysslsocketfactory (truststore); return factory;} catch (Exception e) {e.getmessage (); return null;}}}
At the same time, you need to modify the Defaulthttpclient register method to build your own Sslsocket:
public static HttpClient Getcustomclient () {basichttpparams params = new Basichttpparams (); Httpprotocolparams.setversion (params, httpversion.http_1_1); Httpprotocolparams.setcontentcharset (params, HTTP. Default_content_charset); Httpprotocolparams.setuseexpectcontinue (params, true); Schemeregistry Schreg = new Schemeregistry () Schreg.register (New Scheme ("http", Plainsocketfactory.getsocketfactory ( ), Schreg.register (New Scheme ("https", Mysslsocketfactory.getsocketfactory (), 443)); Clientconnectionmanager connmgr = new Threadsafeclientconnmanager (params, schreg); return new Defaulthttpclient ( Connmgr, params);}
This makes it possible to successfully access the Nginx-based HTTPS virtual site of your own build. BUG: However, although this scenario uses HTTPS, the client and server side of the communication content is encrypted, the sniffer cannot get the contents of the transmission, but can not withstand "man-in-the-middle attack." For example, in the intranet configuration of a DNS, the target server domain name resolution to a local address, and then use an intermediary server at this address as a proxy, it uses a fake certificate to communicate with the client, and then the proxy server as a client connected to the actual server, with the real certificate to communicate with the server. In this way, all the communication content will pass through this agent, and the client will not be aware, because the client does not verify the server public key certificate.

Using a custom certificate to establish an HTTPS connection in order to prevent a "man-in-the-middle attack" that might result from the above scenario, we can download the server-side public key certificate and then compile the public key certificate into the Android app, which is used by the app to verify the certificate Generate KeyStore

To validate a custom certificate, you first compile the certificate into the app, which requires the use of the Keytool tool to produce the KeyStore file. The certificate here refers to the public key of the target server, which can be obtained from a. crt file or a. pem file configured by the Web server. At the same time, you need to configure Bouncycastle, I download is Bcprov-jdk16-145.jar, as for the configuration of the Google is good for you.

Keytool-importcert-v-trustcacerts-alias example-file www.example.com.crt-keystore example.bks-storetype bks-provid Erclass Org.bouncycastle.jce.provider.bouncycastleprovider-providerpath/home/wzy/downloads/java/jdk1.7.0_60/jre /lib/ext/bcprov-jdk16-145.jar-storepass pw123456
After running, the contents of the certificate are displayed and you are prompted to confirm, enter Y to return.

Once the production KeyStore file is successful, place it in the app's Res/raw directory.

Using custom KeyStore To implement connection ideas is similar to Trushall and requires a custom sslsokcetfactory, but because the certificate needs to be validated, no custom trustmanager is required.
Package Com.example.photocrop;import Java.io.ioexception;import Java.io.inputstream;import Java.security.keymanagementexception;import Java.security.keystore;import Java.security.keystoreexception;import Java.security.nosuchalgorithmexception;import Java.security.unrecoverablekeyexception;import Org.apache.http.conn.ssl.sslsocketfactory;import Android.content.context;public class CustomerSocketFactory Extends Sslsocketfactory {private static final String PASSWD = "pw123456";p ublic customersocketfactory (KeyStore Truststore) throws NoSuchAlgorithmException, Keymanagementexception,keystoreexception, unrecoverablekeyexception { Super (Truststore);} public static Sslsocketfactory Getsocketfactory (context context) {InputStream input = null;try {input = Context.getresour CES (). Openrawresource (R.raw.example); KeyStore Truststore = keystore.getinstance (Keystore.getdefaulttype ()); Truststore.load (input, Passwd.tochararray ()) ; Sslsocketfactory factory = new Customersocketfactory (truststore); return factorY;} catch (Exception e) {e.printstacktrace (); return null;} finally {if (input! = null) {try {input.close ()} catch (Ioexceptio n e) {e.printstacktrace ();} input = null;}}}
At the same time, you need to modify the Defaulthttpclient register method to build your own Sslsocket:
public static HttpClient Getspecialkeystoreclient (context context) {Basichttpparams params = new Basichttpparams (); Httpprotocolparams.setversion (params, httpversion.http_1_1); Httpprotocolparams.setcontentcharset (params, HTTP. Default_content_charset); Httpprotocolparams.setuseexpectcontinue (params, true); Schemeregistry Schreg = new Schemeregistry () Schreg.register (New Scheme ("http", Plainsocketfactory.getsocketfactory ( ), Schreg.register ("https", customersocketfactory.getsocketfactory (context), 443)); Clientconnectionmanager connmgr = new Threadsafeclientconnmanager (params, schreg); return new Defaulthttpclient ( Connmgr, params);}

References [1] http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html

Android HTTPS detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.