1. 程式人生 > >JAVA RSA演算法工具類

JAVA RSA演算法工具類

RSAUtilV2

1.使用了兩個properties檔案分別儲存公/私鑰,具體儲存的為Base64編碼格式;
2.使用UUID 生成SecureRandom,每次都會生成不一樣的金鑰;
3.其中有個Provider的引數,沒有理會,字面意思就指提供這個生成金鑰演算法的提供者吧,Java預設有一些,可以自己打出來看看;
4.類中使用了slf4j規範的logger(關於這個,請自行搜尋學習了),如果不想用,可以把類中所有用LOGGER的地方,都換成Java自帶的異常捕獲;
5.我用的JDK 1.8,如果版本不夠,可能Base64用不了(不想用JDK 1.8,那麼需要自行下載一個帶Base64功能的JAR包,然後修改我使用Base64的地方);
6.包含’公鑰加密-私鑰解密’和’私鑰加密-公鑰解密’;
7.使用起來很簡單:直接複製程式碼,然後用類呼叫方法,比如 RSAUtilsV2.encryptByPublic(”test”.getBytes(),null);
8.完成這個類的時候,參考了很多網上的部落格,非常感謝每一位的分享;
接下來直接上程式碼:

/**
 * RSA演算法加密/解密工具類V2
 */
public class RSAUtilV2 {
    private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtils.class);
    /** 演算法名稱 */
    private static final String ALGORITHM =  "RSA";
    /** 預設金鑰大小 */
    private static final int KEY_SIZE = 1024;
    /** 用來指定儲存金鑰對的檔名和儲存的名稱 */
    private
