天天看點

PKI - 非對稱加密算法1. 密鑰交換算法(DH&ECDH)2. 典型非對稱加密算法 - RSA3. 常用非對稱加密算法 - ElGamal

非對稱加密算法

  • 1. 密鑰交換算法(DH&ECDH)
    • 1.1 DH
    • 1.2 ECDH
  • 2. 典型非對稱加密算法 - RSA
  • 3. 常用非對稱加密算法 - ElGamal

密鑰管理是對稱加密算法系統不容忽視的問題,它成為安全系統中最為薄弱的環節。為了彌補這一弱勢,非對稱加密算法應運而生。

非對稱加密算法源于DH算法(Diffie-Hellman,密鑰交換算法),由W.Diffie和M.Hellman共同提出。該算法為非對稱加密算法奠定了基礎,堪稱非對稱加密算法之鼻祖。

DH算法提出後,國際上相繼出現了各種實用性更強的非對稱加密算法,其構成主要是基于數學問題的求解,主要分為兩類:

  • 基于因子分解難題。RSA算法是最為典型的非對稱加密算法,該算法由美國麻省理工學院(MIT)的Ron Rivest、Adi Shamir和Leonard Adleman三位學者提出,并以這三位學者的姓氏開頭字母命名,稱為RSA算法。RSA算法是當今應用範圍最為廣泛的非對稱加密算法,也是第一個既能用于資料加密也能用于數字簽名的算法。
  • 基于離散對數難題。ElGamal算法由TaherElGamal提出,以自己的名字命名。該算法既可用于加密/解密,也可用于數字簽名,并為數字簽名算法形成标準提供參考。美國的DSS(Digital Signature Standard,資料簽名标準)的DSA(Digital Signature Algorithm,數字簽名算法)經ElGamal算法演變而來。

ECC(Elliptical Curve Cryptography,橢圓曲線加密)算法以橢圓曲線理論為基礎,在建立密鑰時可做到更快、更小,并且更有效。ECC算法通過橢圓曲線方程式的性質産生密鑰,而不是采用傳統的方法利用大質數的積來産生。

1. 密鑰交換算法(DH&ECDH)

1.1 DH

對稱加密算法提高資料安全性的同時帶來了密鑰管理的複雜性。消息收發雙方若想發送加密消息,必須事先約定好加密算法并發放密鑰。而如何安全的傳遞密鑰,成為對稱加密算法的一個棘手問題。密鑰交換算法(Diffie-Hellman算法,簡稱DH算法)成為解決這一問題的金鑰匙!

代碼實作

public static final String KEY_ALGORITHM = "DH";
public static final String SECRET_ALGORITHM = "AES";
public static final int KEY_SIZE = 512;
public static final String PUBLIC_KEY = "DHPublicKey";
public static final String PRIVATE_KEY = "DHPrivateKey";

/**
 * 生成甲方密鑰對(含公鑰、私鑰)
 *
 * @return map
 * @throws Exception 異常
 */
public Map<String, Object> initKey() throws Exception {
    // 初始化密鑰對生成器
    final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
    keyPairGenerator.initialize(KEY_SIZE);

    // 生成密鑰對
    final KeyPair keyPair = keyPairGenerator.generateKeyPair();
    // 擷取公鑰
    final PublicKey publicKey = keyPair.getPublic();
    // 擷取私鑰
    final PrivateKey privateKey = keyPair.getPrivate();

    // 構造傳回map
    Map<String, Object> keyMap = new HashMap<>();
    keyMap.put(PUBLIC_KEY, publicKey);
    keyMap.put(PRIVATE_KEY, privateKey);

    return keyMap;
}
           
/**
 * 根據甲方公鑰生成乙方密鑰對(含公鑰、私鑰)
 *
 * @param key 甲方公鑰
 * @return map
 * @throws Exception 異常
 */
