目錄
- 數(shù)字簽名
- 數(shù)字證書
- Https 編程
數(shù)字簽名
數(shù)字簽名是非對稱加密與數(shù)字摘要的組合應(yīng)用
應(yīng)用場景
- 校驗用戶身份(使用私鑰簽名,公鑰校驗,只要用公鑰能校驗通過,則該信息一定是私鑰持有者發(fā)布的)
- 校驗數(shù)據(jù)的完整性(用解密后的消息摘要跟原文的消息摘要進(jìn)行對比)
簽名過程
“發(fā)送報文時,發(fā)送方用一個哈希函數(shù)從報文文本中生成報文摘要,然后用自己的私人密鑰對這個摘要進(jìn)行加密,這個加密后的摘要將作為報文的數(shù)字簽名和報文一起發(fā)送給接收方,接收方首先用與發(fā)送方一樣的哈希函數(shù)從接收到的原始報文中計算出報文摘要,接著再用發(fā)送方的公用密鑰來對報文附加的數(shù)字簽名進(jìn)行解密,如果這兩個摘要相同、那么接收方就能確認(rèn)該數(shù)字簽名是發(fā)送方的。
數(shù)字簽名有兩種功效:一是能確定消息確實是由發(fā)送方簽名并發(fā)出來的,因為別人假冒不了發(fā)送方的簽名。二是數(shù)字簽名能確定消息的完整性。因為數(shù)字簽名的特點是它代表了文件的特征,文件如果發(fā)生改變,數(shù)字摘要的值也將發(fā)生變化。不同的文件將得到不同的數(shù)字摘要。一次數(shù)字簽名涉及到一個哈希函數(shù)、發(fā)送者的公鑰、發(fā)送者的私鑰。

使用步驟
1. //獲取signature 對象,初始化算法:MD2withRSA, MD5withRSA, or SHA1withRSA
2. Signature signature = Signature.getInstance("MD5withRSA");
3. //創(chuàng)建私鑰(從磁盤上讀?。?4. PrivateKey privateKey = (PrivateKey)SerializableUtil.readObject(
5. "haha.privateKey");
6. //使用私鑰進(jìn)行初始化
7. signature.initSign(privateKey);
8. //傳入需要簽名的數(shù)據(jù)
9. signature.update(content.getBytes());
10. //執(zhí)行簽名
11. byte[] sign = signature.sign();
12.
13. //創(chuàng)建公鑰(從磁盤上讀?。?14. PublicKey publicKey = (PublicKey) SerializableUtil.readObject(
15. "haha.publicKey");
16. //使用公鑰進(jìn)行初始化
17. signature.initVerify(publicKey);
18. //傳入需要校驗的數(shù)據(jù)(即上面的原文)
19. signature.update(content.getBytes());
20. //執(zhí)行校驗
21. boolean verify = signature.verify(sign);
小結(jié)
數(shù)字簽名一般不單獨使用,基本都是用在數(shù)字證書里實現(xiàn)SSL 通信協(xié)議。下面將學(xué)習(xí)的數(shù)字證書就是基于數(shù)字簽名技術(shù)實現(xiàn)的。
數(shù)字證書
數(shù)字證書就是互聯(lián)網(wǎng)通訊中標(biāo)志通訊各方身份信息的一串?dāng)?shù)字,提供了一種在Internet 上驗證通信實體身份的方式,數(shù)字證書不是數(shù)字身份證,而是身份認(rèn)證機構(gòu)蓋在數(shù)字身份證上的一個章或?。ɑ蛘哒f加在數(shù)字身份證上的一個簽名)。它是由權(quán)威機構(gòu)——CA 機構(gòu),又稱為證書授權(quán)(Certificate Authority)中心發(fā)行的,人們可以在網(wǎng)上用它來識別對方的身份。
應(yīng)用場景
1,交易者身份的確定性、不可否認(rèn)性、不可修改性
2,對應(yīng)用進(jìn)行簽名認(rèn)證(例如Android 的apk)
數(shù)字證書格式

數(shù)字證書的格式普遍采用的是X.509V3 國際標(biāo)準(zhǔn),一個標(biāo)準(zhǔn)的X.509 數(shù)字證書包含以下一些內(nèi)容:
證書的版本信息;
證書的序列號,每個證書都有一個唯一的證書序列號;
證書所使用的簽名算法;
證書的發(fā)行機構(gòu)名稱,命名規(guī)則一般采用X.500 格式;
證書的有效期,通用的證書一般采用UTC 時間格式,它的計時范圍為1950-2049;
證書所有人的名稱,命名規(guī)則一般采用X.500 格式;
證書所有人的公開密鑰;
證書發(fā)行者對證書的簽名。
數(shù)字證書原理

