Android安全加密專題文章索引
- Android安全加密:對稱式加密
- Android安全加密:非對稱式加密
- Android安全加密:訊息摘要Message Digest
- Android安全加密:數位簽章和數位憑證
- Android安全加密:Https編程
以上學習所有內容,對稱式加密、非對稱式加密、訊息摘要、數位簽章等知識都是為了理解數位憑證工作原理而作為一個預備知識。數位憑證是密碼學裡的終極武器,是人類幾千年歷史總結的智慧的結晶,只有在明白了數位憑證工作原理後,才能理解Https 協議的安全通訊機制。最終才能在SSL 開發過程中得心應手。
另外,對稱式加密和訊息摘要這兩個知識點是可以單獨拿來使用的。
知識點串聯:
數位憑證使用到了以上學習的所有知識
- 對稱式加密與非對稱式加密結合使用實現了秘鑰交換,之後通訊雙方使用該秘鑰進行對稱式加密通訊。
- 訊息摘要與非對稱式加密實現了數位簽章,根憑證機構對目標認證進行簽名,在校正的時候,根憑證用公開金鑰對其進行校正。若校正成功,則說明該認證是受信任的。
- Keytool 工具可以建立認證,之後交給根憑證機構認證後直接使用自我簽署憑證,還可以輸出認證的RFC格式資訊等。
- 數位簽章技術實現了身份認證與資料完整性保證。
- 加密技術保證了資料的保密性,訊息摘要演算法保證了資料的完整性,對稱式加密的高效保證了資料處理的可靠性,數位簽章技術保證了操作的不可否認性。
通過以上內容的學習,我們要能掌握以下知識點:
- 基礎知識:bit 位、位元組、字元、字元編碼、進位轉換、io
- 知道怎樣在實際開發裡怎樣使用對稱式加密解決問題
- 知道對稱式加密、非對稱式加密、訊息摘要、數位簽章、數位憑證是為瞭解決什麼問題而出現的
- 瞭解SSL 通訊流程
- 實際開發裡怎樣請求Https 的介面
概述
SSL(Secure Sockets Layer 安全套接層),為網景公司(Netscape)所研發,用以保障在Internet 上資料轉送之安全,利用資料加密(Encryption)技術,可確保資料在網路上之傳輸過程中不會被截取及竊聽。一般通用之規格為40 bit 之安全標準,美國則已推出128 bit 之更高安全標準,但限制出境。只要3.0 版本以上之I.E.或Netscape 瀏覽器即可支援SSL。
TLS(Transport Layer Security 傳輸層安全),用於在兩個通訊應用程式之間提供保密性和資料完整性。TLS 是SSL 的標準化後的產物,有1.0 ,1.1 ,1.2 三個版本,預設使用1.0。TLS1.0 和SSL3.0 幾乎沒
有區別,事實上我們現在用的都是TLS,但因為曆史上習慣了SSL 這個稱呼。
SSL 通訊簡單圖示:
SSL 通訊詳細圖示:
當請求使用自我簽署憑證的網站資料時,例如請求12306 的客運服務頁面:https://kyfw.12306.cn/otn/,則會報下面的錯誤,原因是用戶端的根認證機構不能識別該認證錯誤資訊:unable to find valid certification path to requested target
解決方案1
一個認證可不可信,是由TrustManager 決定的,所以我們只需要自訂一個什麼都不做的TrustManager即可,伺服器出示的所有認證都不做校正,一律允許存取。
public static void main(String[] args) throws Exception {//協議傳輸層安全TLS(transport layer secure)SSLContext sslContext = SSLContext.getInstance("TLS");//建立信任管理器(TrustManager 負責校正認證是否可信)TrustManager[] tm = new TrustManager[]{new EmptyX509TrustManager()};//使用自訂的信任管理器初始化SSL 內容物件sslContext.init(null, tm, null);//設定全域的SSLSocketFactory 工廠(對所有ssl 連結都產生影響)HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); //URL url = new URL("https://www.baidu.com"); URL url = new URL("https://kyfw.12306.cn/otn/"); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); InputStream in = conn.getInputStream(); System.out.println(Util.inputstream2String(in)); } /** * 自訂一個什麼都不做的信任管理器,所有認證都不做校正,一律允許存取 */ private static class EmptyX509TrustManager implements X509TrustManager{ @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; }}
解決方案2
12306 伺服器出示的認證是中鐵集團SRCA 給他頒發的,所以SRCA 的認證是能夠識別12306 的認證的,所以只需要把SRCA 憑證匯入系統的KeyStore 裡,之後交給TrustManagerFactory 進行初始化,則可把SRCA 添加至根憑證認證機構,之後校正的時候,SRCA 對12306 認證校正時就能通過認證。
這種解決方案有兩種使用方式:一是直接使用SRCA.cer 檔案,二是使用改檔案的RFC 格式資料,將其寫在代碼裡。
//12306 認證的RFC 格式(注意要記得手動添加兩個分行符號) private static final String CERT_12306_RFC = "-----BEGIN CERTIFICATE-----\n"+"MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn"+"BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X"+"DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp"+"bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3"+"DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2"+"9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6"+"D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle"+"tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov"+"LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt"+"x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV"+"23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ"+ "og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A=="+ "-----END CERTIFICATE-----\n"; public static void main(String[] args) throws Exception { // 使用傳輸層安全性通訊協定TLS(transport layer secure) SSLContext sslContext = SSLContext.getInstance("TLS"); //使用SRCA.cer 檔案的形式//FileInputStream certInputStream = new FileInputStream(new File("srca.cer"));//也可以通過RFC 字串的形式使用認證ByteArrayInputStream certInputStream = newByteArrayInputStream(CERT_12306_RFC.getBytes());// 初始化keyStore,用來匯入認證KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());//參數null 表示使用系統預設keystore,也可使用其他keystore(需事先將srca.cer 認證匯入keystore 裡)keyStore.load(null);//通過流建立一個認證Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(certInputStream);// 把srca.cer 這個認證匯入到KeyStore 裡,別名叫做srcakeyStore.setCertificateEntry("srca", certificate);// 設定使用keyStore 去進行認證校正TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);//用我們設定好的TrustManager 去做ssl 通訊協定校正,即認證校正sslContext.init(null, trustManagerFactory.getTrustManagers(), null);HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());URL url = new URL("https://kyfw.12306.cn/otn/");HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();InputStream in = conn.getInputStream();System.out.println(Util.inputstream2String(in));}
Android 裡的https 請求:
把scra.cer 檔案考到assets 或raw 目錄下,或者直接使用認證的RFC 格式,接下來的做法和java工程代碼一樣
//ByteArrayInputStream in = new ByteArrayInputStream("rfc".getBytes());CertificateFactory cf = CertificateFactory.getInstance("X.509");InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));Certificate ca;try { ca = cf.generateCertificate(caInput); System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());} finally { caInput.close();}String keyStoreType = KeyStore.getDefaultType();KeyStore keyStore = KeyStore.getInstance(keyStoreType);keyStore.load(null, null);keyStore.setCertificateEntry("ca", ca);String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);tmf.init(keyStore);SSLContext context = SSLContext.getInstance("TLS");context.init(null, tmf.getTrustManagers(), null);URL url = new URL("https://certs.cac.washington.edu/CAtest/");HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();urlConnection.setSSLSocketFactory(context.getSocketFactory());InputStream in = urlConnection.getInputStream();copyInputStreamToOutputStream(in, System.out);
雙向認證驗證
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null);SSLContext sslContext = SSLContext.getInstance("TLS");TrustManagerFactory trustManagerFactory = TrustManagerFactory. getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);//初始化keystoreKeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());clientKeyStore.load(getAssets().open("client.bks"), "123456".toCharArray());KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());keyManagerFactory.init(clientKeyStore, "123456".toCharArray());sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
Nogotofail
網路流量安全性測試工具,Google的開源項目:https://github.com/google/nogotofail