public Map<String, Object> initKey(byte[] key) throws Exception {
    // 解析甲方公鑰
    final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
    // 執行個體化密鑰工廠
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 産生甲方公鑰
    final PublicKey aPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);

    // 由甲方公鑰建構乙方密鑰
    final DHParameterSpec dhParameterSpec = ((DHPublicKey) aPublicKey).getParams();
    // 初始化密鑰對生成器
    final KeyPairGenerator dh = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
    dh.initialize(dhParameterSpec);
    // 生成密鑰對
    final KeyPair keyPair = dh.generateKeyPair();
    // 擷取公鑰
    final PublicKey publicKey = keyPair.getPublic();
    // 擷取私鑰
    final PrivateKey privateKey = keyPair.getPrivate();

    // 構造傳回map
    Map<String, Object> keyMap = new HashMap<>();
    keyMap.put(PUBLIC_KEY, publicKey);
    keyMap.put(PRIVATE_KEY, privateKey);
    return keyMap;
}
           
/**
 * 生成密鑰
 * @param publicKey 對方公鑰
 * @param privateKey 自己私鑰
 * @return 密鑰
 * @throws Exception 異常
 */
public byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws Exception {
    // 初始化密鑰工廠
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

    // 初始化公鑰
    final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
    final PublicKey pubKey = keyFactory.generatePublic(x509EncodedKeySpec);

    // 初始化私鑰
    final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey);
    final PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

    // 執行個體化
    final KeyAgreement keyAgreement = KeyAgreement.getInstance(keyFactory.getAlgorithm());
    keyAgreement.init(priKey);
    keyAgreement.doPhase(pubKey, true);

    // 生成本地密鑰
    final SecretKey secretKey = keyAgreement.generateSecret(SECRET_ALGORITHM);
    return secretKey.getEncoded();
}
           
/**
 * 取得公鑰
 *
 * @param keyMap 密鑰map
 * @return 公鑰
 */
public byte[] getPublicKey(Map<String, Object> keyMap) {
    final Key key = (Key) keyMap.get(PUBLIC_KEY);
    return key.getEncoded();
}

/**
 * 取得私鑰
 *
 * @param keyMap 密鑰map
 * @return 私鑰
 */
public byte[] getPrivateKey(Map<String, Object> keyMap) {
    final Key key = (Key) keyMap.get(PRIVATE_KEY);
    return key.getEncoded();
}
           
/**
 * 資料加密
 *
 * @param data 待加密資料
 * @param key  密鑰
 * @return 加密後資料
 */
public byte[] encrypt(byte[] data, byte[] key) throws Exception {
    // 生成本地密鑰
    final SecretKeySpec secretKeySpec = new SecretKeySpec(key, SECRET_ALGORITHM);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(secretKeySpec.getAlgorithm());
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    return cipher.doFinal(data);
}

/**
 * 資料解密
 *
 * @param data 待解密資料
 * @param key  密鑰
 * @return 解密後資料
 */
public byte[] decrypt(byte[] data, byte[] key) throws Exception {
    // 生成本地密鑰
    final SecretKeySpec secretKeySpec = new SecretKeySpec(key, SECRET_ALGORITHM);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(secretKeySpec.getAlgorithm());
    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    return cipher.doFinal(data);
}
           

測試用例