數(shù)字證書是安全領(lǐng)域里的終極武器,SSL 通信協(xié)議里最核心的東西就是數(shù)字證書。他涉及到前面提到的所有知識:對稱加密、非對稱加密、消息摘要、數(shù)字簽名等。數(shù)字證書可以通過java 自帶的KeyTool 工具生成,生成后的數(shù)字證書一般保管在KeyStore 里。KeyStore可以叫做秘鑰倉庫。
秘鑰倉庫可以保管3 種類型的數(shù)據(jù):KeyStore.PrivateKeyEntry(非對稱機密里的私鑰)、KeyStore.SecretKeyEntry (對稱加密里的秘鑰)、KeyStore.TrustedCertificateEntry(受信任的證書)
Keytool 工具
路徑:jre\bin\keytool.exe

常用命令:
生成keypair
keytool -genkeypair
keytool -genkeypair -alias lisi(后面部分是為證書指定別名,否則采用默認(rèn)的名稱為mykey)
看看keystore 中有哪些項目:
keytool -list 或keytool -list -v
keytool -exportcert -alias lisi -file lisi.cer
生成可打印的證書:
keytool -exportcert -alias lisi -file lisi.cer –rfc
顯示數(shù)字證書文件中的證書信息:
keytool -printcert -file lisi.cer
直接雙擊lisi.cer,用window 系統(tǒng)的內(nèi)置程序打開lisi.cer
Android 的keystore 相關(guān)知識
debug 簽名路徑:user.android\debug.keystore

debug.keystore 的別名(alias)及密碼:
別名:androiddebugkey,密碼:android
簽名命令(jdk1.6):
jarsigner -verbose -keystore debug.keystore -signedjar 1signed.apk 1.apk androiddebugkey
簽名命令(jdk1.7):
jarsigner -verbose -keystore debug.keystore -signedjar 1signed.apk 1.apk androiddebugkey -digestalg
SHA1 -sigalg MD5withRSA
優(yōu)化命令:zipalign -v 4 1signed.apk 1signedaligned.apk
驗證簽名是否成功:jarsigner -verify 1signed.apk
補充
簽名證書:
由權(quán)威頒發(fā)機構(gòu)頒發(fā)給服務(wù)器或者個人用于證明自己身份的東西,默認(rèn)客戶端都是信任的。主要目的是用來加密和保證數(shù)據(jù)的完整性和不可抵賴性
例如根證書機構(gòu)Symantec 頒發(fā)給百度的就是簽名證書,是受信任的。

自簽名證書:
由服務(wù)器自己頒發(fā)給自己,用于證明自己身份的東西,非權(quán)威頒發(fā)機構(gòu)發(fā)布,默認(rèn)客戶端都是不信任的,主要目的是用來加密和保證數(shù)據(jù)的完整性和不可抵賴性,與簽名證書相同.
例如中鐵集團(SRCA)辦法給12306 的證書就是自簽名證書,自己給自己頒發(fā)的。

Https 編程
介紹
** SSL(Secure Sockets Layer 安全套接層)**,為網(wǎng)景公司(Netscape)所研發(fā),用以保障在Internet 上數(shù)據(jù)傳輸之安全,利用數(shù)據(jù)加密(Encryption)技術(shù),可確保數(shù)據(jù)在網(wǎng)絡(luò)上之傳輸過程中不會被截取及竊聽。一般通用之規(guī)格為40 bit 之安全標(biāo)準(zhǔn),美國則已推出128 bit 之更高安全標(biāo)準(zhǔn),但限制出境。只要3.0 版本以上之I.E.或Netscape 瀏覽器即可支持SSL。
TLS(Transport Layer Security 傳輸層安全),用于在兩個通信應(yīng)用程序之間提供保密性和數(shù)據(jù)完整性。TLS 是SSL 的標(biāo)準(zhǔn)化后的產(chǎn)物,有1.0 ,1.1 ,1.2 三個版本,默認(rèn)使用1.0。TLS1.0 和SSL3.0 幾乎沒有區(qū)別,事實上我們現(xiàn)在用的都是TLS,但因為歷史上習(xí)慣了SSL 這個稱呼。
SSL 通信簡單圖示:

SSL 通信詳細(xì)圖示:

當(dāng)請求使用自簽名證書的網(wǎng)站數(shù)據(jù)時,例如請求12306 的客運服務(wù)頁面:https://kyfw.12306.cn/otn/,則會報下面的錯誤,原因是客戶端的根認(rèn)證機構(gòu)不能識別該證書
錯誤信息:unable to find valid certification path to requested target
解決方案1
一個證書可不可信,是由TrustManager 決定的,所以我們只需要自定義一個什么都不做的TrustManager即可,服務(wù)器出示的所有證書都不做校驗,一律放行。
1. public static void main(String[] args) throws Exception {
2. //協(xié)議傳輸層安全TLS(transport layer secure)
3. SSLContext sslContext = SSLContext.getInstance("TLS");
4. //創(chuàng)建信任管理器(TrustManager 負(fù)責(zé)校驗證書是否可信)
5. TrustManager[] tm = new TrustManager[]{new EmptyX509TrustManager()};
6. //使用自定義的信任管理器初始化SSL 上下文對象
7. sslContext.init(null, tm, null);
8. //設(shè)置全局的SSLSocketFactory 工廠(對所有ssl 鏈接都產(chǎn)生影響)
9. HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
10.
11. //URL url = new URL("https://www.baidu.com");
12. URL url = new URL("https://kyfw.12306.cn/otn/");
13. HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
14. InputStream in = conn.getInputStream();
15. System.out.println(Util.inputstream2String(in));
16. }
17.
18. /**
19. * 自定義一個什么都不做的信任管理器,所有證書都不做校驗,一律放行
20. */
21. private static class EmptyX509TrustManager implements X509TrustManager{
22. @Override
23. public void checkClientTrusted(X509Certificate[] chain, String authType)
24. throws CertificateException {
25. }
26. @Override
27. public void checkServerTrusted(X509Certificate[] chain, String authType)
28. throws CertificateException {
29. }
30. @Override
31. public X509Certificate[] getAcceptedIssuers() {
32. return null;
33. }
解決方案2
12306 服務(wù)器出示的證書是中鐵集團SRCA 給他頒發(fā)的,所以SRCA 的證書是能夠識別12306 的證書的,所以只需要把SRCA 證書導(dǎo)入系統(tǒng)的KeyStore 里,之后交給TrustManagerFactory 進(jìn)行初始化,則可把SRCA 添加至根證書認(rèn)證機構(gòu),之后校驗的時候,SRCA 對12306 證書校驗時就能通過認(rèn)證。
這種解決方案有兩種使用方式:一是直接使用SRCA.cer 文件,二是使用改文件的RFC 格式數(shù)據(jù),將其寫在代碼里。
1. //12306 證書的RFC 格式(注意要記得手動添加兩個換行符)
2. private static final String CERT_12306_RFC = "-----BEGIN CERTIFICATE-----\n"
3. +
"MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn"
4. +
"BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X"
5. +
"DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp"
6. +
"bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3"
7. +
"DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2"
8. +
"9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6"
9. +
"D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle"
10. +
"tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov"
11. +
"LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt"
12. +
"x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV"
13. +
"23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ"
14. + "og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A=="
15. + "-----END CERTIFICATE-----\n";
16. public static void main(String[] args) throws Exception {
17. // 使用傳輸層安全協(xié)議TLS(transport layer secure)
18. SSLContext sslContext = SSLContext.getInstance("TLS");
19. //使用SRCA.cer 文件的形式
20. //FileInputStream certInputStream = new FileInputStream(new File("srca.cer"));
21. //也可以通過RFC 字符串的形式使用證書
22. ByteArrayInputStream certInputStream = new
ByteArrayInputStream(CERT_12306_RFC.getBytes());
23. // 初始化keyStore,用來導(dǎo)入證書
24. KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
25. //參數(shù)null 表示使用系統(tǒng)默認(rèn)keystore,也可使用其他keystore(需事先將srca.cer 證書導(dǎo)入
keystore 里)
26. keyStore.load(null);
27. //通過流創(chuàng)建一個證書
28. Certificate certificate = CertificateFactory.getInstance("X.509")
29. .generateCertificate(certInputStream);
30. // 把srca.cer 這個證書導(dǎo)入到KeyStore 里,別名叫做srca
31. keyStore.setCertificateEntry("srca", certificate);
32. // 設(shè)置使用keyStore 去進(jìn)行證書校驗
33. TrustManagerFactory trustManagerFactory = TrustManagerFactory
34. .getInstance(TrustManagerFactory.getDefaultAlgorithm());
35. trustManagerFactory.init(keyStore);
36. //用我們設(shè)定好的TrustManager 去做ssl 通信協(xié)議校驗,即證書校驗
37. sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
38. HttpsURLConnection.setDefaultSSLSocketFactory(sslContext
39. .getSocketFactory());
40. URL url = new URL("https://kyfw.12306.cn/otn/");
41. HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
42. InputStream in = conn.getInputStream();
43. System.out.println(Util.inputstream2String(in));
44. }
Android 里的https 請求:
把scra.cer 文件考到assets 或raw 目錄下,或者直接使用證書的RFC 格式,接下來的做法和java工程代碼一樣
總結(jié)
1,對稱加密與非對稱加密結(jié)合使用實現(xiàn)了秘鑰交換,之后通信雙方使用該秘鑰進(jìn)行對稱加密通信。
2,消息摘要與非對稱加密實現(xiàn)了數(shù)字簽名,根證書機構(gòu)對目標(biāo)證書進(jìn)行簽名,在校驗的時候,根證書用公鑰對其進(jìn)行校驗。若校驗成功,則說明該證書是受信任的。
3,Keytool 工具可以創(chuàng)建證書,之后交給根證書機構(gòu)認(rèn)證后直接使用自簽名證書,還可以輸出證書的RFC格式信息等。
4,數(shù)字簽名技術(shù)實現(xiàn)了身份認(rèn)證與數(shù)據(jù)完整性保證。
5,加密技術(shù)保證了數(shù)據(jù)的保密性,消息摘要算法保證了數(shù)據(jù)的完整性,對稱加密的高效保證了數(shù)據(jù)處理的可靠性,數(shù)字簽名技術(shù)保證了操作的不可否認(rèn)性。