这里提供一个RSA加密算法的工具类,其中包含生成密钥、加密、解密、加签、验签等RSA常用的方法,可以直接使用
引入 Maven 依赖,(如果不引入则需要修改 base64加密、解密方法为 java.ultils.base64
)
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.19.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
package cn.lzscxb.common.utils; import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; 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.HashMap; import java.util.Map; /** * @Description RSA非对称加密算法工具类 * @Author LzsCxb * @Date 2022/07/04 20:26 */ public class RSAUtils { /** * RSA最大加密明文大小 2048/8-11 */ private static final int MAX_ENCRYPT_BLOCK = 245; /** * RSA最大解密密文大小 2048/8 */ private static final int MAX_DECRYPT_BLOCK = 256; /** * 定义加密方式 */ public static final String KEY_RSA = "RSA"; /** * 定义公钥 */ public static final String KEY_RSA_PUBLICKEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhbMJG9i6O0T1hQ8oCoThMAg/0mlcerjYn+wMdZudoDCeEbxKYebs+WoNvBmV26A/co9yJ2+aUIf60kkJ6YwDh9pXSk2vgm7x0TAZ9HzRhpk6td4JO4HM9QpPaQG2Z3Tw8DnhNk7yGADp+weLqgULDDlUI7lm1s1G9OSY+ZK2TwjKPSC4j1CnjD6kvSW1qVGB0GhkreX877Rop+KbOmVE+JtQQgc+DcOgyMjGtSvDGrwBsI569wrywlOeFMLqVDlVLi3ugWDSEn3EHz63Nj442VSfR6ukxtifIwmogUI4VplXQoO4Am6kKH50tkggqVBNFGh0s5qavpig0XYkn42+6QIDAQAB"; /** * 定义私钥 */ public static final String KEY_RSA_PRIVATEKEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCFswkb2Lo7RPWFDygKhOEwCD/SaVx6uNif7Ax1m52gMJ4RvEph5uz5ag28GZXboD9yj3Inb5pQh/rSSQnpjAOH2ldKTa+CbvHRMBn0fNGGmTq13gk7gcz1Ck9pAbZndPDwOeE2TvIYAOn7B4uqBQsMOVQjuWbWzUb05Jj5krZPCMo9ILiPUKeMPqS9JbWpUYHQaGSt5fzvtGin4ps6ZUT4m1BCBz4Nw6DIyMa1K8MavAGwjnr3CvLCU54UwupUOVUuLe6BYNISfcQfPrc2PjjZVJ9Hq6TG2J8jCaiBQjhWmVdCg7gCbqQofnS2SCCpUE0UaHSzmpq+mKDRdiSfjb7pAgMBAAECggEAR3vSAvF9oPLd0qan4ffp7qR6eyWaLINoTxkGEFuDi4JzAUiK/I1bZn8tmMSVOzgStE292xfwid4qXQRwKE6UFK7IvRGMJVDsOcxeFDooTK7glRyCEy7zRpCcpKglvmrn54kKwN600eCrOWxvYBgSMBb2xaL7OR3IMmeG4uluUBK8u8phRfXbt1CaQvzfqZqZbspE/XX23Lgnxq/7PV2ME1ukOHAzQm8XdSQosLTX2WhbGBCG8xG1Ia9qZ5R63Y3Gk8gnXxVEpzcbtF7sxU/hDwdpfb7wiIQTyoBcL/XIr9I42p4TvizAtr4spzzkIMprKiEAP1IozBCD3YWvPMUJgQKBgQDGgSoosujtJ2OicvtJrO67YW6ecMc9L2VBY/qAxrivC+Ups/rS2PPchNy9abv8JGnCpa1MdOUudpaSv9g47BES5NwZ38bGHj+U7Wg9VIRQ/G8dxWelQrVgALLJ9mjDmJrenUmfwBaYqej3fvYZMA/hWT0CUhBWKVn1X0nPzXlYRwKBgQCsbKgHrQK39bccVMBDBnsRLXzJOLcIFu+AHShhqQfttMeDOQiXuVpy4CAv84y0Y3/rV7Yr6RGZ1pOTOr2NvTGUka/ZfOvYi8UPULzAOLh02KBb1LtcRrvwPYuoLxKN81XYZ85yS7EggpEFtbsm0YSZozv4Vx5uccHxevzHXBn3TwKBgQCj83DPtp09qufW96LnAicXquyDfmCA/5FhBeOT0w4cvfVjkVycI0afHzl2VEtIgQa9Frvgxze3PYk14bADq66abV4BHNt/LOKU7dTHuvOiNCzOaQom68cEaO9CcfureXKIZV62zB+drdBWAo3e1dx34o3KSd9mWrcLO82qDWqo5wKBgGxZAuV/5Dtw3hWhdAcqJV9P9CAF0Y31y533tI5Zxy+p780Xo7yjrqCNEezP4FTiSVm7ji/djz/aRHW57a8JegRf396Mzy8N9VCAbXtkqRRTo8DQ1sNPd32pTv7qRYCJriIEaQgNZEqHgVXTMr1b3zUkC+Ur6WWBeluh6wHjcDWlAoGAfduQDd31wN1r8MaTv0Uj1k4YXWPQdfKlmATsD0iT1oMg2bfPVwPhs+UI5hwhu2KD/zjzS7qGyfXiTXLh11pJrlFV9D5OVsxwOKwCGe1mUuwmBtWTTLxw1Irlz91Tu3sgioSZ9MeuUHI1psAttcnxGmOq6taEXCFkr20q+9SH3fk="; /** * 定义签名算法 */ private final static String KEY_RSA_SIGNATURE = "sha256withRSA"; /** * 生成公私密钥对 */ public static Map<String, Object> init() { Map<String, Object> map = null; try { KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA); //设置密钥对的bit数,越大越安全,但速度减慢,一般使用512或1024、2048 generator.initialize(2048); KeyPair keyPair = generator.generateKeyPair(); // 获取公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 获取私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 将密钥对封装为Map map = new HashMap<String, Object>(2); map.put(KEY_RSA_PUBLICKEY, publicKey); map.put(KEY_RSA_PRIVATEKEY, privateKey); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return map; } /** * 获取 RSAPublicKey */ public static RSAPublicKey getPublicKey() throws Exception { byte[] decoded = Base64.decodeBase64(KEY_RSA_PUBLICKEY); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PublicKey publicKey = factory.generatePublic(new X509EncodedKeySpec(decoded)); return (RSAPublicKey) publicKey; } /** * 获取 RSAPrivateKey */ public static RSAPrivateKey getPrivateKey() throws Exception { byte[] decoded = Base64.decodeBase64(KEY_RSA_PRIVATEKEY); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PrivateKey privateKey = factory.generatePrivate(new PKCS8EncodedKeySpec(decoded)); return (RSAPrivateKey) privateKey; } /** * 公钥加密 如果大于245则分段加密 */ public static String encryptByPublic(String encryptingStr, String publicKeyStr) { try { // 将公钥由字符串转为UTF-8格式的字节数组 byte[] publicKeyBytes = Base64.decodeBase64(publicKeyStr); // 获得公钥 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); // 取得待加密数据 byte[] data = encryptingStr.getBytes(StandardCharsets.UTF_8); KeyFactory factory; factory = KeyFactory.getInstance(KEY_RSA); PublicKey publicKey = factory.generatePublic(keySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); // 返回加密后由Base64编码的加密信息 return new String(Base64.encodeBase64(encryptedData)); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 私钥解密 如果大于256则分段解密 */ public static String decryptByPrivate(String encryptedStr, String privateKeyStr) { try { // 对私钥解密 byte[] privateKeyBytes = Base64.decodeBase64(privateKeyStr); // 获得私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 获得待解密数据 byte[] data = Base64.decodeBase64(encryptedStr); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PrivateKey privateKey = factory.generatePrivate(keySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); // 返回UTF-8编码的解密信息 return new String(decryptedData, StandardCharsets.UTF_8); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 私钥加密 如果大于245则分段加密 */ public static String encryptByPrivate(String encryptingStr, String privateKeyStr) { try { byte[] privateKeyBytes = Base64.decodeBase64(privateKeyStr); // 获得私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 取得待加密数据 byte[] data = encryptingStr.getBytes(StandardCharsets.UTF_8); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PrivateKey privateKey = factory.generatePrivate(keySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); // 返回加密后由Base64编码的加密信息 return new String(Base64.encodeBase64(encryptedData)); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 公钥解密 如果大于256则分段解密 */ public static String decryptByPublic(String encryptedStr, String publicKeyStr) { try { // 对公钥解密 byte[] publicKeyBytes = Base64.decodeBase64(publicKeyStr); // 取得公钥 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); // 取得待加密数据 byte[] data = Base64.decodeBase64(encryptedStr); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PublicKey publicKey = factory.generatePublic(keySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); // 返回UTF-8编码的解密信息 return new String(decryptedData, StandardCharsets.UTF_8); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 用私钥对加密数据进行签名 */ public static String sign(String encryptedStr, String privateKey) { String str = ""; try { //将私钥加密数据字符串转换为字节数组 byte[] data = encryptedStr.getBytes(); // 解密由base64编码的私钥 byte[] bytes = Base64.decodeBase64(privateKey); // 构造PKCS8EncodedKeySpec对象 PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes); // 指定的加密算法 KeyFactory factory = KeyFactory.getInstance(KEY_RSA); // 取私钥对象 PrivateKey key = factory.generatePrivate(pkcs); // 用私钥对信息生成数字签名 Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); signature.initSign(key); signature.update(data); str = new String(Base64.encodeBase64(signature.sign())); } catch (Exception e) { e.printStackTrace(); } return str; } /** * 校验数字签名 * * @return 校验成功返回true,失败返回false */ public static boolean verify(String encryptedStr, String publicKey, String sign) { boolean flag = false; try { //将私钥加密数据字符串转换为字节数组 byte[] data = encryptedStr.getBytes(); // 解密由base64编码的公钥 byte[] bytes = Base64.decodeBase64(publicKey); // 构造X509EncodedKeySpec对象 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); // 指定的加密算法 KeyFactory factory = KeyFactory.getInstance(KEY_RSA); // 取公钥对象 PublicKey key = factory.generatePublic(keySpec); // 用公钥验证数字签名 Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); signature.initVerify(key); signature.update(data); flag = signature.verify(Base64.decodeBase64(sign)); } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 功能描述:格式化公私钥 C++格式 * 公钥字符串开头要加上“-----BEGIN PUBLIC KEY-----\n”,结尾加上“\n-----END PUBLIC KEY-----\n” * 私钥字符串开头要加上“-----BEGIN RSA PRIVATE KEY-----\n”,结尾加上“\n-----END RSA PRIVATE KEY-----\n” * * @param str 要格式的字符串, flag * @param flag true为公 false为私 * @return java.lang.String * @author xiaobu * @date 2020/3/18 16:40 * @version 1.0 */ public static String formatStr(String str, boolean flag) { StringBuilder sb = new StringBuilder(str); for (int i = 0, len = sb.length(); i < len; i++) { if (i % 64 == 0) { sb.insert(i, "\n"); } } if (flag) { sb = new StringBuilder("-----BEGIN PUBLIC KEY-----").append(sb).append("\n-----END PUBLIC KEY-----\n"); } else { sb = new StringBuilder("-----BEGIN RSA PRIVATE KEY-----").append(sb).append("\n-----END RSA PRIVATE KEY-----\n"); } return sb.toString(); } /** * 测试方法 */ public static void main(String[] args) { // 生成 RSA 密钥 Map<String, Object> map = new HashMap<String, Object>(2); map = RSAUtils.init(); System.out.println(map); // 使用密钥进行认证 String publicKey = RSAUtils.KEY_RSA_PUBLICKEY; String privateKey = RSAUtils.KEY_RSA_PRIVATEKEY; System.out.println("publicKey = " + publicKey); System.out.println("privateKey = " + privateKey); System.out.println("formatStr(publicKey,false) = " + formatStr(publicKey, true)); System.out.println("formatStr(privateKey,false) = " + formatStr(privateKey, false)); //由前四行代码获得公、私密钥 // publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjVgHojy7oZ1Gl/iT9CXgvzlqPyV5wxvSRW7f6qDQh1FreYVTIbyVOees9LDbyFyocLCx6Cz3E4csHJvjwIem6SuZpIpmeJGS5bo04JVK2JwdqbFoIXd1Q5bGsA17nUNlnSR4h3ODM8OCKsC0Qpt1KSvN0WB2JUGBbUFwiPxrwEMLeYntz4cABBA/KYt5Ac9HBk5TDRDpFVlOM43t0B2219GxQOxm1x8fFjwzKV06nwYbmIuqoKqQVlym3FYrYiOdd0/iXXxp4Whi0Hdo7XyfaQhoCCd3FNnFP8Ng0HDAW99HxEaP9eIuC4wCV16o8jsUzm7V/yhTF1NlIPlTQW35hQIDAQAB"; String str = "1 InnoDB 支持表锁和行锁,使用索引作为检索条件修改数据时采用行锁,否则采用表锁。\n" + "2 InnoDB 自动给修改操作加锁,给查询操作不自动加锁" + "3 行锁可能因为未使用索引而升级为表锁,所以除了检查索引是否创建的同时,也需要通过explain执行计划查询索引是否被实际使用。, RSA!"; // 公钥加密,私钥解密 String enStr1 = RSAUtils.encryptByPublic(str, publicKey); System.out.println("公钥加密后:" + enStr1); String deStr1 = RSAUtils.decryptByPrivate(enStr1, privateKey); System.out.println("私钥解密后:" + deStr1); // 私钥加密,公钥解密 String enStr2 = RSAUtils.encryptByPrivate(str, privateKey); System.out.println("私钥加密后:" + enStr2); String deStr2 = RSAUtils.decryptByPublic(enStr2, publicKey); System.out.println("公钥解密后:" + deStr2); // 产生签名 String sign = sign(enStr2, privateKey); System.out.println("签名:" + sign); // 验证签名 boolean status = verify(enStr2, publicKey, sign); System.out.println("状态:" + status); } }
package cn.lzscxb.common.utils; import cn.lzscxb.entity.exception.ConditionException; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import lombok.extern.slf4j.Slf4j; import java.util.Calendar; import java.util.Date; import java.util.Map; @Slf4j public class TokenUtils { private static final String ISSUER = "lzscxb.cn"; private static final Integer EXPIRE =30 ; /** * 生成token * * @param userId * @return * @throws Exception */ public static String generateToken(Long userId, String phone, String avatar, String nickname) { Algorithm algorithm = null; try { algorithm = Algorithm.RSA256(RSAUtils.getPublicKey(), RSAUtils.getPrivateKey()); } catch (Exception e) { throw new RuntimeException(e); } Calendar calendar = Calendar.getInstance(); // 日历类用于生成过期时间 calendar.setTime(new Date()); calendar.add(Calendar.SECOND, EXPIRE); return JWT.create().withKeyId(String.valueOf(userId)).withIssuer(ISSUER).withExpiresAt(calendar.getTime()).withClaim("user_id", userId).withClaim("phone", phone).withClaim("avatar", avatar).withClaim("nickname", nickname).sign(algorithm); } public static Map<String, Claim> VerifyToken(String token) { try { Algorithm algorithm = Algorithm.RSA256(RSAUtils.getPublicKey(), RSAUtils.getPrivateKey()); JWTVerifier verifier = JWT.require(algorithm).build(); DecodedJWT jwt = verifier.verify(token); Map<String, Claim> claims = jwt.getClaims(); return claims; } catch (TokenExpiredException e) { throw new ConditionException(401, "token 令牌已过期"); } catch (SignatureVerificationException e) { e.printStackTrace(); log.info(token); throw new ConditionException(401, "token 令牌无效"); } catch (Exception e) { throw new RuntimeException(e); } } }