@Test
public void testDH() throws Exception {
    final Map<String, Object> aKeyMap = initKey();
    final byte[] aPublicKey = getPublicKey(aKeyMap);
    final byte[] aPrivateKey = getPrivateKey(aKeyMap);
    System.out.println("甲方公鑰:" + Base64.toBase64String(aPublicKey));
    System.out.println("甲方私鑰:" + Base64.toBase64String(aPrivateKey));

    final Map<String, Object> bKeyMap = initKey(aPublicKey);
    final byte[] bPublicKey = getPublicKey(bKeyMap);
    final byte[] bPrivateKey = getPrivateKey(bKeyMap);
    System.out.println("乙方公鑰:" + Base64.toBase64String(bPublicKey));
    System.out.println("乙方私鑰:" + Base64.toBase64String(bPrivateKey));

    final byte[] aSecretKey = getSecretKey(bPublicKey, aPrivateKey);
    final byte[] bSecretKey = getSecretKey(aPublicKey, bPrivateKey);
    System.out.println("甲方密鑰:" + Base64.toBase64String(aSecretKey));
    System.out.println("乙方密鑰:" + Base64.toBase64String(bSecretKey));

    final byte[] aEncrypt = encrypt("我是阿湯哥".getBytes(), aSecretKey);
    final byte[] bDecrypt = decrypt(aEncrypt, bSecretKey);
    System.out.println("甲方加密消息:" + Base64.toBase64String(aEncrypt));
    System.out.println("乙方解密消息:" + Base64.toBase64String(bDecrypt));

    final byte[] bEncrypt = encrypt("Hello, 阿湯哥".getBytes(), bSecretKey);
    final byte[] aDecrypt = decrypt(bEncrypt, aSecretKey);
    System.out.println("乙方加密消息:" + Base64.toBase64String(bEncrypt));
    System.out.println("甲方解密消息:" + Base64.toBase64String(aDecrypt));
}
           

使用jdk8執行本用例時如果報錯

java.security.NoSuchAlgorithmException: Unsupported secret key algorithm: AES

	at com.sun.crypto.provider.DHKeyAgreement.engineGenerateSecret(DHKeyAgreement.java:387)
	at javax.crypto.KeyAgreement.generateSecret(KeyAgreement.java:648)
	at com.jd.eps.eis.product.core.config.DHTest.getSecretKey(DHTest.java:110)
	at com.jd.eps.eis.product.core.config.DHTest.testDH(DHTest.java:183)
           

可以通過增加vm參數

-Djdk.crypto.KeyAgreement.legacyKDF=true

解決。

執行結果

甲方公鑰:MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBAMCeFF4M4gFXNabyak7DplZnTVPJCNpw9eOao4BWNrdu8ptUiTg4kwmP8bxjot873vQ7QDg4cPyTFJGZ/c3HApE=
甲方私鑰:MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEA1f2vYbDfzWpVlX8ib4ftWD5q24Mzh74C0L+ze8ienkfwv41dErOl0HqZOmmf18HN
乙方公鑰:MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBAJ3BzkiX8n6RurBasjqLYwCbewwX0ZkWykCzyQj6y/4uBgNX0m+0bgPX1emxlFt/N3ueC8803OhNcprcHRxschY=
乙方私鑰:MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAqi55vmMEF5pfS4//fvfqELLlo817cCRlRMOZ+sQ9HLtroIJ16x7RWusDpK75dqxA
甲方密鑰:sSVOKIBcVtQ5h806csVXzmkPZWUhC75Xp9glwAjFWhY=
乙方密鑰:sSVOKIBcVtQ5h806csVXzmkPZWUhC75Xp9glwAjFWhY=
甲方加密消息:DPftIVbpAGj7dkF73QB4zw==
乙方解密消息:我是阿湯哥
乙方加密消息:FTZnyPN+ZAzdqU4vEKjkMCo6U0TLlKPDyL3zoBSGvvQ=
甲方解密消息:Hello, 阿湯哥
           

1.2 ECDH

JDK8沒有ECDH的實作,需要添加Provider。

根據甲方公鑰生成乙方密鑰對時需對ParameterSpec進行調整。

/**
 * 根據甲方公鑰生成乙方密鑰對(含公鑰、私鑰)
 *
 * @param key 甲方公鑰
 * @return map
 * @throws Exception 異常
 */
public Map<String, Object> initKey(byte[] key) throws Exception {
    // 解析甲方公鑰
    final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
    // 執行個體化密鑰工廠
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 産生甲方公鑰
    final PublicKey aPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);

    // 由甲方公鑰建構乙方密鑰
    final ECParameterSpec ecParameterSpec = ((ECPublicKey) aPublicKey).getParams();
    // 初始化密鑰對生成器
    final KeyPairGenerator dh = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
    dh.initialize(ecParameterSpec);
    // 生成密鑰對
    final KeyPair keyPair = dh.generateKeyPair();
    // 擷取公鑰
    final PublicKey publicKey = keyPair.getPublic();
    // 擷取私鑰
    final PrivateKey privateKey = keyPair.getPrivate();

    // 構造傳回map
    Map<String, Object> keyMap = new HashMap<>();
    keyMap.put(PUBLIC_KEY, publicKey);
    keyMap.put(PRIVATE_KEY, privateKey);
    return keyMap;
}
           

