**

RSA加密解密,加签解签学习记录

**
转载请注明出处!!!

RSA是一种非对称加密算法,需要通过不同的密钥来加解密和加解签。通过RSA我们可以对信息传输做到防泄漏放篡改的目的。

RSA的几个概念:

公钥:用于信息信加密和验证签名
私钥:用于信息解密和签名
加密:防止信息泄漏
加签:防止信息被篡改

总结下来就是:公钥解密、私钥加密、私钥加签、公钥验签。加密防泄漏、加签防篡改。

至于RSA的加解密算法这里不做研究,下面谈谈RSA加解密和签名、验签的JAVA实现

1、RSA的密钥对
如果用公钥加密则用私钥解密,用私钥加密则公钥解密,也就是一方加密,则另一方用来解密,签名和验签也是同样的道理。下面代码使用随机数自动产生一对随机密钥对:

/**
	 * 	随机生成一对密钥
	 * @return	Map<String,String> map中key为pub的为公钥,key为pri的为私钥
	 * @throws NoSuchAlgorithmException 
	 */
	public static Map<String,String> generateKeyPair() throws NoSuchAlgorithmException{
		Map<String,String> result = new HashMap<String,String>();
		//使用KeyPairGenerator来创建密钥对生成器,基于RSA算法
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
		//使用随机数来初始化密钥对生成器
		SecureRandom sRan = new SecureRandom();
		keyPairGen.initialize(1024, sRan);
		//生成密钥对
		KeyPair keyPair = keyPairGen.generateKeyPair();
		//获取私钥
		RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate();
		//获取公钥
		RSAPublicKey pubKey = (RSAPublicKey)keyPair.getPublic();
		
		//对密钥对做Base64编码处理
		String priKeyStr = Base64.getEncoder().encodeToString(priKey.getEncoded());
		String pubKeyStr = Base64.getEncoder().encodeToString(pubKey.getEncoded());
		result.put("pri",priKeyStr);
		result.put("pub",pubKeyStr);
		return result;
	}

2、RSA使用java实现加密和解密
由于RSA加密的原文最长不能超过117byte,解密的原文最长不能超过128byte,不然加密会产生异常:Data must not be longer than 117 bytes,解密会产生异常:Data must not be longer than 128 bytes。下面使用分段逻辑的方法来实现加解密