static final String PUBLIC_KEY_NAME = "publicKey"; private static final String PRIVATE_KEY_NAME = "privateKey"; private static final String PUBLIC_FILENAME = "publicKey.properties"; private static final String PRIVATE_FILENAME = "privateKey.properties"; /** 金鑰對生成器 */ private static
KeyPairGenerator keyPairGenerator = null; private static KeyFactory keyFactory = null; /** 快取的金鑰對 */ private static KeyPair keyPair = null; /** Base64 編碼/解碼器 JDK1.8 */ private static Base64.Decoder decoder = Base64.getDecoder(); private static Base64.Encoder encoder = Base64.getEncoder(); /** 初始化金鑰工廠 */ static{ try { keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); keyFactory = KeyFactory.getInstance(ALGORITHM); } catch (NoSuchAlgorithmException e) { LOGGER.error(e.getMessage(),e); } } /** 私有構造器 */ private RSAUtilsV2(){} /** * 生成金鑰對 * 將金鑰分別用Base64編碼儲存到#publicKey.properties#和#privateKey.properties#檔案中 * 儲存的預設名稱分別為publicKey和privateKey */ public static synchronized void generateKeyPair(){ try { keyPairGenerator.initialize(KEY_SIZE,new SecureRandom(UUID.randomUUID().toString().replaceAll("-","").getBytes())); keyPair = keyPairGenerator.generateKeyPair(); } catch (InvalidParameterException e){ LOGGER.error("KeyPairGenerator does not support a key length of " + KEY_SIZE + ".",e); } catch (NullPointerException e){ LOGGER.error("RSAUtils#key_pair_gen is null,can not generate KeyPairGenerator instance.",e); } RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic(); RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate(); String publicKeyString = encoder.encodeToString(rsaPublicKey.getEncoded()); String privateKeyString = encoder.encodeToString(rsaPrivateKey.getEncoded()); storeKey(publicKeyString,PUBLIC_KEY_NAME,PUBLIC_FILENAME); storeKey(privateKeyString,PRIVATE_KEY_NAME,PRIVATE_FILENAME); } /** * 將指定的金鑰字串儲存到檔案中,如果找不到檔案,就建立 * @param keyString 金鑰的Base64編碼字串(值) * @param keyName 儲存在檔案中的名稱(鍵) * @param fileName 目標檔名 */ private static void storeKey(String keyString,String keyName,String fileName){ Properties properties = new Properties(); //存放金鑰的絕對地址 String path = null; try{ path = RSAUtils.class.getClassLoader().getResource(fileName).toString(); path = path.substring(path.indexOf(":") + 1); }catch (NullPointerException e){ //如果不存#fileName#就建立 LOGGER.warn("storeKey()# " + fileName + " is not exist.Begin to create this file."); String classPath = RSAUtils.class.getClassLoader().getResource("").toString(); String prefix = classPath.substring(classPath.indexOf(":") + 1); String suffix = fileName; File file = new File(prefix + suffix); try { file.createNewFile(); path = file.getAbsolutePath(); } catch (IOException e1) { LOGGER.error(fileName +" create fail.",e1); } } try(OutputStream out = new FileOutputStream(path)){ properties.setProperty(keyName,keyString); properties.store(out,"There is " + keyName); } catch (FileNotFoundException e) { LOGGER.error("ModulusAndExponent.properties is not found.",e); } catch (IOException e) { LOGGER.error("OutputStream output failed.",e); } } /** * 獲取金鑰字串 * @param keyName 需要獲取的金鑰名 * @param fileName 金鑰所在檔案 * @return Base64編碼的金鑰字串 */ private static String getKeyString(String keyName,String fileName){ if (RSAUtils.class.getClassLoader().getResource(fileName) == null){ LOGGER.warn("getKeyString()# " + fileName + " is not exist.Will run #generateKeyPair()# firstly."); generateKeyPair(); } try(InputStream in = RSAUtils.class.getClassLoader().getResource(fileName).openStream()){ Properties properties = new Properties(); properties.load(in); return properties.getProperty(keyName); } catch (IOException e) { LOGGER.error("getKeyString()#" + e.getMessage(),e); } return null; } /** * 從檔案獲取RSA公鑰 * @return RSA公鑰 * @throws InvalidKeySpecException */ public static RSAPublicKey getPublicKey(){ try { byte[] keyBytes = decoder.decode(getKeyString(PUBLIC_KEY_NAME,PUBLIC_FILENAME)); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); return (RSAPublicKey)keyFactory.generatePublic(x509EncodedKeySpec); }catch (InvalidKeySpecException e) { LOGGER.error("getPublicKey()#" + e.getMessage(),e); } return null; } /** * 從檔案獲取RSA私鑰 * @return RSA私鑰 * @throws InvalidKeySpecException */ public static RSAPrivateKey getPrivateKey(){ try { byte[] keyBytes = decoder.decode(getKeyString(PRIVATE_KEY_NAME,PRIVATE_FILENAME)); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); return (RSAPrivateKey)keyFactory.generatePrivate(pkcs8EncodedKeySpec); } catch (InvalidKeySpecException e) { LOGGER.error("getPrivateKey()#" + e.getMessage(),e); } return null; } /** * RSA公鑰加密 * @param content 等待加密的資料 * @param publicKey RSA 公鑰 if null then getPublicKey() * @return 加密後的密文(16進位制的字串) */ public static String encryptByPublic(byte[] content,PublicKey publicKey){ if (publicKey == null){ publicKey = getPublicKey(); } try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE,publicKey); //該金鑰能夠加密的最大位元組長度 int splitLength = ((RSAPublicKey)publicKey).getModulus().bitLength() / 8 -11; byte[][] arrays = splitBytes(content,splitLength); StringBuffer stringBuffer = new StringBuffer(); for (byte[] array : arrays){ stringBuffer.append(bytesToHexString(cipher.doFinal(array))); } return stringBuffer.toString(); } catch (NoSuchAlgorithmException e) { LOGGER.error("encrypt()#NoSuchAlgorithmException",e); } catch (NoSuchPaddingException e) { LOGGER.error("encrypt()#NoSuchPaddingException",e); } catch (InvalidKeyException e) { LOGGER.error("encrypt()#InvalidKeyException",e); } catch (BadPaddingException e) { LOGGER.error("encrypt()#BadPaddingException",e); } catch (IllegalBlockSizeException e) { LOGGER.error("encrypt()#IllegalBlockSizeException",e); } return null; } /** * RSA私鑰加密 * @param content 等待加密的資料 * @param privateKey RSA 私鑰 if null then getPrivateKey() * @return 加密後的密文(16進位制的字串) */ public static String encryptByPrivate(byte[] content,PrivateKey privateKey){ if (privateKey == null){ privateKey = getPrivateKey(); } try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE,privateKey); //該金鑰能夠加密的最大位元組長度 int splitLength = ((RSAPrivateKey)privateKey).getModulus().bitLength() / 8 -11; byte[][] arrays = splitBytes(content,splitLength); StringBuffer stringBuffer = new StringBuffer(); for(byte[] array : arrays){ stringBuffer.append(bytesToHexString(cipher.doFinal(array))); } return stringBuffer.toString(); } catch (NoSuchAlgorithmException e) { LOGGER.error("encrypt()#NoSuchAlgorithmException",e); } catch (NoSuchPaddingException e) { LOGGER.error("encrypt()#NoSuchPaddingException",e); } catch (InvalidKeyException e) { LOGGER.error("encrypt()#InvalidKeyException",e); } catch (BadPaddingException e) { LOGGER.error("encrypt()#BadPaddingException",e); } catch (IllegalBlockSizeException e) { LOGGER.error("encrypt()#IllegalBlockSizeException",e); } return null; } /** * RSA私鑰解密 * @param content 等待解密的資料 * @param privateKey RSA 私鑰 if null then getPrivateKey() * @return 解密後的明文 */ public static String decryptByPrivate(String content,PrivateKey privateKey){ if (privateKey == null){ privateKey = getPrivateKey(); } try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE,privateKey); //該金鑰能夠加密的最大位元組長度 int splitLength = ((RSAPrivateKey)privateKey).getModulus().bitLength() / 8; byte[] contentBytes = hexStringToBytes(content); byte[][] arrays = splitBytes(contentBytes,splitLength); StringBuffer stringBuffer = new StringBuffer(); String sTemp = null; for (byte[] array : arrays){ stringBuffer.append(new String(cipher.doFinal(array))); } return stringBuffer.toString(); } catch (NoSuchAlgorithmException e) { LOGGER.error("encrypt()#NoSuchAlgorithmException",e); } catch (NoSuchPaddingException e) { LOGGER.error("encrypt()#NoSuchPaddingException",e); } catch (InvalidKeyException e) { LOGGER.error("encrypt()#InvalidKeyException",e); } catch (BadPaddingException e) { LOGGER.error("encrypt()#BadPaddingException",e); } catch (IllegalBlockSizeException e) { LOGGER.error("encrypt()#IllegalBlockSizeException",e); } return null; } /** * RSA公鑰解密 * @param content 等待解密的資料 * @param publicKey RSA 公鑰 if null then getPublicKey() * @return 解密後的明文 */ public static String decryptByPublic(String content,PublicKey publicKey){ if (publicKey == null){ publicKey = getPublicKey(); } try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE,publicKey); //該金鑰能夠加密的最大位元組長度 int splitLength = ((RSAPublicKey)publicKey).getModulus().bitLength() / 8; byte[] contentBytes = hexStringToBytes(content); byte[][] arrays = splitBytes(contentBytes,splitLength); StringBuffer stringBuffer = new StringBuffer(); String sTemp = null; for (byte[] array : arrays){ stringBuffer.append(new String(cipher.doFinal(array))); } return stringBuffer.toString(); } catch (NoSuchAlgorithmException e) { LOGGER.error("encrypt()#NoSuchAlgorithmException",e); } catch (NoSuchPaddingException e) { LOGGER.error("encrypt()#NoSuchPaddingException",e); } catch (InvalidKeyException e) { LOGGER.error("encrypt()#InvalidKeyException",e); } catch (BadPaddingException e) { LOGGER.error("encrypt()#BadPaddingException",e); } catch (IllegalBlockSizeException e) { LOGGER.error("encrypt()#IllegalBlockSizeException",e); } return null; } /** * 根據限定的每組位元組長度,將位元組陣列分組 * @param bytes 等待分組的位元組組 * @param splitLength 每組長度 * @return 分組後的位元組組 */ public static byte[][] splitBytes(byte[] bytes,int splitLength){ //bytes與splitLength的餘數 int remainder = bytes.length % splitLength; //資料拆分後的組數,餘數不為0時加1 int quotient = remainder != 0 ? bytes.length / splitLength + 1:bytes.length / splitLength; byte[][] arrays = new byte[quotient][]; byte[] array = null; for (int i =0;i<quotient;i++){ //如果是最後一組(quotient-1),同時餘數不等於0,就將最後一組設定為remainder的長度 if (i == quotient -1 && remainder != 0){ array = new byte[remainder]; System.arraycopy(bytes,i * splitLength,array,0,remainder); } else { array = new byte[splitLength]; System.arraycopy(bytes,i*splitLength,array,0,splitLength); } arrays[i] = array; } return arrays; } /** * 將位元組陣列轉換成16進位制字串 * @param bytes 即將轉換的資料 * @return 16進位制字串 */ public static String bytesToHexString(byte[] bytes){ StringBuffer sb = new StringBuffer(bytes.length); String temp = null; for (int i = 0;i< bytes.length;i++){ temp = Integer.toHexString(0xFF & bytes[i]); if(temp.length() <2){ sb.append(0); } sb.append(temp); } return sb.toString(); } /** * 將16進位制字串轉換成位元組陣列 * @param hex 16進位制字串 * @return byte[] */ public static byte[] hexStringToBytes(String hex){ int len = (hex.length() / 2); hex = hex.toUpperCase(); byte[] result = new byte[len]; char[] chars = hex.toCharArray(); for (int i= 0;i<len;i++){ int pos = i * 2; result[i] = (byte)(toByte(chars[pos]) << 4 | toByte(chars[pos + 1])); } return result; } /** * 將char轉換為byte * @param c char * @return byte */ private static byte toByte(char c){ return (byte)"0123456789ABCDEF".indexOf(c); } }

比如下面這樣使用(如果出錯,請檢查,或者評論,我看到或者說我能解決,我就會回覆):

public class TestMain {
    public static void main(String[] args) {
        String s = "test";
        String c1 = RSAUtilsV2.encryptByPublic(s.getBytes(),null);
        String m1 = RSAUtilsV2.decryptByPrivate(c1,null);
        String c2 = RSAUtilsV2.encryptByPrivate(s.getBytes(),null);
        String m2 = RSAUtilsV2.decryptByPublic(c2,null);
        System.out.println(c1);
        System.out.println(m1);
        System.out.println(c2);
        System.out.println(m2);
    }
}

結果:
這裡寫圖片描述