Java:RSA加密工具

RSA工具示例:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;

/**
 * 此类是非对称加密算法RSA的工具类,方便对传输数据进行基于密钥的加密和解密。
 * 
 * 一般情况下,私钥是服务器端不公开的,公钥公开给每个客户端。
 * 客户端向服务器发送需要加密的消息时,可以用公钥加密后进行传送,服务器端受到密文后可以用私钥进行解密。
 * 服务器端可以对发送的消息进行数字签名,传给客户端,这样客户端受到签名后用公钥进行签名校验,若通过校验说明消息未被修改。
 * 
 * 由于RSA算法速度比对称加密算法AES慢很多,所以一般仅仅用来和服务器完成对接认证,和AES密钥传输。
 * 一旦AES密钥传输完成,客户服务器端就可以用AES加密进行通信。
 * 认证过程可以如下:
 * 1、客户端生成伪随机数D,用公钥加密后传给服务器。
 * 2、服务器收到密文用私钥进行解密得到D,然后用私钥对D进行数字签名,将签名发送给客户端。
 * 3、客户端收到签名,用公钥和D进行签名校验,通过校验说明认证通过。
 * 4、通过认证后,客户端可以将自己选择的AES加密算法和密钥用公钥加密后传给服务器。
 * 简单情况下可以只进行第4步,但最好跟一个随机数(加盐),防止其他拥有公钥的人进行穷举法破解。
 * 
 * @author liuweitao
 */
public class RSAUtil {
	private RSAPrivateKey key_pri = null;
	private RSAPublicKey key_pub = null;
	private int KEYSIZE = 0;
	private static int D = 11; // java算法要求加密数据长度不能超过密钥长度减去11字节。

	private static final String SIGN_ALGORITHMS = "SHA256WithRSA";

	// 检查公钥私钥,若都为空则抛出异常。
	private void check() throws Exception {
		if ("none".equals(type())) {
			throw new Exception("密钥为空!");
		}
		if (key_pub != null) {
			KEYSIZE = key_pub.getModulus().bitLength();
		} else {
			KEYSIZE = key_pri.getModulus().bitLength();
		}
		KEYSIZE /= Byte.SIZE;
	}

	/**
	 * @return pub:公钥填充完成; pri:私钥填充完成; all:公钥私钥都填充完成。
	 */
	public String type() {
		String res = null;
		if (key_pub == null && key_pri == null) {
			res = "none";
		} else if (key_pub != null && key_pri == null) {
			res = "pub";
		} else if (key_pub == null && key_pri != null) {
			res = "pri";
		} else if (key_pub != null && key_pri != null) {
			res = "all";
		}
		return res;
	}

	/**
	 * @param key_pub
	 *            公钥,若不指定则传入null
	 * @param key_pri
	 *            私钥,若不指定则传入null
	 * @throws Exception
	 */
	public RSAUtil(RSAPublicKey key_pub, RSAPrivateKey key_pri) throws Exception {
		this.key_pub = key_pub;
		this.key_pri = key_pri;
		check();
	}