2. 典型非對稱加密算法 - RSA

代碼實作

public static final String KEY_ALGORITHM = "RSA";
public static final int KEY_SIZE = 512;
public static final String PUBLIC_KEY = "DHPublicKey";
public static final String PRIVATE_KEY = "DHPrivateKey";

/**
 * 生成甲方密鑰對(含公鑰、私鑰)
 *
 * @return map
 * @throws Exception 異常
 */
public Map<String, Object> initKey() throws Exception {
    // 初始化密鑰對生成器
    final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
    keyPairGenerator.initialize(KEY_SIZE);

    // 生成密鑰對
    final KeyPair keyPair = keyPairGenerator.generateKeyPair();
    // 擷取公鑰
    final PublicKey publicKey = keyPair.getPublic();
    // 擷取私鑰
    final PrivateKey privateKey = keyPair.getPrivate();

    // 構造傳回map
    Map<String, Object> keyMap = new HashMap<>();
    keyMap.put(PUBLIC_KEY, publicKey);
    keyMap.put(PRIVATE_KEY, privateKey);

    return keyMap;
}

/**
 * 取得公鑰
 *
 * @param keyMap 密鑰map
 * @return 公鑰
 */
public byte[] getPublicKey(Map<String, Object> keyMap) {
    final Key key = (Key) keyMap.get(PUBLIC_KEY);
    return key.getEncoded();
}

/**
 * 取得私鑰
 *
 * @param keyMap 密鑰map
 * @return 私鑰
 */
public byte[] getPrivateKey(Map<String, Object> keyMap) {
    final Key key = (Key) keyMap.get(PRIVATE_KEY);
    return key.getEncoded();
}
           
/**
 * 使用私鑰加密資料
 *
 * @param data       待加密資料
 * @param privateKey 私鑰
 * @return 加密後資料
 */
public byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
    // 擷取私鑰
    final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey);
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 生成私鑰
    final PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.ENCRYPT_MODE, priKey);
    return cipher.doFinal(data);
}

/**
 * 使用公鑰解密資料
 *
 * @param data      待解密資料
 * @param publicKey 公鑰
 * @return 解密後資料
 */
public byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
    // 擷取公鑰
    final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 生成公鑰
    final PublicKey pubKey = keyFactory.generatePublic(x509EncodedKeySpec);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.DECRYPT_MODE, pubKey);
    return cipher.doFinal(data);
}
           
/**
 * 使用公鑰加密資料
 *
 * @param data      待解密資料
 * @param publicKey 公鑰
 * @return 解密後資料
 */
public byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
    // 擷取公鑰
    final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 生成公鑰
    final PublicKey pubKey = keyFactory.generatePublic(x509EncodedKeySpec);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    return cipher.doFinal(data);
}

/**
 * 使用私鑰解密資料
 *
 * @param data       待加密資料
 * @param privateKey 私鑰
 * @return 加密後資料
 */
public byte[] decryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
    // 擷取私鑰
    final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey);
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 生成私鑰
    final PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.DECRYPT_MODE, priKey);
    return cipher.doFinal(data);
}
           
