一、什么是非对称加密算法?
简单点讲,就是加密密钥和解密密钥不一样的一种加密算法。非对称加密是指通过特定算法获取一对密钥对:公钥和私钥,公钥可以对外公开,私钥由你自己保存。我们使用其中一个密钥对数据进行加密,使用另一个密钥对加密后的数据进行解密。
优点:保密性比较好,不需要用户交换密钥,不适合于对文件加密;
缺点:加密和解密花费时间长、速度慢,适用于对少量数据进行加密。
常见的非对称加密算法有:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)。
二、RSA加解密
PKCS1Padding,最常用的填充方式,要求
输入:必须 比 密钥长度 短至少11个字节, 也就是 KEYSIZE/8 – 11,如果输入的明文过长,必须切割,然后填充
输出:和密钥长度一样长
具体算法以及填充方式感兴趣的可以自己去网上找下。
RSAUtil.java:
package com.su.mybatis.mysql.util; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * @Title: RSAUtil.java * @author sucb * @date 2017年3月28日 下午8:09:41 */ public final class RSAUtil { private RSAUtil() { } /** * 日志对象 */ private static Logger LOG = LoggerFactory.getLogger(RSAUtil.class); /** * 密钥长度(bit) */ private static final int KEYSIZE = 1024; /** * CIPHER_ALGORITHM RSA */ private static final String CIPHER_ALGORITHM_RSA = "RSA/ECB/PKCS1Padding"; /** * RSA加密 */ public static final String KEY_ALGORITHM_RSA = "RSA"; /** * RSAPublicKey */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * RSAPrivateKey */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 获取配对的公钥和私钥 * @return keyMap * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:29:51 */ public static Map<String, Object> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA); keyPairGen.initialize(KEYSIZE); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * 对公钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:33:03 */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 对私钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:34:39 */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); } /** * RSA加密 * @param publicKeyStr 公钥 * @param plainText 需要加密的数组 * @return 加密后数组 * @author sucb * @date 2017年3月29日下午2:45:26 */ public static byte[] encodeRSA(String publicKeyStr, byte[] plainText) { try { RSAPublicKey key = restorePublicKey(publicKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, key); return cipher.doFinal(plainText); } catch (Exception e) { LOG.error("RSA加密异常.publicKeyStr=({}), plainText=({}), 异常信息=({}).", publicKeyStr, plainText, e.getMessage()); return null; } } /** * RSA解密 * @param privateKeyStr 私钥 * @param plainText 需要解密的数组 * @return 解密后数组 * @author sucb * @date 2017年3月29日下午2:46:14 */ public static byte[] decodeRSA(String privateKeyStr, byte[] plainText) { try { RSAPrivateKey key = restorePrivateKey(privateKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, key); return cipher.doFinal(plainText); } catch (Exception e) { LOG.error("RSA解密异常.privateKeyStr=({}), plainText=({}), 异常信息=({}).", privateKeyStr, plainText, e.getMessage()); return null; } } /** * 还原公钥,X509EncodedKeySpec 用于构建公钥的规范 * @param publicKeyStr 公钥 * @return 还原后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:54 */ private static RSAPublicKey restorePublicKey(String publicKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(publicKeyStr); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPublicKey publicKey = (RSAPublicKey) factory.generatePublic(x509EncodedKeySpec); return publicKey; } /** * 还原私钥 PKCS8EncodedKeySpec * @param privateKeyStr 私钥 * @return 还原后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:37 */ private static RSAPrivateKey restorePrivateKey(String privateKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(privateKeyStr); PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPrivateKey privateKey = (RSAPrivateKey) factory.generatePrivate(priPKCS8); return privateKey; } /** * 进行BASE64转码 * @param key byte型密钥 * @return 转码后的String型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:49:58 */ private static String encryptBASE64(byte[] key) throws Exception { return new BASE64Encoder().encodeBuffer(key); } /** * 进行BASE64解码 * @param key String型密钥 * @return 解码后的byte型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:52:29 */ private static byte[] decryptBASE64(String key) throws Exception { return new BASE64Decoder().decodeBuffer(key); } public static void main(String[] args) throws Exception { Map<String, Object> keyMap = initKey(); String publicKey = getPublicKey(keyMap); String privateKey = getPrivateKey(keyMap); String a = "aaaaaaaaaaaa"; byte[] miByte = encodeRSA(publicKey, a.getBytes()); byte[] mingByte = decodeRSA(privateKey, miByte); String actual = new String(mingByte); System.out.println("actual : " + actual); System.out.println(a.equals(actual)); } }
上面方法只适用于输入比密钥长度少11个字节的情况,可以参考下下面这个
RSAUtils.java:
package com.su.mybatis.mysql.util; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public final class RSAUtils { private RSAUtils() { } /** * 日志对象 */ private static Logger LOG = LoggerFactory.getLogger(RSAUtils.class); /** * 密钥长度(bit) */ private static final int KEYSIZE = 1024; /** * CIPHER_ALGORITHM RSA */ private static final String CIPHER_ALGORITHM_RSA = "RSA/ECB/PKCS1Padding"; /** * RSA加密 */ public static final String KEY_ALGORITHM_RSA = "RSA"; /** * RSAPublicKey */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * RSAPrivateKey */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 获取配对的公钥和私钥 * @return keyMap * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:29:51 */ public static Map<String, Object> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA); keyPairGen.initialize(KEYSIZE); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * 对公钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:33:03 */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 对私钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:34:39 */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); } /** * RSA加密 * @param publicKeyStr 公钥 * @param plainText 需要加密的数组 * @return 加密后数组 * @author sucb * @date 2017年3月29日下午2:45:26 */ public static byte[] encodeRSA(String publicKeyStr, byte[] plainText) { try { int i = plainText.length/(KEYSIZE/8-11) +1; //加密数组需要切割的段数 //方式一、补位,保证下面循环中切割时不会出现数组越界 // byte[] newPlainText = new byte[i * KEYSIZE/8-11]; // System.arraycopy(plainText, 0, newPlainText, 0, plainText.length); byte[] resultByte = new byte[i * KEYSIZE/8];//用于接收加密后数组 for (int j = 0; j < i; j++) { byte[] adata = new byte[KEYSIZE/8-11]; //需要加密的每段数据 //方式一、补位的情况 // if(plainText.length < adata.length) {//数据不需要切割的情况 // System.arraycopy(newPlainText, j * adata.length, adata, 0, newPlainText.length); // }else { // System.arraycopy(newPlainText, j * adata.length, adata, 0, adata.length); // } //方式二、不补位的情况 if(plainText.length < adata.length) {//数据不需要切割的情况 System.arraycopy(plainText, j * adata.length, adata, 0, plainText.length); }else { if(j<i-1) { System.arraycopy(plainText, j * adata.length, adata, 0, adata.length); }else{//不补位的话,最后一段需要加密的数组长度小于KEYSIZE/8-11 System.arraycopy(plainText, j * adata.length, adata, 0, plainText.length- j * adata.length); } } RSAPublicKey key = restorePublicKey(publicKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] cipherText = cipher.doFinal(adata); //数据拼接 System.arraycopy(cipherText, 0, resultByte, j * cipherText.length, cipherText.length); } return resultByte; } catch (Exception e) { LOG.error("RSA加密异常.publicKeyStr=({}), plainText=({}), 异常信息=({}).", publicKeyStr, plainText, e.getMessage()); return null; } } /** * RSA解密 * @param privateKeyStr 私钥 * @param plainText 需要解密的数组 * @return 解密后数组 * @author sucb * @date 2017年3月29日下午2:46:14 */ public static byte[] decodeRSA(String privateKeyStr, byte[] plainText,int m) { int i = plainText.length/(KEYSIZE/8); byte[] decodeByte = new byte[i * plainText.length ]; try { byte[] cipherText = new byte[KEYSIZE/8];//需要解密的每段数据(也就是之前每段加密后得到的数组) for (int j = 0; j < i; j++) { System.arraycopy(plainText, j * cipherText.length, cipherText, 0, cipherText.length); RSAPrivateKey key = restorePrivateKey(privateKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, key); byte[] newPlainText = cipher.doFinal(cipherText); System.arraycopy(newPlainText, 0, decodeByte, j * newPlainText.length, newPlainText.length); } byte[] resultByte = new byte[m]; System.arraycopy(decodeByte, 0, resultByte, 0, resultByte.length); return resultByte; } catch (Exception e) { LOG.error("RSA解密异常.privateKeyStr=({}), plainText=({}), 异常信息=({}).", privateKeyStr, plainText, e.getMessage()); return null; } } /** * 还原公钥,X509EncodedKeySpec 用于构建公钥的规范 * @param publicKeyStr 公钥 * @return 还原后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:54 */ private static RSAPublicKey restorePublicKey(String publicKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(publicKeyStr); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPublicKey publicKey = (RSAPublicKey) factory.generatePublic(x509EncodedKeySpec); return publicKey; } /** * 还原私钥 PKCS8EncodedKeySpec * @param privateKeyStr 私钥 * @return 还原后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:37 */ private static RSAPrivateKey restorePrivateKey(String privateKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(privateKeyStr); PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPrivateKey privateKey = (RSAPrivateKey) factory.generatePrivate(priPKCS8); return privateKey; } /** * 进行BASE64转码 * @param key byte型密钥 * @return 转码后的String型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:49:58 */ private static String encryptBASE64(byte[] key) throws Exception { return new BASE64Encoder().encodeBuffer(key); } /** * 进行BASE64解码 * @param key String型密钥 * @return 解码后的byte型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:52:29 */ private static byte[] decryptBASE64(String key) throws Exception { return new BASE64Decoder().decodeBuffer(key); } public static void main(String[] args) throws Exception { Map<String, Object> keyMap = initKey(); String publicKey = getPublicKey(keyMap); String privateKey = getPrivateKey(keyMap); String a = "aaaaaaaaaaaa"; byte[] miByte = encodeRSA(publicKey, a.getBytes()); byte[] mingByte = decodeRSA(privateKey, miByte, a.getBytes().length); String actual = new String(mingByte); System.out.println("actual : " + actual); System.out.println(a.equals(actual)); String message = "然而,这几乎是个不可能完成的任务。当p和q是非常大的质数时,根据pq的乘积去分解因子p和q,这是数学上公认的难题。通常,p和q都会选的非常大,比如说200位。这导致n也非常大,有400位。寻找一个400位数字的质数分解并不容易,我们要做的除法运算次数大约为10 199!世界最强的超级计算机天河2号每秒浮点运算是1016级别。那么,分解出p和q,大约需要10174年。10174就是1的后面跟上174个0,时间是不是很长?"; byte[] miByte2 = encodeRSA(publicKey, message.getBytes()); byte[] mingByte2 = decodeRSA(privateKey, miByte2, message.getBytes().length); String actual2 = new String(mingByte2); System.out.println("actual2 : " + actual2); System.out.println(message.equals(actual2)); } }
如果公司不允许引用
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
则可以在 pom.xml文件中加入:
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency>
引用 import org.apache.commons.codec.binary.Base64; 修改如下:
RSAUtil.java:
package com.su.mybatis.mysql.util; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Title: RSAUtil.java * @author sucb * @date 2017年3月28日 下午8:09:41 */ public final class RSAUtil { private RSAUtil() { } /** * 日志对象 */ private static Logger LOG = LoggerFactory.getLogger(RSAUtil.class); /** * 密钥长度(bit) */ private static final int KEYSIZE = 1024; /** * CIPHER_ALGORITHM RSA */ private static final String CIPHER_ALGORITHM_RSA = "RSA/ECB/PKCS1Padding"; /** * RSA加密 */ public static final String KEY_ALGORITHM_RSA = "RSA"; /** * RSAPublicKey */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * RSAPrivateKey */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 获取配对的公钥和私钥 * @return keyMap * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:29:51 */ public static Map<String, Object> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA); keyPairGen.initialize(KEYSIZE); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * 对公钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:33:03 */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 对私钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:34:39 */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); } /** * RSA加密 * @param publicKeyStr 公钥 * @param plainText 需要加密的数组 * @return 加密后数组 * @author sucb * @date 2017年3月29日下午2:45:26 */ public static byte[] encodeRSA(String publicKeyStr, byte[] plainText) { try { RSAPublicKey key = restorePublicKey(publicKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, key); return cipher.doFinal(plainText); } catch (Exception e) { LOG.error("RSA加密异常.publicKeyStr=({}), plainText=({}), 异常信息=({}).", publicKeyStr, plainText, e.getMessage()); return null; } } /** * RSA解密 * @param privateKeyStr 私钥 * @param plainText 需要解密的数组 * @return 解密后数组 * @author sucb * @date 2017年3月29日下午2:46:14 */ public static byte[] decodeRSA(String privateKeyStr, byte[] plainText) { try { RSAPrivateKey key = restorePrivateKey(privateKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, key); return cipher.doFinal(plainText); } catch (Exception e) { LOG.error("RSA解密异常.privateKeyStr=({}), plainText=({}), 异常信息=({}).", privateKeyStr, plainText, e.getMessage()); return null; } } /** * 还原公钥,X509EncodedKeySpec 用于构建公钥的规范 * @param publicKeyStr 公钥 * @return 还原后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:54 */ private static RSAPublicKey restorePublicKey(String publicKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(publicKeyStr); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPublicKey publicKey = (RSAPublicKey) factory.generatePublic(x509EncodedKeySpec); return publicKey; } /** * 还原私钥 PKCS8EncodedKeySpec * @param privateKeyStr 私钥 * @return 还原后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:37 */ private static RSAPrivateKey restorePrivateKey(String privateKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(privateKeyStr); PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPrivateKey privateKey = (RSAPrivateKey) factory.generatePrivate(priPKCS8); return privateKey; } /** * 进行BASE64转码 * @param key byte型密钥 * @return 转码后的String型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:49:58 */ private static String encryptBASE64(byte[] key) throws Exception { return Base64.encodeBase64String(key); } /** * 进行BASE64解码 * @param key String型密钥 * @return 解码后的byte型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:52:29 */ private static byte[] decryptBASE64(String key) throws Exception { return Base64.decodeBase64(key); } public static void main(String[] args) throws Exception { Map<String, Object> keyMap = initKey(); String publicKey = getPublicKey(keyMap); String privateKey = getPrivateKey(keyMap); String a = "aaaaaaaaaaaa"; byte[] miByte = encodeRSA(publicKey, a.getBytes()); byte[] mingByte = decodeRSA(privateKey, miByte); String actual = new String(mingByte); System.out.println("actual : " + actual); System.out.println(a.equals(actual)); } }
RSAUtils.java:
package com.su.mybatis.mysql.util; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class RSAUtils { private RSAUtils() { } /** * 日志对象 */ private static Logger LOG = LoggerFactory.getLogger(RSAUtils.class); /** * 密钥长度(bit) */ private static final int KEYSIZE = 1024; /** * CIPHER_ALGORITHM RSA */ private static final String CIPHER_ALGORITHM_RSA = "RSA/ECB/PKCS1Padding"; /** * RSA加密 */ public static final String KEY_ALGORITHM_RSA = "RSA"; /** * RSAPublicKey */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * RSAPrivateKey */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 获取配对的公钥和私钥 * @return keyMap * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:29:51 */ public static Map<String, Object> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA); keyPairGen.initialize(KEYSIZE); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * 对公钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:33:03 */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 对私钥进行编码转换,并进行BASE64转码 * @param keyMap 配对的公钥和私钥组成的map * @return 处理后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:34:39 */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); } /** * RSA加密 * @param publicKeyStr 公钥 * @param plainText 需要加密的数组 * @return 加密后数组 * @author sucb * @date 2017年3月29日下午2:45:26 */ public static byte[] encodeRSA(String publicKeyStr, byte[] plainText) { try { int i = plainText.length/(KEYSIZE/8-11) +1; //加密数组需要切割的段数 //方式一、补位,保证下面循环中切割时不会出现数组越界 // byte[] newPlainText = new byte[i * KEYSIZE/8-11]; // System.arraycopy(plainText, 0, newPlainText, 0, plainText.length); byte[] resultByte = new byte[i * KEYSIZE/8];//用于接收加密后数组 for (int j = 0; j < i; j++) { byte[] adata = new byte[KEYSIZE/8-11]; //需要加密的每段数据 //方式一、补位的情况 // if(plainText.length < adata.length) {//数据不需要切割的情况 // System.arraycopy(newPlainText, j * adata.length, adata, 0, newPlainText.length); // }else { // System.arraycopy(newPlainText, j * adata.length, adata, 0, adata.length); // } //方式二、不补位的情况 if(plainText.length < adata.length) {//数据不需要切割的情况 System.arraycopy(plainText, j * adata.length, adata, 0, plainText.length); }else { if(j<i-1) { System.arraycopy(plainText, j * adata.length, adata, 0, adata.length); }else{//不补位的话,最后一段需要加密的数组长度小于KEYSIZE/8-11 System.arraycopy(plainText, j * adata.length, adata, 0, plainText.length- j * adata.length); } } RSAPublicKey key = restorePublicKey(publicKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] cipherText = cipher.doFinal(adata); //数据拼接 System.arraycopy(cipherText, 0, resultByte, j * cipherText.length, cipherText.length); } return resultByte; } catch (Exception e) { LOG.error("RSA加密异常.publicKeyStr=({}), plainText=({}), 异常信息=({}).", publicKeyStr, plainText, e.getMessage()); return null; } } /** * RSA解密 * @param privateKeyStr 私钥 * @param plainText 需要解密的数组 * @return 解密后数组 * @author sucb * @date 2017年3月29日下午2:46:14 */ public static byte[] decodeRSA(String privateKeyStr, byte[] plainText,int m) { int i = plainText.length/(KEYSIZE/8); byte[] decodeByte = new byte[i * plainText.length ]; try { byte[] cipherText = new byte[KEYSIZE/8];//需要解密的每段数据(也就是之前每段加密后得到的数组) for (int j = 0; j < i; j++) { System.arraycopy(plainText, j * cipherText.length, cipherText, 0, cipherText.length); RSAPrivateKey key = restorePrivateKey(privateKeyStr); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, key); byte[] newPlainText = cipher.doFinal(cipherText); System.arraycopy(newPlainText, 0, decodeByte, j * newPlainText.length, newPlainText.length); } byte[] resultByte = new byte[m]; System.arraycopy(decodeByte, 0, resultByte, 0, resultByte.length); return resultByte; } catch (Exception e) { LOG.error("RSA解密异常.privateKeyStr=({}), plainText=({}), 异常信息=({}).", privateKeyStr, plainText, e.getMessage()); return null; } } /** * 还原公钥,X509EncodedKeySpec 用于构建公钥的规范 * @param publicKeyStr 公钥 * @return 还原后的公钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:54 */ private static RSAPublicKey restorePublicKey(String publicKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(publicKeyStr); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPublicKey publicKey = (RSAPublicKey) factory.generatePublic(x509EncodedKeySpec); return publicKey; } /** * 还原私钥 PKCS8EncodedKeySpec * @param privateKeyStr 私钥 * @return 还原后的私钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:47:37 */ private static RSAPrivateKey restorePrivateKey(String privateKeyStr) throws Exception { byte[] keyBytes = decryptBASE64(privateKeyStr); PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM_RSA); RSAPrivateKey privateKey = (RSAPrivateKey) factory.generatePrivate(priPKCS8); return privateKey; } /** * 进行BASE64转码 * @param key byte型密钥 * @return 转码后的String型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:49:58 */ private static String encryptBASE64(byte[] key) throws Exception { return Base64.encodeBase64String(key); } /** * 进行BASE64解码 * @param key String型密钥 * @return 解码后的byte型密钥 * @throws Exception 异常 * @author sucb * @date 2017年3月29日下午2:52:29 */ private static byte[] decryptBASE64(String key) throws Exception { return Base64.decodeBase64(key); } public static void main(String[] args) throws Exception { Map<String, Object> keyMap = initKey(); String publicKey = getPublicKey(keyMap); String privateKey = getPrivateKey(keyMap); String a = "aaaaaaaaaaaa"; byte[] miByte = encodeRSA(publicKey, a.getBytes()); byte[] mingByte = decodeRSA(privateKey, miByte, a.getBytes().length); String actual = new String(mingByte); System.out.println("actual : " + actual); System.out.println(a.equals(actual)); String message = "然而,这几乎是个不可能完成的任务。当p和q是非常大的质数时,根据pq的乘积去分解因子p和q,这是数学上公认的难题。通常,p和q都会选的非常大,比如说200位。这导致n也非常大,有400位。寻找一个400位数字的质数分解并不容易,我们要做的除法运算次数大约为10 199!世界最强的超级计算机天河2号每秒浮点运算是1016级别。那么,分解出p和q,大约需要10174年。10174就是1的后面跟上174个0,时间是不是很长?"; byte[] miByte2 = encodeRSA(publicKey, message.getBytes()); byte[] mingByte2 = decodeRSA(privateKey, miByte2, message.getBytes().length); String actual2 = new String(mingByte2); System.out.println("actual2 : " + actual2); System.out.println(message.equals(actual2)); } }
以上就是RSA加解密。