RSA算法实现数据加密签名传输与数据解密代码实例(上)
1. RSA算法实现数据加解密与签名的原理浅析:RSA算法实现数据的加解密与签名都是通过一对非对称的密钥对(公钥与私钥)来实现的,公钥可对外公开给其他要传输数据给我的人使用,私钥留着我自己对加密的数据进行解密时使用。公钥通常用来加密数据,私钥通常用来解密数据。使用私钥签名主要是为了防止传送的数据被篡改。
2. 废话不多说,直接上代码
项目目录结构:
RSA密钥常量文件
package com.sxy.rsademo.rsa;
/**
* @Description 密钥相关常量
* @By SuXingYong
* @DateTime 2020/7/11 23:35
**/
public class KeyConstant {
/** 字符编码 **/
public final static String CHARACTER_ENCODING_FORMAT = "utf-8";
/** 密钥常量 - 密钥采用的算法 **/
public final static String KEY_ALGORITHM = "RSA";
/** 密钥常量 - 签名算法 **/
public final static String SIGN_ALGORITHMS = "MD5withRSA";
/**
* 密钥长度,DH算法的默认密钥长度是1024
* 密钥长度必须是64的倍数,在512到65536位之间
**/
public final static int KEY_SIZE = 1024;
/** 最大 - 加密字节数组 - 大小 **/
public final static int ENCRYPT_MAX_SIZE = 117;
/** 最大 - 解密字节数组 - 大小 **/
public final static int DECRYPT_MAX_SIZE = 128;
/** RSA - 模式 - 01 - 加密 **/
public final static String RSA_MODE_01 = "encrypt";
/** RSA - 模式 - 02 - 解密 **/
public final static String RSA_MODE_02 = "decrypt";
/** 公钥 **/
public final static String PUBLIC_KEY = "public.key";
/** 私钥 **/
public final static String PRIVATE_KEY = "private.key";
/** A方 - 原文 **/
public final static String A_ORIGINAL_TEXT = "aOriginalText";
/** B方 - 原文 **/
public final static String B_ORIGINAL_TEXT = "bOriginalText";
/** A方 - 公钥 - 密文 **/
public final static String A_PUBLIC_KEY_CIPHER_TEXT = "aPublicKeyCipherText";
/** A方 - 私钥 - 密文 **/
public final static String A_PRIVATE_KEY_CIPHER_TEXT = "aPrivateKeyCipherText";
/** A方 - 公钥 - 明文 **/
public final static String A_PUBLIC_KEY_PLAIN_TEXT = "aPublicKeyPlainText";
/** A方 - 私钥 - 明文 **/
public final static String A_PRIVATE_KEY_PLAIN_TEXT = "aPrivateKeyPlainText";
/** B方 - 公钥 - 密文 **/
public final static String B_PUBLIC_KEY_CIPHER_TEXT = "bPublicKeyCipherText";
/** B方 - 私钥 - 密文 **/
public final static String B_PRIVATE_KEY_CIPHER_TEXT = "bPrivateKeyCipherText";
/** B方 - 公钥 - 明文 **/
public final static String B_PUBLIC_KEY_PLAIN_TEXT = "bPublicKeyPlainText";
/** B方 - 私钥 - 明文 **/
public final static String B_PRIVATE_KEY_PLAIN_TEXT = "bPrivateKeyPlainText";
/** A方 - 私钥 - 签名 - 原文 **/
public final static String A_PRIVATE_KEY_SIGN_ORIGINAL_TEXT = "aPrivateKeySignOriginalText";
/** A方 - 私钥 - 签名 - 密文 **/
public final static String A_PRIVATE_KEY_SIGN_CIPHER_TEXT = "aPrivateKeySignCipherText";
/** B方 - 私钥 - 签名 - 原文 **/
public final static String B_PRIVATE_KEY_SIGN_ORIGINAL_TEXT = "bPrivateKeySignOriginalText";
/** B方 - 私钥 - 签名 - 密文 **/
public final static String B_PRIVATE_KEY_SIGN_CIPHER_TEXT = "bPrivateKeySignCipherText";
/** 私钥 - 签名 - 合法性 **/
public final static String PRIVATE_KEY_SIGN_VERIFY = "privateKeySignVerify";
/** 公钥文件存储路径 **/
public final static String PUBLIC_KEY_FILE_ULR = "d:/upload/rsaKey/publicKey.keystore";
/** 私钥钥文件存储路径 **/
public final static String PRIVATE_KEY_FILE_ULR = "d:/upload/rsaKey/privateKey.keystore";
/** 密钥名称和值的分隔符 **/
public final static String KEY_AND_VALUE_SEPARATOR = "==>";
/** 公钥文件存储路径 - 键名 **/
public final static String PUBLIC_KEY_FILE_SAVE_PATH = "publicKeyFile.savePath";
/** 私钥钥文件存储路径 - 键名 **/
public final static String PRIVATE_KEY_FILE_SAVE_PATH = "privateKeyFile.savePath";
}
KeyConstant.java
RSA工具类:
package com.sxy.rsademo.rsa;
import com.sxy.rsademo.utils.Base64;
import com.sxy.rsademo.utils.CastUtils;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @Description: RSA 工具类
* @Author: SuXingYong
* @Date 2020/7/11 23:35
**/
@Slf4j
public class RsaUtils extends KeyConstant {
/************************************************* 密钥初始化、持久化、获取start *************************************************/
/**
* @Description 初始化密钥对
* 返回甲方密钥的Map
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param []
* @Return java.util.Map<java.lang.String,java.lang.Object>
**/
public static Map<String,Object> initKey(){
// 将密钥存储在map中
Map<String,Object> keyMap = new HashMap<String,Object>();
try {
// 实例化密钥生成器 采用RSA算法
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密钥生成器 1024
keyPairGenerator.initialize(KEY_SIZE);
// 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 甲方公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
log.info("系数:"+publicKey.getModulus()+" 加密指数:"+publicKey.getPublicExponent());
// 甲方私钥
RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();
log.info("系数:"+privateKey.getModulus()+" 解密指数:"+privateKey.getPrivateExponent());
// 公钥
keyMap.put(PUBLIC_KEY, Base64.encode(publicKey.getEncoded()));
// 私钥
keyMap.put(PRIVATE_KEY, Base64.encode(privateKey.getEncoded()));
// 公钥持久性文件存储地址
String publicKeyFileSavePath = PUBLIC_KEY_FILE_ULR;
if (publicKeyFileSavePath != null && !publicKeyFileSavePath.equals("")){
keyMap.put(PUBLIC_KEY_FILE_SAVE_PATH,publicKeyFileSavePath);
}
// 私钥持久性文件存储地址
String privateKeyFileSavePath = PRIVATE_KEY_FILE_ULR;
if (privateKeyFileSavePath != null && !privateKeyFileSavePath.equals("")){
keyMap.put(PRIVATE_KEY_FILE_SAVE_PATH,privateKeyFileSavePath);
}
// 密钥对持久化存储
RsaUtils.saveKeyPairToFile(keyMap);
}catch (Exception e){
e.printStackTrace();
log.error(e.getMessage());
}
return keyMap;
}
/**
* @Description 保存密钥对 到文件中
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [keyMap]
* @Return void
**/
public static void saveKeyPairToFile(Map<String,Object> keyMap){
try {
// 公钥原始字符串
String publicKeyOriginalString = CastUtils.castString(keyMap.get(PUBLIC_KEY));
log.info("公钥:"+publicKeyOriginalString);
// 私钥原始字符串
String privateKeyOriginalString = CastUtils.castString(keyMap.get(PRIVATE_KEY));
log.info("私钥:"+privateKeyOriginalString);
// 需要存储的公钥字符串键值对
StringBuilder publicKeyOutString = new StringBuilder("");
publicKeyOutString.append(PUBLIC_KEY).append(KEY_AND_VALUE_SEPARATOR).append(publicKeyOriginalString);
// 需要存储的私钥字符串键值对
StringBuilder privateKeyOutString = new StringBuilder("");
privateKeyOutString.append(PUBLIC_KEY).append(KEY_AND_VALUE_SEPARATOR).append(privateKeyOriginalString);
// 公钥存储地址
String publicKeyPath = CastUtils.castString(keyMap.get(PUBLIC_KEY_FILE_SAVE_PATH));
File publicKeyFile = new File(publicKeyPath);
if (!publicKeyFile.exists()){
publicKeyFile.getParentFile().mkdirs();
}
log.info("公钥存储地址:"+publicKeyPath);
// 私钥存储地址
String privateKeyPath = CastUtils.castString(keyMap.get(PRIVATE_KEY_FILE_SAVE_PATH));
File privateKeyFile = new File(privateKeyPath);
if (!privateKeyFile.exists()){
privateKeyFile.getParentFile().mkdirs();
}
log.info("私钥存储地址:"+privateKeyPath);
// 将密钥对写入到文件
FileWriter publicFileWriter = new FileWriter(publicKeyPath);
FileWriter privateFileWriter = new FileWriter(privateKeyPath);
BufferedWriter publicBufferedWriter = new BufferedWriter(publicFileWriter);
BufferedWriter privateBufferedWriter = new BufferedWriter(privateFileWriter);
publicBufferedWriter.write(publicKeyOutString.toString());
privateBufferedWriter.write(privateKeyOutString.toString());
publicBufferedWriter.flush();
publicBufferedWriter.close();
publicFileWriter.close();
privateBufferedWriter.flush();
privateBufferedWriter.close();
privateFileWriter.close();
}catch (Exception e){
e.printStackTrace();
log.error(e.getMessage());
}
}
/**
* @Description 从文件中输入流中获得密钥(公钥或者私钥[根据传入的地址不同读取不同的文件])字符串
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [keyFilePath]
* @Return java.lang.String
**/
public static String getKeyByFile(String keyFilePath) throws Exception {
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader(keyFilePath));
String readLine = null;
StringBuilder keyOutStr = new StringBuilder();
// 读取文件
while ((readLine = bufferedReader.readLine()) != null) {
keyOutStr.append(readLine);
}
bufferedReader.close();
// 密钥字符串
String keyStr = "";
if (keyOutStr.toString().indexOf(KEY_AND_VALUE_SEPARATOR) != -1){
String[] keyOutStrArr = keyOutStr.toString().split(KEY_AND_VALUE_SEPARATOR);
if (keyOutStrArr != null && keyOutStrArr.length >1){
keyStr = keyOutStrArr[1];
}
}
return keyStr;
} catch (IOException e) {
throw new Exception("密钥数据流读取错误");
} catch (NullPointerException e) {
throw new Exception("密钥输入流为空");
}
}
/**
* @Description 获取持久的密钥对(直接从密钥文件中读取的)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param []
* @Return java.util.Map<java.lang.String,java.lang.Object> 返回持久的公钥和私钥
**/
public static Map<String, Object> getLastingKeyPair() throws Exception {
Map<String, Object> returnMap = new LinkedHashMap<>();
// 读取文件中的公钥 获取方式为:基础文件路径 + 公钥文件存储地址
String publicKeyFileStr = RsaUtils.getKeyByFile(PUBLIC_KEY_FILE_ULR);
if (publicKeyFileStr != null && !publicKeyFileStr.equals("")){
// 公钥
returnMap.put(PUBLIC_KEY,publicKeyFileStr);
log.info("持久化公钥:"+publicKeyFileStr);
}
// 读取文件中的私钥 获取方式为:基础文件路径 + 私钥文件存储地址
String privateKeyFileStr = RsaUtils.getKeyByFile(PRIVATE_KEY_FILE_ULR);
if (privateKeyFileStr != null && !privateKeyFileStr.equals("")){
// 私钥
returnMap.put(PRIVATE_KEY,privateKeyFileStr);
log.info("持久化私钥:"+privateKeyFileStr);
}
return returnMap;
}
/************************************************* 密钥初始化、持久化、获取end *************************************************/
/**
* @Description 分组加密/解密
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [rsaMode, dataByteArr, cipher]
* @param rsaMode RSA模式:encrypt:加密 decrypt:解密
* @param dataByteArr 需要加密/解密的数据字节数组
* @param cipher
* @Return byte[] 完成加密/解密之后的字节数组
**/
public static byte[] groupEncryptOrDecrypt(String rsaMode,byte[] dataByteArr, Cipher cipher) throws BadPaddingException, IllegalBlockSizeException {
// 结果数组
byte[] returnByteArr = {};
// 分段处理
int dataByteArrLength = dataByteArr.length;
log.info("数据字节数:" + dataByteArrLength);
// 最大加密/解密字节数,超出最大字节数需要分组加密/解密
int MAX_BLOCK = 0;
if (rsaMode != null && !rsaMode.equals("")){
// 加密模式
if (RSA_MODE_01.equalsIgnoreCase(rsaMode)){
// 117
MAX_BLOCK = ENCRYPT_MAX_SIZE;
}
// 解密模式
if (RSA_MODE_02.equalsIgnoreCase(rsaMode)){
// 128
MAX_BLOCK = DECRYPT_MAX_SIZE;
}
}
// 标识
int offSet = 0;
// 缓存数组
byte[] tempByteArr = {};
// 判断加密/解密字节数 - 标识 是否到达末尾
while (dataByteArrLength - offSet > 0) {
// 如果加密/解密字节数 - 标识 > 最大加密/解密字节数
if (dataByteArrLength - offSet > MAX_BLOCK) {
// 执行加密/解密 标识位 到 最大加密/解密字节数位
tempByteArr = cipher.doFinal(dataByteArr, offSet, MAX_BLOCK);
// 标识 = 自身 + 最大加密/解密字节数
offSet += MAX_BLOCK;
} else {
// 如果加密/解密字节数 - 标识 小于等于 最大加密/解密字节数
// 执行加密/解密 标识位 到 (加密/解密字节数 - 标志)位
tempByteArr = cipher.doFinal(dataByteArr, offSet, dataByteArrLength - offSet);
// 标识 = 加密/解密字节数
offSet = dataByteArrLength;
}
// 创建信息的数组 原来数组的长度 想要得到的新数组的长度(原数组长度 + 缓存数组长度)
returnByteArr = Arrays.copyOf(returnByteArr, returnByteArr.length + tempByteArr.length);
// 数组复制 (源数组, 源数组要复制的起始位置, 目标数组, 目标数组放置的起始位置, 要复制的长度)
// 将缓存数组中的数据 复制到结果数组中
System.arraycopy(tempByteArr, 0, returnByteArr, returnByteArr.length - tempByteArr.length, tempByteArr.length);
}
return returnByteArr;
}
/************************************************* 加密start *************************************************/
/**
* @Description 私钥加密(字节数组)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待加密数据
* @param key 密钥
* @Return byte[] 加密之后的数据
**/
public static byte[] encryptByPrivateKey(byte[] data,byte[] key) throws Exception{
// 返回结果
byte[] result = {};
// 取得私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
// 实例化密钥工厂 RSA 算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 加密模式 1
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
// RSA模式 加密模式
String rsaMode = RSA_MODE_01;
// 分组加密
byte[] returnByteArr = RsaUtils.groupEncryptOrDecrypt(rsaMode,data,cipher);
if (returnByteArr != null && returnByteArr.length > 0){
result = returnByteArr;
}
return result;
}
/**
* @Description 公钥加密(字节数组)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待加密的数据
* @param key 密钥
* @Return byte[] 加密之后的数据
**/
public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
// 返回结果
byte[] result = {};
// 实例化密钥工厂 RSA 算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 初始化公钥
// 密钥材料转换
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
// 产生公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 加密模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// RSA模式 加密模式
String rsaMode = RSA_MODE_01;
// 分组加密
byte[] returnByteArr = RsaUtils.groupEncryptOrDecrypt(rsaMode,data,cipher);
if (returnByteArr != null && returnByteArr.length > 0){
result = returnByteArr;
}
return result;
}
/**
* @Description 公钥加密(字符串)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待加密的数据
* @param key 密钥
* @Return java.lang.String 加密之后的数据
**/
public static String encryptByPublicKey(String data,String key) throws Exception{
// 返回结果
StringBuilder result = new StringBuilder("");
// 实例化密钥工厂 RSA 算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 初始化公钥
// 密钥材料转换
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(key));
// 产生公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 加密模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 将数据字符串转换为字节数组
byte[] dataByteArr = data.getBytes();
// RSA模式 加密模式
String rsaMode = RSA_MODE_01;
// 分组加密
byte[] returnByteArr = RsaUtils.groupEncryptOrDecrypt(rsaMode,dataByteArr,cipher);
if (returnByteArr != null && returnByteArr.length > 0){
result.append(Base64.encode(returnByteArr));
}
return result.toString();
}
/**
* @Description 私钥加密(字符串)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待加密数据
* @param key 密钥
* @Return java.lang.String 加密之后的数据
**/
public static String encryptByPrivateKey(String data,String key) throws Exception{
// 返回结果
StringBuilder result = new StringBuilder("");
// 取得私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(key));
// 实例化密钥工厂 RSA 算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 加密模式 1
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
// 将数据字符串转换为字节数组
byte[] dataByteArr = data.getBytes();
// RSA模式 加密模式
String rsaMode = RSA_MODE_01;
// 分组加密
byte[] returnByteArr = RsaUtils.groupEncryptOrDecrypt(rsaMode,dataByteArr,cipher);
if (returnByteArr != null && returnByteArr.length > 0){
result.append(Base64.encode(returnByteArr));
}
return result.toString();
}
/************************************************* 加密end *************************************************/
/************************************************* 解密start *************************************************/
/**
* @Description 私钥解密(字节数组)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待解密数据
* @param key 密钥
* @Return byte[] 解密之后的数据
**/
public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws Exception{
// 返回的结果字节数组
byte[] resultByteArr = {};
// 取得私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key);
// 实例化密钥工厂 RSA算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 解密模式
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// RSA模式 解密模式
String rsaMode = RSA_MODE_02;
// 分组解密
byte[] returnBytes = RsaUtils.groupEncryptOrDecrypt(rsaMode,data,cipher);
if (returnBytes != null && resultByteArr.length >0){
resultByteArr = returnBytes;
}
return resultByteArr;
}
/**
* @Description 公钥解密(字节数组)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待解密数据
* @param key 密钥
* @Return byte[] 解密之后的数据
**/
public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception{
// 返回的结果字节数组
byte[] resultByteArr = {};
// 实例化密钥工厂 RSA算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 初始化公钥
// 密钥材料转换
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
// 产生公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 解密模式
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// RSA模式 解密模式
String rsaMode = RSA_MODE_02;
// 分组解密
byte[] returnBytes = RsaUtils.groupEncryptOrDecrypt(rsaMode,data,cipher);
if (returnBytes != null && resultByteArr.length >0){
resultByteArr = returnBytes;
}
return resultByteArr;
}
/**
* @Description 私钥解密(字符串)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待解密数据
* @param key 密钥
* @Return java.lang.String 解密之后的数据
**/
public static String decryptByPrivateKey(String data,String key) throws Exception{
// 解密之后的明文字符串
StringBuilder result = new StringBuilder("");
// 取得私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(key));
// 实例化密钥工厂 RSA算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 解密模式
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 将字符串数据转换为字节数组
byte[] dataByteArr = Base64.decode(data);
// RSA模式 解密模式
String rsaMode = RSA_MODE_02;
// 分组解密
byte[] resultBytes = RsaUtils.groupEncryptOrDecrypt(rsaMode,dataByteArr,cipher);
// 给返回结果赋值
// TODO 特别注意: 本处将字节数组装换为字符串的时候,必须使用 new String()方法,不能使用toString()方法
// TODO toString()方法是调用的对象本身的,也就是继承或者重写的object.toString()方法,如果是byte[] b,那么返回的是b的内存地址。
// TODO new String()方法是使用虚拟机默认的编码base返回对应的字符。
result.append(new String(resultBytes));
return result.toString();
}
/**
* @Description 公钥解密(字节数组)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [data, key]
* @param data 待解密数据
* @param key 密钥
* @Return ava.lang.String 解密之后的数据
**/
public static String decryptByPublicKey(String data,String key) throws Exception{
// 解密之后的明文字符串
StringBuilder result = new StringBuilder("");
// 实例化密钥工厂 RSA算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 初始化公钥
// 密钥材料转换
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(key));
// 产生公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
// 解密模式
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// 将字符串数据转换为字节数组
byte[] dataByteArr = Base64.decode(data);
// RSA模式 解密模式
String rsaMode = RSA_MODE_02;
// 分组解密
byte[] resultBytes = RsaUtils.groupEncryptOrDecrypt(rsaMode,dataByteArr,cipher);
// 给返回结果赋值
// TODO 特别注意: 本处将字节数组装换为字符串的时候,必须使用 new String()方法,不能使用toString()方法
// TODO toString()方法是调用的对象本身的,也就是继承或者重写的object.toString()方法,如果是byte[] b,那么返回的是b的内存地址。
// TODO new String()方法是使用虚拟机默认的编码base返回对应的字符。
result.append(new String(resultBytes));
return result.toString();
}
/************************************************* 解密end *************************************************/
/************************************************* 生成签名、签名验证start *************************************************/
/**
* @Description 生成签名
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [content, privateKey]
* @param content 待签名的数据原文
* @param privateKey 私钥字符串
* @Return java.lang.String 签名值
**/
public static String generatorSign(String content, String privateKey) {
String signStr = "";
try {
// 取得私钥
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
// 实例化密钥工厂 RSA算法的
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// 实例化签名
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
// 初始化签名
signature.initSign(priKey);
// 签名更新
signature.update(content.getBytes());
// 生成的签名字节数组
byte[] signByteArr = signature.sign();
// 返回Base64编码的签名字符串
signStr = Base64.encode(signByteArr);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
return signStr;
}
/**
* @Description 检查签名是否合法性
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [content, sign, publicKey]
* @param content 待签名的数据原文
* @param sign 签名值
* @param publicKey 私钥
* @Return boolean 是否合法
**/
public static boolean checkSignVerify(String content, String sign, String publicKey) {
boolean isOK = false;
try {
// 取得公钥
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(publicKey));
// 实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成公钥
PublicKey pubKey = keyFactory.generatePublic(x509EncodedKeySpec);
// 实例化签名
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
// 签名验证初始化
signature.initVerify(pubKey);
// 更新签名
signature.update(content.getBytes());
// 验证签名是否合法
isOK = signature.verify(Base64.decode(sign));
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
return isOK;
}
/************************************************* 生成签名、签名验证end *************************************************/
}
RsaUtils.java
Base64类可以使用java自带的Base64替代:
package com.sxy.rsademo.utils;
public final class Base64 {
static private final int BASELENGTH = 128;
static private final int LOOKUPLENGTH = 64;
static private final int TWENTYFOURBITGROUP = 24;
static private final int EIGHTBIT = 8;
static private final int SIXTEENBIT = 16;
static private final int FOURBYTE = 4;
static private final int SIGN = -128;
static private final char PAD = '=';
static private final boolean fDebug = false;
static final private byte[] base64Alphabet = new byte[BASELENGTH];
static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
static {
for (int i = 0; i < BASELENGTH; ++i) {
base64Alphabet[i] = -1;
}
for (int i = 'Z'; i >= 'A'; i--) {
base64Alphabet[i] = (byte) (i - 'A');
}
for (int i = 'z'; i >= 'a'; i--) {
base64Alphabet[i] = (byte) (i - 'a' + 26);
}
for (int i = '9'; i >= '0'; i--) {
base64Alphabet[i] = (byte) (i - '0' + 52);
}
base64Alphabet['+'] = 62;
base64Alphabet['/'] = 63;
for (int i = 0; i <= 25; i++) {
lookUpBase64Alphabet[i] = (char) ('A' + i);
}
for (int i = 26, j = 0; i <= 51; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('a' + j);
}
for (int i = 52, j = 0; i <= 61; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('0' + j);
}
lookUpBase64Alphabet[62] = (char) '+';
lookUpBase64Alphabet[63] = (char) '/';
}
private static boolean isWhiteSpace(char octect) {
return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
}
private static boolean isPad(char octect) {
return (octect == PAD);
}
private static boolean isData(char octect) {
return (octect < BASELENGTH && base64Alphabet[octect] != -1);
}
/**
* Encodes hex octects into Base64
*
* @param binaryData Array containing binaryData
* @return Encoded Base64 array
*/
public static String encode(byte[] binaryData) {
if (binaryData == null) {
return null;
}
int lengthDataBits = binaryData.length * EIGHTBIT;
if (lengthDataBits == 0) {
return "";
}
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
char encodedData[] = null;
encodedData = new char[numberQuartet * 4];
byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
int encodedIndex = 0;
int dataIndex = 0;
if (fDebug) {
System.out.println("number of triplets = " + numberTriplets);
}
for (int i = 0; i < numberTriplets; i++) {
b1 = binaryData[dataIndex++];
b2 = binaryData[dataIndex++];
b3 = binaryData[dataIndex++];
if (fDebug) {
System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
}
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
if (fDebug) {
System.out.println("val2 = " + val2);
System.out.println("k4 = " + (k << 4));
System.out.println("vak = " + (val2 | (k << 4)));
}
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
}
// form integral number of 6-bit groups
if (fewerThan24bits == EIGHTBIT) {
b1 = binaryData[dataIndex];
k = (byte) (b1 & 0x03);
if (fDebug) {
System.out.println("b1=" + b1);
System.out.println("b1<<2 = " + (b1 >> 2));
}
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
encodedData[encodedIndex++] = PAD;
encodedData[encodedIndex++] = PAD;
} else if (fewerThan24bits == SIXTEENBIT) {
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
encodedData[encodedIndex++] = PAD;
}
return new String(encodedData);
}
/**
* Decodes Base64 data into octects
*
* @param encoded string containing Base64 data
* @return Array containind decoded data.
*/
public static byte[] decode(String encoded) {
if (encoded == null) {
return null;
}
char[] base64Data = encoded.toCharArray();
// remove white spaces
int len = removeWhiteSpace(base64Data);
if (len % FOURBYTE != 0) {
// should be divisible by four
return null;
}
int numberQuadruple = (len / FOURBYTE);
if (numberQuadruple == 0) {
return new byte[0];
}
byte decodedData[] = null;
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
int i = 0;
int encodedIndex = 0;
int dataIndex = 0;
decodedData = new byte[(numberQuadruple) * 3];
for (; i < numberQuadruple - 1; i++) {
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
|| !isData((d3 = base64Data[dataIndex++]))
|| !isData((d4 = base64Data[dataIndex++]))) {
return null;
}//if found "no data" just return null
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
}
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
//if found "no data" just return null
return null;
}
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
d3 = base64Data[dataIndex++];
d4 = base64Data[dataIndex++];
// Check if they are PAD characters
if (!isData((d3)) || !isData((d4))) {
if (isPad(d3) && isPad(d4)) {
// last 4 bits should be zero
if ((b2 & 0xf) != 0)
{
return null;
}
byte[] tmp = new byte[i * 3 + 1];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
return tmp;
} else if (!isPad(d3) && isPad(d4)) {
b3 = base64Alphabet[d3];
//last 2 bits should be zero
if ((b3 & 0x3) != 0)
{
return null;
}
byte[] tmp = new byte[i * 3 + 2];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
return tmp;
} else {
return null;
}
} else {
//No PAD e.g 3cQl
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
}
return decodedData;
}
/**
* remove WhiteSpace from MIME containing encoded Base64 data.
*
* @param data the byte array of base64 data (with WS)
* @return the new length
*/
private static int removeWhiteSpace(char[] data) {
if (data == null) {
return 0;
}
// count characters that's not whitespace
int newSize = 0;
int len = data.length;
for (int i = 0; i < len; i++) {
if (!isWhiteSpace(data[i])) {
data[newSize++] = data[i];
}
}
return newSize;
}
}
Base64.java
转型工具类:
package com.sxy.rsademo.utils;
/**
* @Description 转型工具类
* @Author SuXingYong
* @Date 2020/7/11 23:35
**/
public final class CastUtils {
/**
* @Description 转为String 型 默认为空
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [obj]
* @param obj
* @Return java.lang.String
**/
public static String castString(Object obj) {
return CastUtils.castString(obj, "");
}
/**
* @Description 转为String 型(提供默认值)
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [obj, defaultValue]
* @param obj
* @param defaultValue 默认值
* @Return java.lang.String
**/
public static String castString(Object obj, String defaultValue) {
return obj != null ? String.valueOf(obj) : defaultValue;
}
}
CastUtils.java
统一返回常量类:
package com.sxy.rsademo.utils;
/**
* @Description: 返回常量
* @Author: SuXingYong
* @Date 2020/7/11 23:35
**/
public class ReturnConstant {
/** 返回值常量 - 成功 **/
public final static String SUCCESS = "success";
/** 返回值常量 - 失败 **/
public final static String ERROR = "error";
}
ReturnConstant.java
HttpClientUtils工具类:
package com.sxy.rsademo.utils;
import com.alibaba.fastjson.JSON;
import com.sxy.rsademo.rsa.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
/**
* @Description HttpClient 工具类
* @Author SuXingYong
* @Date 2020/7/11 23:35
**/
@Slf4j
public class HttpClientUtils {
/** 目标服务器 - URL - 01 **/
public final static String CLIENT_URL_01 = "http://localhost:9009/target-server/data/receive";
/** 目标服务器 - 数据 - 键名 **/
public final static String SERVER_DATA_KEY = "dataJson";
/** 目标服务器 - 签名 - 键名 **/
public final static String SERVER_SIGN_KEY = "sign";
public static void main(String[] args) {
try {
String url = "";
Map<String, String> parameterMap = new LinkedHashMap<>();
// 发送数据
Map<String, String> resultMap = HttpClientUtils.sendDataToTargetServerForOne(url,parameterMap);
for (Map.Entry<String, String> result : resultMap.entrySet()){
log.info("result==》 "+result.getKey()+": "+result.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 构造数据
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param []
* @Return java.util.Map<java.lang.String,java.lang.String>
**/
public static Map<String,String> createData() throws UnsupportedEncodingException {
Map<String, String> returnMap = new LinkedHashMap<>();
Map<String, String> dataMap = new LinkedHashMap<>();
dataMap.put("id","11eh-9b58-af45b5c8-b5e2-9d0036e9473z");
dataMap.put("name","小明");
dataMap.put("loginName","xiaoming");
dataMap.put("phone","12345678901");
dataMap.put("time","2020-07-12 00:33:27");
dataMap.put("content","随便整了些内容,就验证一下。");
for (Map.Entry<String, String> data : dataMap.entrySet()){
returnMap.put(data.getKey(),URLEncoder.encode(data.getValue(),"UTF-8"));
}
return returnMap;
}
/**
* @Description 单条发送数据
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [url,parameterMap]
* @Return java.util.Map<java.lang.String,java.lang.String>
**/
public static Map<String, String> sendDataToTargetServerForOne(String url,Map<String, String> parameterMap) throws Exception {
// 返回结果集
Map<String, String> returnMap = new LinkedHashMap<>();
// 请求参数 传入参数结果集为空的时候就直接使用默认值
Map<String, String> requestMap = HttpClientUtils.createData();
if (parameterMap != null && parameterMap.size() >0){
// 清空默认值
requestMap = new LinkedHashMap<>();
// 对参数集合的值进行url编码
for (Map.Entry<String, String> param : parameterMap.entrySet()){
requestMap.put(param.getKey(),URLEncoder.encode(param.getValue(),"UTF-8"));
}
}
if (requestMap != null && requestMap.size() >0){
// 数据参数字符串
StringBuilder dataStr = new StringBuilder("");
// 遍历参数集合并拼接成字符串
for (Map.Entry<String, String> map : requestMap.entrySet()){
// 键名
String dataKey = map.getKey();
// 键值
String dataValue = map.getValue();
dataStr.append(dataKey).append("=");
dataStr.append(dataValue);
dataStr.append("&");
}
log.info("send==》 dataStr:"+dataStr);
// 去除最后一个&符号
String paramStr = dataStr.toString().substring(0, dataStr.length() - 1);
log.info("send==》 paramStr:"+paramStr);
// 服务器原文数据
//requestMap.put("originalTextData",paramStr);
// 将数据转化为json字符串
String dataJson = JSON.toJSONString(requestMap);
log.info("send==》 dataJson: "+dataJson);
// 重置请求参数集合
requestMap = new LinkedHashMap<>();
// 将json数据放到请求参数集合中
//requestMap.put("data",dataJson);
// 密钥对
Map<String,Object> keyMap = RsaUtils.getLastingKeyPair();
// 使用持久化公钥对数据进行加密
String cipherTextData = RsaUtils.encryptByPublicKey(dataJson, CastUtils.castString(keyMap.get(RsaUtils.PUBLIC_KEY)));
log.info("send==》 cipherTextData: "+cipherTextData);
// 服务器密文数据
requestMap.put("data",cipherTextData);
// 使用持久化私钥生成签名
String sign = RsaUtils.generatorSign(cipherTextData, CastUtils.castString(keyMap.get(RsaUtils.PRIVATE_KEY)));
//
log.info("send==》 sign: "+sign);
// 请求参数中需带上签名字符串
requestMap.put(SERVER_SIGN_KEY, sign);
// 将请求参数转化为json字符串
String requestJson = JSON.toJSONString(requestMap);
log.info("send==》 requestJson:"+requestJson);
// 请求地址 没有传入的时候就使用默认值
String requestUrl = CLIENT_URL_01;
if (url != null && url != ""){
requestUrl = url;
log.info("send==》 requestUrl:"+requestUrl);
}
if (requestUrl != null && requestUrl != ""){
requestMap = new LinkedHashMap<>();
requestMap.put(SERVER_DATA_KEY, requestJson);
if (requestMap != null && requestMap.size() >0){
//发送POST请求 parameterMap模式
returnMap = HttpClientUtils.sendPostRequest(requestUrl,requestMap);
}else{
returnMap.put(ReturnConstant.ERROR,"请求数据参数为空,不支持");
}
//if (requestJson != null && requestJson != ""){
// 发送POST请求 json模式
// returnMap = HttpClientUtils.sendPostRequest(requestUrl,requestJson);
//}else{
// returnMap.put(ReturnConstant.ERROR,"请求数据参数为空,不支持");
//}
}else{
returnMap.put(ReturnConstant.ERROR,"请求地址为空,不支持");
}
}else{
returnMap.put(ReturnConstant.ERROR,"发送数据为空,不支持");
}
return returnMap;
}
/**
* @Description 批量发送数据
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [url, dataList]
* @Return java.util.Map<java.lang.String,java.lang.String>
**/
public static Map<String,String> sendDataToTargetServerForList(String url, List<Map<String,String>> dataList) throws Exception{
// 返回结果集
Map<String, String> returnMap = new LinkedHashMap<>();
// 请求参数集合
Map<String, String> requestMap = new LinkedHashMap<>();
if (dataList != null && dataList.size() >0){
// 缓存列表
List<Map<String, String>> cacheList = new ArrayList<>();
for (int i = 0 ; i < dataList.size() ; i++){
// 对参数进行编码之后的新集合
Map<String, String> newDataMap = new LinkedHashMap<>();
Map<String, String> dataMap = dataList.get(i);
// 对参数集合的值进行url编码
for (Map.Entry<String, String> data : dataMap.entrySet()){
newDataMap.put(data.getKey(),URLEncoder.encode(data.getValue(),"UTF-8"));
}
if (newDataMap != null && newDataMap.size() >0){
// 将编码后的新集合放到缓存数组中
cacheList.add(newDataMap);
}
}
if (cacheList != null && cacheList.size() >0){
// 重置数据列表
dataList = new ArrayList<>();
dataList = cacheList;
}
// 将数据转化为json字符串
String dataJson = JSON.toJSONString(dataList);
log.info("send==》 dataJson: "+dataJson);
// 将数据json字符串放到请求参数中
//requestMap.put("originalTextData",dataJson);
// 密钥对
Map<String,Object> keyMap = RsaUtils.getLastingKeyPair();
// 使用持久化公钥对数据进行加密
String cipherTextData = RsaUtils.encryptByPublicKey(dataJson, CastUtils.castString(keyMap.get(RsaUtils.PUBLIC_KEY)));
log.info("send==》 cipherTextData: "+cipherTextData);
// 发送密文数据
requestMap.put("data",cipherTextData);
// 使用持久化私钥生成签名
String sign = RsaUtils.generatorSign(cipherTextData, CastUtils.castString(keyMap.get(RsaUtils.PRIVATE_KEY)));
//
log.info("send==》 sign: "+sign);
// 请求参数中需带上签名字符串
requestMap.put(SERVER_SIGN_KEY, sign);
// 将请求参数转化为json字符串
String requestJson = JSON.toJSONString(requestMap);
log.info("send==》 requestJson:"+requestJson);
// 请求地址 没有传入的时候就使用默认值
String requestUrl = CLIENT_URL_01;
if (url != null && url != ""){
requestUrl = url;
log.info("send==》 requestUrl:"+requestUrl);
}
if (requestUrl != null && requestUrl != ""){
if (requestJson != null && requestJson != ""){
// 发送POST请求 json模式
returnMap = HttpClientUtils.sendPostRequest(requestUrl,requestJson);
}else{
returnMap.put(ReturnConstant.ERROR,"请求数据参数为空,不支持");
}
}else {
returnMap.put(ReturnConstant.ERROR, "请求地址为空,不支持");
}
}else{
returnMap.put(ReturnConstant.ERROR,"数据为空,不支持");
}
return returnMap;
}
/**
* @Description 发送POST请求 parameterMap模式
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [url, json]
* @Return java.util.Map<java.lang.String,java.lang.String>
**/
public static Map<String, String> sendPostRequest(String url,Map<String, String> parameterMap){
// 返回结果
Map<String, String> returnMap = new LinkedHashMap<>();
OutputStream out = null;
BufferedReader in = null;
HttpURLConnection conn = null;
String result = "";
try {
StringBuilder data = new StringBuilder();
for (Map.Entry<String, String> dataKeyValue : parameterMap.entrySet()) {
String dataName = dataKeyValue.getKey();
String dataValue = dataKeyValue.getValue();
data.append(dataName).append("=");
//data.append(dataValue);
// 转换为UTF-8编码
data.append(URLEncoder.encode(dataValue, "UTF-8"));
data.append("&");
}
data.append("sendTime=").append(System.currentTimeMillis());
log.info("send==》 parameterMapStr: "+data.toString());
byte[] entity = data.toString().getBytes();
conn = (HttpURLConnection)new URL(url).openConnection();
conn.setUseCaches(false);
// 10000
conn.setConnectTimeout(10000);
// POST
conn.setRequestMethod("POST");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(entity.length));
out = conn.getOutputStream();
// 获取URLConnection对象对应的输出流
out = conn.getOutputStream();
// 发送请求参数
out.write(entity);
// flush输出流的缓冲
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
returnMap.put(ReturnConstant.SUCCESS,result);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return returnMap;
}
/**
* @Description 发送POST请求 json字符串模式
* @Author SuXingYong
* @Date 2020/7/11 23:35
* @Param [url, json]
* @Return java.util.Map<java.lang.String,java.lang.String>
**/
public static Map<String, String> sendPostRequest(String url,String json){
// 返回结果集
Map<String, String> returnMap = new LinkedHashMap<>();
// 创建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost(url);
log.info("send==》 json:"+json);
// 创建请求内容
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(entity);
// 执行http请求
response = httpClient.execute(httpPost);
returnMap.put(ReturnConstant.SUCCESS, EntityUtils.toString(response.getEntity(), "utf-8"));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return returnMap;
}
/**
* 获取sendPostRequest请求的Json数据
*/
private String getRequestPostData(HttpServletRequest request) throws IOException {
int contentLength = request.getContentLength();
if (contentLength < 0) {
return null;
}
byte buffer[] = new byte[contentLength];
for (int i = 0; i < contentLength;) {
int len = request.getInputStream().read(buffer, i, contentLength - i);
if (len == -1) {
break;
}
i += len;
}
return new String(buffer, "utf-8");
}
}
HttpClientUtils.java
SpringBoot项目运行入口类:
package com.sxy.rsademo;
import com.sxy.rsademo.rsa.RsaUtils;
import com.sxy.rsademo.utils.HttpClientUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.Map;
@Slf4j
@SpringBootApplication
public class RsaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RsaDemoApplication.class, args);
// 初始化密钥对,并持久化存储
RsaUtils.initKey();
try {
// 获取持久化密钥对
Map<String,Object> keyMap = RsaUtils.getLastingKeyPair();
for (Map.Entry<String,Object> entry :keyMap.entrySet()){
log.info("keyMap==》 "+entry.getKey()+": "+entry.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
// 发送数据进行测试
HttpClientUtils.main(args);
}
}
RsaDemoApplication.java
pom.xml maven依赖文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sxy</groupId>
<artifactId>rsa-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rsa-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<fastjson.version>1.2.62</fastjson.version>
<httpClient.version>4.5.12</httpClient.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpClient.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
pom.xml
运行结果:
密钥对生成成功:
私钥持久化文件:
公钥持久化文件:
至此,RSA算法的密钥对的初始化,持久化保存、读取,数据签名、加密、发送等基本功能已完成;
关于数据如何接收、验证签名以及解密将在下一篇文章中继续分享;
沉浸在代码的海洋中无法自拔