天天看點

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 = ;
    /** 用來指定儲存密鑰對的檔案名和存儲的名稱 */
    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(":") + );
        }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(":") + );
            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() /  -;
            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() /  -;
            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() / ;
            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() / ;
            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 !=  ? bytes.length / splitLength + :bytes.length / splitLength;
        byte[][] arrays = new byte[quotient][];
        byte[] array = null;
        for (int i =;i<quotient;i++){
            //如果是最後一組(quotient-1),同時餘數不等于0,就将最後一組設定為remainder的長度
            if (i == quotient - && remainder != ){
                array = new byte[remainder];
                System.arraycopy(bytes,i * splitLength,array,,remainder);
            } else {
                array = new byte[splitLength];
                System.arraycopy(bytes,i*splitLength,array,,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 = ;i< bytes.length;i++){
            temp = Integer.toHexString( & bytes[i]);
            if(temp.length() <){
                sb.append();
            }
            sb.append(temp);
        }
        return sb.toString();
    }

    /**
     * 将16進制字元串轉換成位元組數組
     * @param hex 16進制字元串
     * @return byte[]
     */
    public static byte[] hexStringToBytes(String hex){
        int len = (hex.length() / );
        hex = hex.toUpperCase();
        byte[] result = new byte[len];
        char[] chars = hex.toCharArray();
        for (int i= ;i<len;i++){
            int pos = i * ;
            result[i] = (byte)(toByte(chars[pos]) <<  | toByte(chars[pos + ]));
        }
        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);
    }
}
           

結果:

JAVA RSA算法工具類