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"; }
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 *************************************************/ }
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; } }
转型工具类:
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; } }
统一返回常量类:
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"; }
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"); } }
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); } }
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>
运行结果:
密钥对生成成功:
私钥持久化文件:
公钥持久化文件:
至此,RSA算法的密钥对的初始化,持久化保存、读取,数据签名、加密、发送等基本功能已完成;
关于数据如何接收、验证签名以及解密将在下一篇文章中继续分享;
原文:https://www.cnblogs.com/sxyBlog/p/13285359.html