@Test
public void testRSA() throws Exception {
    Security.addProvider(new BouncyCastleProvider());

    final Map<String, Object> aKeyMap = initKey();
    final byte[] aPublicKey = getPublicKey(aKeyMap);
    final byte[] aPrivateKey = getPrivateKey(aKeyMap);
    System.out.println("甲方公鑰:" + Base64.toBase64String(aPublicKey));
    System.out.println("甲方私鑰:" + Base64.toBase64String(aPrivateKey));


    final byte[] aEncrypt = encryptByPrivateKey("我是阿湯哥".getBytes(), aPrivateKey);
    final byte[] bDecrypt = decryptByPublicKey(aEncrypt, aPublicKey);
    System.out.println("甲方:使用甲方私鑰加密消息:" + Base64.toBase64String(aEncrypt));
    System.out.println("乙方:使用甲方公鑰解密消息:" + new String(bDecrypt));

    final byte[] bEncrypt = encryptByPublicKey("Hello, 阿湯哥".getBytes(), aPublicKey);
    final byte[] aDecrypt = decryptByPrivateKey(bEncrypt, aPrivateKey);
    System.out.println("乙方:使用甲方公鑰加密消息:" + Base64.toBase64String(bEncrypt));
    System.out.println("甲方:使用甲方私鑰解密消息:" + new String(aDecrypt));
}
           

執行結果

甲方公鑰:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ7vEoMQFnSZq8tIKydTxeZQZbg3EzZ+uoqMB6xYUz0bJKTLBE2VdT8SKmhCFjyBLzRla8bCl5EtLB/S3F/isD0CAwEAAQ==
甲方私鑰:MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAnu8SgxAWdJmry0grJ1PF5lBluDcTNn66iowHrFhTPRskpMsETZV1PxIqaEIWPIEvNGVrxsKXkS0sH9LcX+KwPQIDAQABAkAePbMyCP+c1BiiJ2s+omwHdMjGEoSvW9G2xwo2ut+rwo+UiKX/OXtjggNL32sOG/VBpmwQnCzhHXlM3Uf/AyLBAiEA0j02vlbqrkb4eLLTX/K1ZXk05xFMaxjCfqIdv9VwqykCIQDBhxD/jP48lN/I/cNQjg4710e46gL5U3TvDfmpXZYS9QIgYAHkRfebJAr03OmM7XwAql43cm3L3/xmlT2jKD9oPEECIBAgRh1VTVYU/bTM2Hqc67i2zqYs8cR+3M6StowTXU8FAiAp+LnIyULp1obJN9ZnLRv5RldROa9Evj94cfDq3gu+QQ==
甲方:使用甲方私鑰加密消息:lK3A3bNyxV1xc34st8fOtIy5vyjTL1zm7wbU9v5mV21t0hxf1ZLTdvN5+vZPSylF3th0c0KqSdGNLpaazvEYSg==
乙方:使用甲方公鑰解密消息:我是阿湯哥
乙方:使用甲方公鑰加密消息:msiUhALltZYWQdpDWpp6X4wmDCR3ZVGw4d3AqYBnnwDloNDBivpBhT4LgWseX7x74GpgKFA1g/mpsKCIoXqOiw==
甲方:使用甲方私鑰解密消息:Hello, 阿湯哥
           

3. 常用非對稱加密算法 - ElGamal

代碼實作

public static final String KEY_ALGORITHM = "ElGamal";
public static final int KEY_SIZE = 256;
public static final String PUBLIC_KEY = "ElGamalPublicKey";
public static final String PRIVATE_KEY = "ElGamalPrivateKey";

/**
 * 生成甲方密鑰對(含公鑰、私鑰)
 *
 * @return map
 * @throws Exception 異常
 */
public Map<String, Object> initKey() throws Exception {
    // 加入BouncyCastleProvider支援
    Security.addProvider(new BouncyCastleProvider());
    // 執行個體化算法參數生成器
    final AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
    // 初始化算法生成器
    apg.init(KEY_SIZE);
    // 生成算法參數
    final AlgorithmParameters parameters = apg.generateParameters();
    // 建構參數材料
    final DHParameterSpec dhParameterSpec = parameters.getParameterSpec(DHParameterSpec.class);
    // 執行個體化密鑰對生成器
    final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
    keyPairGenerator.initialize(dhParameterSpec, new SecureRandom());

    // 生成密鑰對
    final KeyPair keyPair = keyPairGenerator.generateKeyPair();
    // 擷取公鑰
    final PublicKey publicKey = keyPair.getPublic();
    // 擷取私鑰
    final PrivateKey privateKey = keyPair.getPrivate();

    // 構造傳回map
    Map<String, Object> keyMap = new HashMap<>();
    keyMap.put(PUBLIC_KEY, publicKey);
    keyMap.put(PRIVATE_KEY, privateKey);

    return keyMap;
}

