【人人都懂密碼學】一篇最易懂的Java密碼學入門教程(下)

2.4.2 證書從哪里來
“證書中心”(certificate authority,簡稱CA),為公鑰做認證。證書中心用自己的私鑰,對公鑰和一些相關信息一起加密,生成“數字證書”(Digital Certificate)。
拿到數字證書以后,就可以放心了。以后只要在簽名的同時,再附上數字證書就行了。
用CA的公鑰解開數字證書,就可以拿到真實的公鑰了,然后就能證明“數字簽名”是否真的是公司簽的。
修改之前的RSAdemo代碼:
/* ?*?Copyright?(c)?Huawei?Technologies?Co.,?Ltd.?2020-2020.?All?rights?reserved. ?*/ package?com.huawei.it.jalor.boot.test; import?com.sun.org.apache.xml.internal.security.utils.Base64; import?org.apache.commons.io.FileUtils; import?javax.crypto.Cipher; import?java.io.File; import?java.nio.charset.Charset; import?java.security.Key; import?java.security.KeyFactory; import?java.security.KeyPair; import?java.security.KeyPairGenerator; import?java.security.PrivateKey; import?java.security.PublicKey; import?java.security.spec.PKCS8EncodedKeySpec; import?java.security.spec.X509EncodedKeySpec; /** ?*?RSAdemo ?* ?*?@Author:?陳志強 ?*?@CreateTime:?2020-10-12 ?*?@Description: ?*/ public?class?RSAdemo?{ ????public?static?void?main(String[]?args)?throws?Exception?{ ????????String?input?=?"硅谷"; ????????//?加密算法 ????????String?algorithm?=?"RSA"; ????????PrivateKey?privateKey?=?getPrivateKey("a.pri",?algorithm); ????????PublicKey?publicKey?=?getPublicKey("a.pub",?algorithm); ????????String?s?=?encryptRSA(algorithm,?privateKey,?input); ????????String?s1?=?decryptRSA(algorithm,?publicKey,?s); ????????System.out.println(s); ????????System.out.println(s1); ????} ????public?static?PublicKey?getPublicKey(String?pulickPath,String?algorithm)?throws?Exception{ ????????//?將文件內容轉為字符串 ????????String?publicKeyString?=?FileUtils.readFileToString(new?File(pulickPath),?Charset.defaultCharset()); ????????//?獲取密鑰工廠 ????????KeyFactory?keyFactory?=?KeyFactory.getInstance(algorithm); ????????//?構建密鑰規范?進行Base64解碼 ????????X509EncodedKeySpec?spec?=?new?X509EncodedKeySpec(Base64.decode(publicKeyString)); ????????//?生成公鑰 ????????return?keyFactory.generatePublic(spec); ????} ????public?static?PrivateKey?getPrivateKey(String?priPath,String?algorithm)?throws?Exception{ ????????//?將文件內容轉為字符串 ????????String?privateKeyString?=?FileUtils.readFileToString(new?File(priPath),?Charset.defaultCharset()); ????????//?獲取密鑰工廠 ????????KeyFactory?keyFactory?=?KeyFactory.getInstance(algorithm); ????????//?構建密鑰規范?進行Base64解碼 ????????PKCS8EncodedKeySpec?spec?=?new?PKCS8EncodedKeySpec(Base64.decode(privateKeyString)); ????????//?生成私鑰 ????????return?keyFactory.generatePrivate(spec); ????} ????/** ?????*?生成密鑰對并保存在本地文件中 ?????* ?????*?@param?algorithm?:?算法 ?????*?@param?pubPath???:?公鑰保存路徑 ?????*?@param?priPath???:?私鑰保存路徑 ?????*?@throws?Exception ?????*/ ????public?static?void?generateKeyToFile(String?algorithm,?String?pubPath,?String?priPath)?throws?Exception?{ ????????//?獲取密鑰對生成器 ????????KeyPairGenerator?keyPairGenerator?=?KeyPairGenerator.getInstance(algorithm); ????????//?獲取密鑰對 ????????KeyPair?keyPair?=?keyPairGenerator.generateKeyPair(); ????????//?獲取公鑰 ????????PublicKey?publicKey?=?keyPair.getPublic(); ????????//?獲取私鑰 ????????PrivateKey?privateKey?=?keyPair.getPrivate(); ????????//?獲取byte數組 ????????byte[]?publicKeyEncoded?=?publicKey.getEncoded(); ????????byte[]?privateKeyEncoded?=?privateKey.getEncoded(); ????????//?進行Base64編碼 ????????String?publicKeyString?=?Base64.encode(publicKeyEncoded); ????????String?privateKeyString?=?Base64.encode(privateKeyEncoded); ????????//?保存文件 ????????FileUtils.writeStringToFile(new?File(pubPath),?publicKeyString,?Charset.forName("UTF-8")); ????????FileUtils.writeStringToFile(new?File(priPath),?privateKeyString,?Charset.forName("UTF-8")); ????} ????/** ?????*?解密數據 ?????* ?????*?@param?algorithm??????:?算法 ?????*?@param?encrypted??????:?密文 ?????*?@param?key????????????:?密鑰 ?????*?@return?:?原文 ?????*?@throws?Exception ?????*/ ????public?static?String?decryptRSA(String?algorithm,Key?key,String?encrypted)?throws?Exception{ ????????//?創建加密對象 ????????//?參數表示加密算法 ????????Cipher?cipher?=?Cipher.getInstance(algorithm); ????????//?私鑰進行解密 ????????cipher.init(Cipher.DECRYPT_MODE,key); ????????//?由于密文進行了Base64編碼,?在這里需要進行解碼 ????????byte[]?decode?=?Base64.decode(encrypted); ????????//?對密文進行解密,不需要使用base64,因為原文不會亂碼 ????????byte[]?bytes1?=?cipher.doFinal(decode); ????????return?new?String(bytes1); ????} ????/** ?????*?使用密鑰加密數據 ?????* ?????*?@param?algorithm??????:?算法 ?????*?@param?input??????????:?原文 ?????*?@param?key????????????:?密鑰 ?????*?@return?:?密文 ?????*?@throws?Exception ?????*/ ????public?static?String?encryptRSA(String?algorithm,Key?key,String?input)?throws?Exception{ ????????//?創建加密對象 ????????//?參數表示加密算法 ????????Cipher?cipher?=?Cipher.getInstance(algorithm); ????????//?初始化加密 ????????//?第一個參數:加密的模式 ????????//?第二個參數:使用私鑰進行加密 ????????cipher.init(Cipher.ENCRYPT_MODE,key); ????????//?私鑰加密 ????????byte[]?bytes?=?cipher.doFinal(input.getBytes()); ????????//?對密文進行Base64編碼 ????????return?Base64.encode(bytes); ????} ????/** ?????*?從文件中加載公鑰 ?????* ?????*?@param?algorithm?:?算法 ?????*?@param?filePath??:?文件路徑 ?????*?@return?:?公鑰 ?????*?@throws?Exception ?????*/ ????public?static?PublicKey?loadPublicKeyFromFile(String?algorithm,?String?filePath)?throws?Exception?{ ????????//?將文件內容轉為字符串 ????????String?keyString?=?FileUtils.readFileToString(new?File(filePath),?Charset.forName("UTF-8")); ????????return?loadPublicKeyFromString(algorithm,?keyString); ????} ????/** ?????*?從字符串中加載公鑰 ?????* ?????*?@param?algorithm?:?算法 ?????*?@param?keyString?:?公鑰字符串 ?????*?@return?:?公鑰 ?????*?@throws?Exception ?????*/ ????public?static?PublicKey?loadPublicKeyFromString(String?algorithm,?String?keyString)?throws?Exception?{ ????????//?進行Base64解碼 ????????byte[]?decode?=?Base64.decode(keyString); ????????//?獲取密鑰工廠 ????????KeyFactory?keyFactory?=?KeyFactory.getInstance(algorithm); ????????//?構建密鑰規范 ????????X509EncodedKeySpec?keyspec?=?new?X509EncodedKeySpec(decode); ????????//?獲取公鑰 ????????return?keyFactory.generatePublic(keyspec); ????} ????/** ?????*?從文件中加載私鑰 ?????* ?????*?@param?algorithm?:?算法 ?????*?@param?filePath??:?文件路徑 ?????*?@return?:?私鑰 ?????*?@throws?Exception ?????*/ ????public?static?PrivateKey?loadPrivateKeyFromFile(String?algorithm,?String?filePath)?throws?Exception?{ ????????//?將文件內容轉為字符串 ????????String?keyString?=?FileUtils.readFileToString(new?File(filePath),?Charset.forName("UTF-8")); ????????return?loadPrivateKeyFromString(algorithm,?keyString); ????} ????/** ?????*?從字符串中加載私鑰 ?????* ?????*?@param?algorithm?:?算法 ?????*?@param?keyString?:?私鑰字符串 ?????*?@return?:?私鑰 ?????*?@throws?Exception ?????*/ ????public?static?PrivateKey?loadPrivateKeyFromString(String?algorithm,?String?keyString)?throws?Exception?{ ????????//?進行Base64解碼 ????????byte[]?decode?=?Base64.decode(keyString); ????????//?獲取密鑰工廠 ????????KeyFactory?keyFactory?=?KeyFactory.getInstance(algorithm); ????????//?構建密鑰規范 ????????PKCS8EncodedKeySpec?keyspec?=?new?PKCS8EncodedKeySpec(decode); ????????//?生成私鑰 ????????return?keyFactory.generatePrivate(keyspec); ????} } 寫一個驗證數字簽名的類: /* ?*?Copyright?(c)?Huawei?Technologies?Co.,?Ltd.?2020-2020.?All?rights?reserved. ?*/ package?com.huawei.it.jalor.boot.test; import?com.sun.org.apache.xml.internal.security.utils.Base64; import?java.security.PrivateKey; import?java.security.PublicKey; import?java.security.Signature; /** ?*?功能描述:?驗證數字簽名 ?* ?*?@author?cWX970190 ?*?@since?2020-10-11 ?*/ public?class?SignatureDemo?{ ????public?static?void?main(String[]?args)?throws?Exception?{ ????????String?a?=?"123"; ????????PublicKey?publicKey?=RSAdemo.loadPublicKeyFromFile("RSA",?"a.pub"); ????????PrivateKey?privateKey?=?RSAdemo.loadPrivateKeyFromFile("RSA",?"a.pri"); ????????String?signaturedData?=?getSignature(a,?"sha256withrsa",?privateKey); ????????boolean?b?=?verifySignature(a,?"sha256withrsa",?publicKey,?signaturedData); ????????System.out.println(b); ????} ????/** ?????*?生成簽名 ?????* ?????*?@param?input??????:?原文 ?????*?@param?algorithm??:?算法 ?????*?@param?privateKey?:?私鑰 ?????*?@return?:?簽名 ?????*?@throws?Exception ?????*/ ????private?static?String?getSignature(String?input,?String?algorithm,?PrivateKey?privateKey)?throws?Exception?{ ????????//?獲取簽名對象 ????????Signature?signature?=?Signature.getInstance(algorithm); ????????//?初始化簽名 ????????signature.initSign(privateKey); ????????//?傳入原文 ????????signature.update(input.getBytes()); ????????//?開始簽名 ????????byte[]?sign?=?signature.sign(); ????????//?對簽名數據進行Base64編碼 ????????return?Base64.encode(sign); ????} ????/** ?????*?校驗簽名 ?????* ?????*?@param?input??????????:?原文 ?????*?@param?algorithm??????:?算法 ?????*?@param?publicKey??????:?公鑰 ?????*?@param?signaturedData?:?簽名 ?????*?@return?:?數據是否被篡改 ?????*?@throws?Exception ?????*/ ????private?static?boolean?verifySignature(String?input,?String?algorithm,?PublicKey?publicKey,?String?signaturedData)?throws?Exception?{ ????????//?獲取簽名對象 ????????Signature?signature?=?Signature.getInstance(algorithm); ????????//?初始化簽名 ????????signature.initVerify(publicKey); ????????//?傳入原文 ????????signature.update(input.getBytes()); ????????//?校驗數據 ????????return?signature.verify(Base64.decode(signaturedData)); ????} }
運行,驗證成功:
________________________________________
拓展: 2.5 Byte和bit
Byte : 字節. 數據存儲的基本單位,比如移動硬盤1T , 單位是byte
bit : 比特, 又叫位. 一個位要么是0要么是1. 數據傳輸的單位 , 比如家里的寬帶100MB,下載速度并沒有達到100MB,一般都是12-13MB,那么是因為需要使用 100 / 8
關系: 1Byte = 8bit
2.5.1 獲取字符串byte
/** ?*?ByteBit ?* ?*?@Author:?陳志強 ?*?@CreateTime:?2020-10-12 ?*?@Description: ?*/ public?class?ByteBit?{ ????public?static?void?main(String[]?args)?{ ????????String?a?=?"a"; ????????byte[]?bytes?=?a.getBytes(); ????????for?(byte?b?:?bytes)?{ ????????????int?c=b; ????????????//?打印發現byte實際上就是ascii碼 ????????????System.out.println(c); ????????} ????} }
運行結果:
和ascii碼表一致
2.5.2 byte對應bit
public?class?ByteBit?{ ????public?static?void?main(String[]?args)?{ ????????String?a?=?"a"; ????????byte[]?bytes?=?a.getBytes(); ????????for?(byte?b?:?bytes)?{ ????????????int?c=b; ????????????//?打印發現byte實際上就是ascii碼 ????????????System.out.println(c); ????????????//?我們在來看看每個byte對應的bit,byte獲取對應的bit ????????????String?s?=?Integer.toBinaryString(c); ????????????System.out.println(s); ????????} ????} }
運行結果
2.5.3 中文對應的字節
package?com.huawei.it.jalor.boot.test; /** ?*?功能描述 ?* ?*?@author?cWX970190 ?*?@since?2020-10-11 ?*/ public?class?ByteBitDemo?{ ????public?static?void?main(String[]?args)?throws?Exception{ ????????String?a?=?"華"; ????????byte[]?bytes?=?a.getBytes(); ????????for?(byte?b?:?bytes)?{ ????????????System.out.print(b?+?"???"); ????????????String?s?=?Integer.toBinaryString(b); ????????????System.out.println(s); ????????} ????} }
運行程序,我們發現一個中文是有 3 個字節組成:
我們修改 編碼格式 , 編碼格式改成 GBK
修改代碼
//?UTF-8:編碼格式占3個字節 ????????byte[]?bytes?=?a.getBytes("GBK");
再運行發現變成了 2 個字節
2.5.4 英文對應的字節
/** ?*?ByteBit ?* ?*?@Author:?陳志強 ?*?@CreateTime:?2020-10-12 ?*?@Description: ?*/ public?class?ByteBit?{ ????public?static?void?main(String[]?args)?throws?Exception{ ????????String?a?=?"a"; ????????byte[]?bytes?=?a.getBytes(); ????????//?在中文情況下,不同的編碼格式,對應不同的字節 //????????byte[]?bytes?=?a.getBytes("GBK"); ????????for?(byte?b?:?bytes)?{ ????????????System.out.print(b?+?"???"); ????????????String?s?=?Integer.toBinaryString(b); ????????????System.out.println(s); ????????} ????} }
運行程序
________________________________________
三、如何設置密碼才安全
通過上述密碼學發展史的介紹,以及對常見加密算法的闡述,相信大家對密碼應該有了較為理性的認識,那么,如何設置密碼才安全呢?這里給出一點小建議:
密碼不要太常見,不要使用類似于123456式的常用密碼。
各應用軟件密碼建議不同,避免出現一個應用數據庫被脫庫,全部應用密碼崩塌,
可在設置密碼時增加注冊時間、注冊地點、應用特性等方法。例如tianjin123456,表示在天津注冊的該應用
參考文獻:
現代密碼學之對稱加密-DES及AES算法- element ui
http://element-ui.cn/article/show-97007.aspx
Java Base64 編碼與解碼----三種實現方式的代碼實例
https://blog.csdn.net/qq_27093465/article/details/93977519
網絡安全之密碼學:信息安全
https://www.bilibili.com/video/av583369085/
好了,本期的分享到此就跟大家saygoodbye了,密碼學博大精深,本文只是淺嘗輒止,關于密碼學的知識一直都在更新,希望下次可以給大家帶來更前沿、更實用的密碼學相關知識,喜歡的老鐵歡迎關注,筆芯!
Java
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。