1. 程式人生 > 實用技巧 >公鑰與私鑰

公鑰與私鑰

在對稱加密的時代,加密和解密用的是同一個金鑰,這個金鑰既用於加密,又用於解密。這樣做有一個明顯的缺點,如果兩個人之間傳輸檔案,兩個人都要知道金鑰,如果是三個人呢,五個人呢?於是就產生了非對稱加密,用一個金鑰進行加密(公鑰),用另一個金鑰進行解密(私鑰)

1.公鑰私鑰原理

張三有兩把鑰匙,一把是公鑰,另一把是私鑰。

張三把公鑰送給他的朋友們—-李四、王五、趙六—-每人一把。

李四要給張三寫一封保密的信。她寫完後用張三的公鑰加密,就可以達到保密的效果。

張三收信後,用私鑰解密,就看到了信件內容。這裡要強調的是,只要張三的私鑰不洩露,這封信就是安全的,即使落在別人手裡,也無法解密。

張三給李四回信,決定採用“數字簽名”。他寫完後先用Hash函式,生成信件的摘要(digest)。然後利用私鑰將摘要進行加密,張三將這個簽名,附在信件下面,一起發給李四。

李四收信後,取下數字簽名,用張三的公鑰解密,得到信件的摘要。由此證明,這封信確實是張三發出的。李四再對信件本身使用Hash函式,將得到的結果,與上一步得到的摘要進行對比。如果兩者一致,就證明這封信未被修改過。

2.生成私鑰公鑰

Spring Security 提供對JWT的支援,我們使用Spring Security 提供的JwtHelper來建立JWT令牌,校驗JWT令牌 等操作。 這裡JWT令牌我們採用非對稱演算法進行加密,所以我們要先生成公鑰和私鑰。

(1)生成金鑰證書 下邊命令生成金鑰證書,採用RSA 演算法每個證書包含公鑰和私鑰

建立一個資料夾,在該資料夾下執行如下命令列:

keytool 
-genkeypair 
-alias changgou 
-keyalg RSA 
-keypass changgou 
-keystore changgou.jks 
-storepass changgou 

Keytool 是一個java提供的證書管理工具

-alias:金鑰的別名
-keyalg:使用的hash演算法
-keypass:金鑰的訪問密碼 
-keystore:金鑰庫檔名,xc.keystore儲存了生成的證書 
-storepass:金鑰庫的訪問密碼

(2)查詢證書資訊

keytool -list -keystore changgou.jks

(3)刪除別名

keytool -delete -alias changgou -keystore changgou.jsk

4.2.3 匯出公鑰

openssl是一個加解密工具包,這裡使用openssl來匯出公鑰資訊。

安裝 openssl:http://slproweb.com/products/Win32OpenSSL.html

安裝資料目錄下的Win64OpenSSL-1_1_0g.exe

cmd進入changgou.jks檔案所在目錄執行如下命令(如下命令在windows下執行,會把-變成中文方式,請將它改成英文的-):

keytool -list -rfc --keystore changgou.jks | openssl x509 -inform pem -pubkey

將上邊的公鑰拷貝到文字public.key檔案中,合併為一行,可以將它放到需要實現授權認證的工程中。

4.2.4 JWT令牌

(1)建立令牌資料

public class Test {
    public static void main(String[] args) {
        /**
         * 金鑰證書檔案路徑
         */
        String key_location="changgou.jks";

        /**
         * 金鑰庫的訪問密碼
         */
        String key_password="changgou";

        /**
         * 金鑰的訪問密碼
         */
        String keypwd = "changgou";

        /**
         * 祕鑰別名
         */
        String alias = "changgou";

        /**
         * 訪問證書路徑
         */
        ClassPathResource resource = new ClassPathResource(key_location);
        /**
         * 建立祕鑰工廠
         * 資源路徑
         * 金鑰庫訪問密碼
         */
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource,key_password.toCharArray());

        /**
         * 讀取祕鑰對(公鑰、私鑰)
         * 金鑰別名
         * 金鑰訪問密碼
         */
        KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias,keypwd.toCharArray());

        /**
         * 獲取私鑰
         */
        RSAPrivateKey rsaPrivate = (RSAPrivateKey) keyPair.getPrivate();

        /**
         * 定義Payload
         */
        Map<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("id", "1");
        tokenMap.put("name", "itheima");
        tokenMap.put("roles", "ROLE_VIP,ROLE_USER");

        /**
         * 生成jwt令牌
         * 用私鑰加密
         */
        Jwt jwt = JwtHelper.encode(JSON.toJSONString(tokenMap), new RsaSigner(rsaPrivate));

        /**
         * 取出令牌
         */
        String encoded = jwt.getEncoded();
        System.out.println(encoded);

    }
}

(2)解析令牌

上面建立令牌後,我們可以對JWT令牌進行解析,這裡解析需要用到公鑰,我們可以將之前生成的公鑰public.key拷貝出來用字串變數token儲存,然後通過公鑰解密。

public class Test2 {
    public static void main(String[] args) {
        /**
         * 令牌
         */
        String token ="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6IlJPTEVfVklQLFJPTEVfVVNFUiIsIm5hbWUiOiJpdGhlaW1hIiwiaWQiOiIxIn0.oW1h0Xza7vUEgi0rzOlgMLdLicnJ7kFXg6pBjW640sxzeeiPC0cUfXEYAAmmTYEMQtLeivbZeiar-p5ydupUVhTVF8evEzqt64p31DJQ5tsIQ2-moXE8Q6W9JP2MY1sylBdN8rmVmIW6pqBh4KuLkFFalWd851HAzdQg95SvIbyUu6F6M-iZvL4-qcTdakYjpnWKOTWNBighB-hMlaAs6REMXyMsU0wo8DRHyNypUb4vILb_NPjd69ubFhOTUvLkYRtImEk8QNnQ8-l68GhAGmqifxDkNAz3I0f0Mcgfu3OdT056qcR6FG_o1thzOaXRZQliA1B2ZnZ3tepHv6ahxw";

        /**
         * 使用公鑰進行解密
         */
        String publickey ="-----BEGIN PUBLIC KEY-----\n" +
                "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA15w2T+DOwQzFxWa26bFq\n" +
                "1xhYdy49INE7vPC1D6+09P/c1byY6U7N3AStO3eYhT/v5TUwCfXobXZ98e2Gf1/O\n" +
                "KO/TmLFXOcoea9MP0kVcVV/80O6g19tzWDIkBbphO9g5E0lq/VwQYC0Cc3/4jNO0\n" +
                "87d5BwMdlSasqbJjA8MVDXjzupPDl+hw6Wr48motbJGgSzrOpNPZMJK25ylwlqac\n" +
                "TCetcjQXL4tpKcPXOaCEUFwWWxBUtFfwP+nU0PSDTUhwe6UsKtugnkAd1TYn9+bh\n" +
                "78J77CFwpFPxtfutSbP2E8/yxYKufUg6NYo+F3PRQQElTb/aH8zi4n+RIHvec2Zw\n" +
                "HwIDAQAB\n" +
                "-----END PUBLIC KEY-----";

        /**
         * 校驗jwt
         */
        Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(publickey));


        /**
         * 獲取Jwt原始內容
         */
        String claims = jwt.getClaims();
        System.out.println(claims);
    }
}