/**
 * 取得公鑰
 *
 * @param keyMap 密鑰map
 * @return 公鑰
 */
public byte[] getPublicKey(Map<String, Object> keyMap) {
    final Key key = (Key) keyMap.get(PUBLIC_KEY);
    return key.getEncoded();
}

/**
 * 取得私鑰
 *
 * @param keyMap 密鑰map
 * @return 私鑰
 */
public byte[] getPrivateKey(Map<String, Object> keyMap) {
    final Key key = (Key) keyMap.get(PRIVATE_KEY);
    return key.getEncoded();
}
           
/**
 * 使用公鑰加密資料
 *
 * @param data      待解密資料
 * @param publicKey 公鑰
 * @return 解密後資料
 */
public byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
    Security.addProvider(new BouncyCastleProvider());
    // 擷取公鑰
    final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 生成公鑰
    final PublicKey pubKey = keyFactory.generatePublic(x509EncodedKeySpec);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    return cipher.doFinal(data);
}

/**
 * 使用私鑰解密資料
 *
 * @param data       待加密資料
 * @param privateKey 私鑰
 * @return 加密後資料
 */
public byte[] decryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
    Security.addProvider(new BouncyCastleProvider());
    // 擷取私鑰
    final PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey);
    final KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    // 生成私鑰
    final PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    // 資料加密
    final Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.DECRYPT_MODE, priKey);
    return cipher.doFinal(data);
}
           
@Test
public void testRSA() throws Exception {
    Security.addProvider(new BouncyCastleProvider());

    final Map<String, Object> bKeyMap = initKey();
    final byte[] bPublicKey = getPublicKey(bKeyMap);
    final byte[] bPrivateKey = getPrivateKey(bKeyMap);
    System.out.println("乙方公鑰:" + Base64.toBase64String(bPublicKey));
    System.out.println("乙方私鑰:" + Base64.toBase64String(bPrivateKey));

    final byte[] aEncrypt = encryptByPublicKey("我是阿湯哥".getBytes(), bPublicKey);
    final byte[] bDecrypt = decryptByPrivateKey(aEncrypt, bPrivateKey);
    System.out.println("甲方:使用乙方公鑰加密消息:" + Base64.toBase64String(aEncrypt));
    System.out.println("乙方:使用乙方私鑰解密消息:" + new String(bDecrypt));
}
           

執行結果

乙方公鑰:MHYwTwYGKw4HAgEBMEUCIQD3Tow0iMrSnqcab/qk3sixGNZsFqerw5TZS8AthdG9/wIgVwGItAIOERVrOUQuvYUf4iBgNedVcIVEMpmCAAF67GsDIwACICuSrF+jA6g2XGfFjtP8zmZWA0LstwQQgsMBB6AYuA1/
乙方私鑰:MHgCAQAwTwYGKw4HAgEBMEUCIQD3Tow0iMrSnqcab/qk3sixGNZsFqerw5TZS8AthdG9/wIgVwGItAIOERVrOUQuvYUf4iBgNedVcIVEMpmCAAF67GsEIgIgS99qTF3QgAjIKNcpPaA5jnTSp6AUOqb1XhOGGtr75iw=
甲方:使用乙方公鑰加密消息:3sdh+pOViDQWU8aDO/LC1SnK427qrFc8PHrMVyE+k7MbL7tQHbq+5I7MZ0vz7WAc6ysAvVZU9pg8YcQvoYWoEw==
乙方:使用乙方私鑰解密消息:我是阿湯哥
           

繼續閱讀