package com.lsk.util;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RsaUtil {
	private final static String RSA = "RSA";
	private final static String UTF8 = "UTF-8";
	//最大加密长度不能超过117byte
	private final static int MAX_ENCRYPT_BLOCK = 117;
	//最大解密长度不能超过128byte
	private final static int MAX_DECRYPT_BLOCK = 128;
	
	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
		// TODO Auto-generated method stub
		Map<String,String> result = generateKeyPair();
		System.out.println("获取到的公钥:\t"+result.get("pub"));
		System.out.println("获取到的私钥:\t"+result.get("pri"));
		String src = "Linsk110";
		System.out.println("Linsk110使用RSA加密后密文:");
		String encryStr = encry(src,result.get("pub"));
		System.out.println(encryStr);
		String decryStr = decry(encryStr,result.get("pri"));
		System.out.println("密文解密后:"+decryStr);
		
		
	}
	/**
	 * 	随机生成一对密钥
	 * @return	Map<String,String> map中key为pub的为公钥,key为pri的为私钥
	 * @throws NoSuchAlgorithmException 
	 */
	public static Map<String,String> generateKeyPair() throws NoSuchAlgorithmException{
		Map<String,String> result = new HashMap<String,String>();
		//使用KeyPairGenerator来创建密钥对生成器,基于RSA算法
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
		//使用随机数来初始化密钥对生成器
		SecureRandom sRan = new SecureRandom();
		keyPairGen.initialize(1024, sRan);
		//生成密钥对
		KeyPair keyPair = keyPairGen.generateKeyPair();
		//获取私钥
		RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate();
		//获取公钥
		RSAPublicKey pubKey = (RSAPublicKey)keyPair.getPublic();
		
		//对密钥对做Base64编码处理
		String priKeyStr = Base64.getEncoder().encodeToString(priKey.getEncoded());
		String pubKeyStr = Base64.getEncoder().encodeToString(pubKey.getEncoded());
		result.put("pri",priKeyStr);
		result.put("pub",pubKeyStr);
		return result;
	}
	/**
	 * 	使用公钥加密(分段加密)
	 * @param src 加密的原文
	 * @param publicKey 加密的公钥
	 * @return
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeySpecException 
	 * @throws NoSuchPaddingException 
	 * @throws InvalidKeyException 
	 * @throws BadPaddingException 
	 * @throws IllegalBlockSizeException 
	 */
	public static String encry(String src,String publicKey) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
		//对公钥先做base64解码
		byte[] decodeKey = Base64.getDecoder().decode(publicKey);
		//获取一个加密key对象
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodeKey);
		//通过RSA算法获取一个密钥工厂对象
		KeyFactory keyFactory = KeyFactory.getInstance(RSA);
		//通过解码的公钥字节来获取公钥对象
		RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(keySpec);
		//获取RSA加密对象
		Cipher cipher = Cipher.getInstance(RSA);
		//初始化加密对象
		cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		//原文字节长度
		int srcLength = src.getBytes().length;
		int offset = 0;//计算标识
		byte[] resultByte = {};
		byte[] cache = {};
		byte[] srcByteArry = src.getBytes();
		//对原文做分段加密
		while(srcLength - offset > 0) {
			int offsetResult = srcLength-offset;
			//原文字节超过117字节
			if(offsetResult > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(srcByteArry,offset,MAX_ENCRYPT_BLOCK);
				offset += MAX_ENCRYPT_BLOCK;
			}else {
				cache = cipher.doFinal(srcByteArry,offset,offsetResult);
				offset = offsetResult;
			}
			//数组扩容
			resultByte = Arrays.copyOf(resultByte, resultByte.length+cache.length);
			/*
			 * 	把cache中的字节拷贝到resultByte中去
			 * 	cache:待拷贝的原始字节数组
			 * 	0:从原始字节数组的第0位开始拷贝
			 * 	resultByte:要拷贝到的目标数组
			 * 	resultByte.length-cache.length:拷贝的内容要放在目标数组的开始位置
			 * 	cache.length:原始字节数组拷贝内容的截至位置
			 */
			System.arraycopy(cache, 0, resultByte, resultByte.length-cache.length, cache.length);
		}
		return Base64.getEncoder().encodeToString(resultByte);
	}
	/**
	 * 	使用公钥加密(分段解密)
	 * @param src
	 * @param privateKey
	 * @return
	 * @throws InvalidKeySpecException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchPaddingException
	 * @throws InvalidKeyException
	 * @throws IllegalBlockSizeException
	 * @throws BadPaddingException
	 * @throws UnsupportedEncodingException
	 */
	public static String decry(String src,String privateKey) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
		//对密钥字串做解码
		byte[] decodeKey = Base64.getDecoder().decode(privateKey);
		//获取一个加密key对象
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodeKey);
		//通过RSA算法获取一个密钥工厂对象
		KeyFactory keyFactory = KeyFactory.getInstance(RSA);
		//通过解码的私钥字节来获取私钥对象
		RSAPrivateKey priKey = (RSAPrivateKey)keyFactory.generatePrivate(keySpec);
		//获取RSA加密对象
		Cipher cipher = Cipher.getInstance(RSA);
		//初始化解密对象
		cipher.init(Cipher.DECRYPT_MODE, priKey);
		//对原文做解码操作,原因是加密后通过base64做了一次编码
		byte[] srcByteArry = Base64.getDecoder().decode(src);
		int srcLength = srcByteArry.length;
		int offset = 0;//计算标识
		byte[] resultByte = {};
		byte[] cache = {};
		
		//对原文做分段解密
		while(srcLength - offset > 0) {
			int offsetResult = srcLength-offset;
			//原文字节超过128字节
			if(offsetResult > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(srcByteArry,offset,MAX_DECRYPT_BLOCK);
				offset += MAX_DECRYPT_BLOCK;
			}else {
				cache = cipher.doFinal(srcByteArry,offset,offsetResult);
				offset = MAX_DECRYPT_BLOCK;
			}
			//数组扩容
			resultByte = Arrays.copyOf(resultByte, resultByte.length+cache.length);
			/*
			 * 	把cache中的字节拷贝到resultByte中去
			 * 	cache:待拷贝的原始字节数组
			 * 	0:从原始字节数组的第0位开始拷贝
			 * 	resultByte:要拷贝到的目标数组
			 * 	resultByte.length-cache.length:拷贝的内容要放在目标数组的开始位置
			 * 	cache.length:原始字节数组拷贝内容的截至位置
			 */
			System.arraycopy(cache, 0, resultByte, resultByte.length-cache.length, cache.length);
		}
		return new String(resultByte);
		
	}

}

至此完毕,如有问题,欢迎留言交流~~~