	/**
	 * @param bytes_pub
	 *            公钥字节流,若不指定则传入null
	 * @param bytes_pri
	 *            私钥字节流,若不指定则传入null
	 * @throws Exception
	 */
	public RSAUtil(byte[] bytes_pub, byte[] bytes_pri) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance("rsa");
		if (bytes_pub != null && bytes_pub.length != 0) {
			X509EncodedKeySpec keySpec_pub = new X509EncodedKeySpec(bytes_pub);
			key_pub = (RSAPublicKey) keyFactory.generatePublic(keySpec_pub);
		}
		if (bytes_pri != null && bytes_pri.length != 0) {
			PKCS8EncodedKeySpec keySpec_pri = new PKCS8EncodedKeySpec(bytes_pri);
			key_pri = (RSAPrivateKey) keyFactory.generatePrivate(keySpec_pri);
		}
		check();
	}

	/**
	 * @param str_pub
	 *            公钥字符串:Base64表示,若不指定则传入null
	 * @param str_pri
	 *            私钥字符串:Base64表示,若不指定则传入null
	 * @throws Exception
	 */
	public RSAUtil(String str_pub, String str_pri) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance("rsa");
		if (str_pub != null) {
			byte[] bytes_pub = Base64.decode(str_pub);
			X509EncodedKeySpec keySpec_pub = new X509EncodedKeySpec(bytes_pub);
			key_pub = (RSAPublicKey) keyFactory.generatePublic(keySpec_pub);
		}
		if (str_pri != null) {
			byte[] bytes_pri = Base64.decode(str_pri);
			PKCS8EncodedKeySpec keySpec_pri = new PKCS8EncodedKeySpec(bytes_pri);
			key_pri = (RSAPrivateKey) keyFactory.generatePrivate(keySpec_pri);
		}
		check();
	}

	/**
	 * @param file_pub
	 *            公钥文件,内容给为Base64表示的字符串,若不指定则传入null
	 * @param file_pri
	 *            私钥文件,内容给为Base64表示的字符串,若不指定则传入null
	 * @throws Exception
	 */
	public RSAUtil(File file_pub, File file_pri) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance("rsa");
		if (file_pub != null) {
			String str_pub = FileUtil.readStringFile(file_pub);
			byte[] bytes_pub = Base64.decode(str_pub);
			X509EncodedKeySpec keySpec_pub = new X509EncodedKeySpec(bytes_pub);
			key_pub = (RSAPublicKey) keyFactory.generatePublic(keySpec_pub);
		}
		if (file_pri != null) {
			String str_pri = FileUtil.readStringFile(file_pri);
			byte[] bytes_pri = Base64.decode(str_pri);
			PKCS8EncodedKeySpec keySpec_pri = new PKCS8EncodedKeySpec(bytes_pri);
			key_pri = (RSAPrivateKey) keyFactory.generatePrivate(keySpec_pri);
		}
		check();
	}

	/**
	 * @param dir_path
	 *            密钥文件保存目录路径,字符串
	 * @param keysize
	 *            密钥文件大小,最小为512,推荐1024和2048
	 * @throws Exception
	 */
	public static void genKeyFile(String dir_path, int keysize) throws Exception {
		File file = new File(dir_path);
		genKeyFile(file, keysize);
	}

	/**
	 * @param dir
	 *            密钥文件保存目录路径,文件
	 * @param keysize
	 *            密钥文件大小,最小为512,推荐1024和2048
	 * @throws Exception
	 */
	public static void genKeyFile(File dir, int keysize) throws Exception {
		if (!dir.isDirectory()) {
			throw new Exception("接收参数不为目录!");
		}
		String path = dir.getAbsolutePath() + File.separatorChar;

		KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("rsa");
		keyGenerator.initialize(keysize, new SecureRandom());
		KeyPair keyPair = keyGenerator.generateKeyPair();
		RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
		RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();

		String rsaPrivateKeyString = Base64.encode(rsaPrivateKey.getEncoded());
		String rsaPublicKeyString = Base64.encode(rsaPublicKey.getEncoded());
		PrintWriter out1;
		PrintWriter out2;
		out1 = new PrintWriter(path + "id_rsa.pub");
		out2 = new PrintWriter(path + "id_rsa.pri");
		out1.write(rsaPublicKeyString);
		out2.write(rsaPrivateKeyString);
		out1.close();
		out2.close();
	}

	// 加密内容
	private byte[] encrypt(Cipher cipher, byte[] content) throws Exception {
		final int groupsize = KEYSIZE - D;
		int group_num = content.length % groupsize == 0 ? content.length / groupsize : content.length / groupsize + 1;
		byte[] outBuffer = new byte[KEYSIZE * group_num];

		for (int i = 0; i * groupsize < content.length; i++) {
			if (content.length - i * groupsize > groupsize) {
				cipher.doFinal(content, i * groupsize, groupsize, outBuffer, KEYSIZE * i);
			} else {
				cipher.doFinal(content, i * groupsize, content.length - i * groupsize, outBuffer, KEYSIZE * i);
			}
		}
		return outBuffer;
	}

	// 解密内容
	private byte[] decrypt(Cipher cipher, byte[] secret) throws Exception {
		int count = secret.length / KEYSIZE;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		for (int i = 0; i < count; i++) {
			out.write(cipher.doFinal(secret, KEYSIZE * i, KEYSIZE));
		}
		byte[] res = out.toByteArray();
		out.reset();
		out.close();
		return res;
	}

	/**
	 * 公钥加密
	 * 
	 * @param content
	 *            要加密的数据
	 * @return 加密后的数据
	 * @throws Exception
	 */
	public byte[] encrypt_pub(byte[] content) throws Exception {
		if (key_pub == null) {
			throw new Exception("公钥为null!");
		}
		Cipher cipher = Cipher.getInstance("rsa");
		cipher.init(Cipher.ENCRYPT_MODE, key_pub);
		return encrypt(cipher, content);
	}

	/**
	 * 公钥解密
	 * 
	 * @param secret
	 *            要解密的数据
	 * @return 解密后的数据
	 * @throws Exception
	 */
	public byte[] decrypt_pub(byte[] secret) throws Exception {
		if (key_pub == null) {
			throw new Exception("公钥为null!");
		}
		Cipher cipher = Cipher.getInstance("rsa");
		cipher.init(Cipher.DECRYPT_MODE, key_pub);
		return decrypt(cipher, secret);
	}

	/**
	 * 私钥加密
	 * 
	 * @param content
	 *            要加密的数据
	 * @return 加密后的数据
	 * @throws Exception
	 */
	public byte[] encrypt_pri(byte[] content) throws Exception {
		if (key_pri == null) {
			throw new Exception("私钥为null!");
		}
		Cipher cipher = Cipher.getInstance("rsa");
		cipher.init(Cipher.ENCRYPT_MODE, key_pri);
		return encrypt(cipher, content);
	}

	/**
	 * 私钥解密
	 * 
	 * @param secret
	 *            要解密的数据
	 * @return 解密后的数据
	 * @throws Exception
	 */
	public byte[] decrypt_pri(byte[] secret) throws Exception {
		if (key_pri == null) {
			throw new Exception("私钥为null!");
		}
		Cipher cipher = Cipher.getInstance("rsa");
		cipher.init(Cipher.DECRYPT_MODE, key_pri);
		return decrypt(cipher, secret);
	}

	/**
	 * 生成数字签名,签名算法SHA256WithRSA
	 * 
	 * @param content
	 *            数据内容
	 * @return 签名
	 * @throws Exception
	 */
	public byte[] sign(byte[] content) throws Exception {
		if (key_pri == null) {
			throw new Exception("私钥为null!");
		}
		java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
		signature.initSign(key_pri);
		signature.update(content);
		return signature.sign();
	}

	/**
	 * 校验签名,签名算法SHA256WithRSA
	 * 
	 * @param content
	 *            数据内容
	 * @param sign
	 *            签名
	 * @return 是否通过校验
	 * @throws Exception
	 */
	public boolean check_sign(byte[] content, byte[] sign) throws Exception {
		if (key_pub == null) {
			throw new Exception("公钥为null!");
		}
		java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
		signature.initVerify(key_pub);
		signature.update(content);
		return signature.verify(sign);
	}

	/**
	 * 对二进制数据进行Base64编码
	 * 
	 * @param binaryData
	 *            要编码的原始二进制数据
	 * @return 
	 *         com.sun.org.apache.xml.internal.security.utils.Base64.encode(binaryData);
	 */
	public static String base64Encode(byte[] binaryData) {
		return Base64.encode(binaryData);
	}

	/**
	 * 对Base64编码字符串解码为二进制数,此方法能自动忽略原始字符串中的换行符。
	 * 
	 * @param encoded
	 *            表示Base64编码的字符串
	 * @return 
	 *         com.sun.org.apache.xml.internal.security.utils.Base64.decode(encoded);
	 * @throws Base64DecodingException
	 */
	public static byte[] base64Decode(String encoded) throws Base64DecodingException {
		return Base64.decode(encoded);
	}
}
posted @ 2018-12-19 11:05  xuejianbest  阅读(301)  评论(0编辑  收藏  举报