1. 程式人生 > >RSA加密和解密問題

RSA加密和解密問題

開始寫部落格完成就是記錄自己的工作內容,感覺比其他的方式更好一些

今天的問題是,大平臺有個介面,是返回一個公鑰的,我需要通過返回的公鑰字串在轉換成PublicKey然後加密資料在傳給大平臺,大平臺會通過私鑰進行解密。解密後會通過我傳入的引數返回給小平臺相應的資料。

直接進入主題

1、生成公私鑰

無論業務怎麼耍,一個應用繫結一個金鑰對也好,或者每次重新生成也好,這都無關緊要。

    public static Map<String, byte[]> generateKeyBytes() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(

"RSA");
            keyPairGenerator.initialize(
1024);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            Map<String, byte[]> keyMap = new HashMap<String, byte[]>();
            keyMap.put("publicKey", publicKey.getEncoded());
            keyMap.put("privateKey", privateKey.getEncoded());
            return keyMap;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

以上講解幾點:

1) 1024沒必要填寫,預設就是1024,RSA金鑰長度必須是64的倍數,在512~65536之間

2) 生成金鑰對KeyPair,再由金鑰對獲取公私鑰

3) 一般情況下,你的公私鑰和業務單元繫結時,就是儲存時,需要BASE64編一下:

String pubKeyString = Base64.encodeBase64String(keyMap.get("publicKey"));
        String pri
KeyString = Base64.encodeBase64String(keyMap.get("privateKey"));

生成這個公私鑰後,要做的就是和你的一個業務單元繫結,以後的資料由公鑰加密,私鑰解密。所以公鑰是要下發下去的。

2、加密解密

1) 一般的流程是,小平臺傳一個業務單元的code去大平臺,大平臺會根據code把對應的公鑰返回,返回的是String,所以第一步就是把符合RSA的String轉換成PublicKey.

下面是程式碼

public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = new Base64().decode(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
   }

感覺沒什麼好解釋的,傳入的就是你拿到的String公鑰。

 2) 加密是很簡單的,有了公鑰,有了需要加密的內容就可以了

public static byte[] RSAEncode(PublicKey key, byte[] plainText) {

        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(plainText);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException| InvalidKeyException | IllegalBlockSizeException| BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
}
 

內容下面一起解釋

3) 解密和加密差不多

   public static String RSADecode(PrivateKey key, byte[] encodedText) {

        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(encodedText));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

4) 呼叫一下就OK了

public static void main(String[] args) throws Exception {
PublicKey publicKey = getPublicKey(key);
        byte[] encodedText = RSAEncode(publicKey, PLAIN_TEXT.getBytes());
        System.out.println("RSA encoded: " + Base64.encodeBase64String(encodedText));
   
        // 解密
        PrivateKey privateKey = restorePrivateKey(keyMap.get(
“privateKey”));
        System.out.println("RSA decoded: " + RSADecode(privateKey, encodedText));
}

太長了,本來不想記錄解密來著,感覺也多不了多少內容,就記下吧,下面是還原私鑰的方法


    /**
    * 還原私鑰,PKCS8EncodedKeySpec 用於構建私鑰的規範
      * @param keyB
ytes 編碼後的byte[]格式的私鑰
      * @return
      */
    public static PrivateKey restorePrivateKey(byte[] keyBytes) {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
                keyBytes);
        try {
            KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = factory.generatePrivate(pkcs8EncodedKeySpec);
            return privateKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

因為存庫的時候,存的是String,所以呼叫返還私鑰的方法時,需要轉成byte[],這個很簡單 ,類似公鑰String轉byte[]的時候也有寫