java实现RSA接口参数加密

为什么使用RSA

对称加密:DES加密适用于一体项目、AES加密适用于前后端分离、Base64加密
非对称加密:RSA加密公钥发出去加密,私钥自己解密、Fiddler。
RSA算法的特点是产生一对密钥,用其中的一个密钥对文件加密后所产生的密文只能使用另一个密钥方能解密还原。把加密和解密的密钥分离对于互联网通信安全具有革命性的意义,由此,加密的密钥(公钥)就可以公开在网上传递而不用担心泄密,因为加密后的文件只能由另一个密钥(私钥)方可解密还原。

一、加入依赖

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.15</version>
</dependency>

1、作用

添加org.apache.commons.codec.binary.Base64;

2、Base64编码说明

Base64 是一种编码的方式, 并不是安全领域的加密解密算法。
Base64 的目的是把一些二进制符转成普通字符, 方便在网络上传输。
因为有些系统只能使用ASCII字符,有些二进制字符是控制字符,不能直接传送, 需要转换。
Base64 作用将 非ASCII字符转换为ASCII字符。

3、sun.misc.BASE64加解密跟Apache的commons-codec加解密区别

由于Sun内部API sun.misc.BASE64在编译的时候会出现后期可能被删除的潜在风险的警告,然而让我们觉得以后真的删除了,那么程序就肯定报错了,潜在很大的风险。

二、常量

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
    /**
     * 算法
     */
    private static final String ALGORITHM_NAME = "RSA";
    /**
     * MD5_RSA
     */
    private static final String MD5_RSA = "MD5withRSA";

三、引用的包

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.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;

四、获取base64加密后密钥对

    public static HashMap<String,String> getKeyPairMap() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM_NAME);
        generator.initialize(1024);
        KeyPair keyPair = generator.generateKeyPair();
        //将公钥私钥进行base64编码、使用encodeBase64进行编译编码,并返回一个byte字节数组
        String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
        String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));

        HashMap<String,String> keyMap = new HashMap<>();
        keyMap.put("privateKey",privateKey);
        keyMap.put("publicKey",publicKey);
        return keyMap;
    }

五、RSA加密

1、获取公钥

    /**
     * RSA加密,获取公钥
     * @param publicKey base64加密的公钥字符串
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        //使用decodeBase64进行破译编码,并返回一个byte字节数组
        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
        //使用X509标准作为密钥规范管理的编码格式,按照 X509 标准对其进行编码的密钥。复制数组的内容,以防随后的修改。
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        //创建一个KeyFactory对象。
        //密钥工厂用于将 密钥 ( Key类型的不透明密码密钥)转换为 密钥规范 (底层密钥资料的透明表示)

        //返回一个KeyFactory对象,用于转换指定算法的公钥/私钥。
        //返回封装指定Provider对象的KeyFactorySpi实现的新KeyFactory对象。 请注意,指定的Provider对象不必在提供程序列表中注册。
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
        //根据提供的密钥规范(密钥材料)生成公钥对象。
        return keyFactory.generatePublic(keySpec);
    }

2、加密

    /**
     * RSA加密
     * @param data      待加密数据
     * @param publicKey 公钥
     */
    public static String encrypt(String data,String publicKey) throws Exception {
        //避免前端解密时,出现中文乱码情况,提前将数据进行中编码
        //data = new String(data.getBytes("utf8"));
        data = java.net.URLEncoder.encode(data, "UTF-8");
        //Cipher此类为加密和解密提供密码功能
        //创建 Cipher 对象,应用程序调用 Cipher 的 getInstance 方法并将所请求转换 的名称传递给它
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        //RSA加密,获取公钥
        PublicKey publicKeyP = getPublicKey(publicKey);
//        Cipher对象需要初始化
//        init(int opmode, Key key, AlgorithmParameterSpec params)
//        (1)opmode :Cipher.ENCRYPT_MODE(加密模式)和 Cipher.DECRYPT_MODE(解密模式)
//        (2)key :密匙,使用传入的盐构造出一个密匙,可以使用SecretKeySpec、KeyGenerator和KeyPairGenerator创建密匙,其中
//                * SecretKeySpec和KeyGenerator支持AES,DES,DESede三种加密算法创建密匙
//                * KeyPairGenerator支持RSA加密算法创建密匙
//        (3)params :使用CBC模式时必须传入该参数,该项目使用IvParameterSpec创建iv 对象
        cipher.init(Cipher.ENCRYPT_MODE, publicKeyP);
        //获取加密内容的长度
        int inputLen = data.getBytes().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.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
        // 加密后的字符串
        return new String(Base64.encodeBase64(encryptedData));
    }

六、RSA解密

1、获取公钥

    /**
     * 获取私钥
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
        //根据提供的密钥规范(密钥材料)生成公钥对象。
        return keyFactory.generatePrivate(keySpec);
    }

2、加密

    /**
     * RSA解密
     *
     * @param data       待解密数据
     * @param privateKey 私钥
     */
    public static String decrypt(String data, String privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        PrivateKey privateKeyP = getPrivateKey(privateKey);
        cipher.init(Cipher.DECRYPT_MODE, privateKeyP);
        byte[] dataBytes = Base64.decodeBase64(data);
        int inputLen = dataBytes.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(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        // 解密后的内容
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

七、RSA签名

1、签名

    /**
     *  RSA签名,签名
     * @param data       待签名数据
     * @param privateKey 私钥
     */
    public static String sign(String data,PrivateKey privateKey) throws Exception {
        //以主编码格式返回密钥,如果此密钥不支持编码,则返回null。
        byte[] keyBytes = privateKey.getEncoded();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
        //根据提供的密钥规范(密钥材料)生成私钥对象。
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        //Signature类用于提供数字签名,用于保证数据的完整性,用非对称密钥中的私钥签名,公钥验签。
        //与 Java Security 中其他基于算法的类一样,Signature 提供了与实现无关的算法,因此,调用方(应用程序代码)
        // 会请求特定的签名算法并将它传回给已被正确初始化的 Signature 对象。如果需要,还可以通过特定的提供程序请求特定的算法
        //getInstance指定签名算法
        Signature signature = Signature.getInstance(MD5_RSA);
        //初始化签署签名的私钥
        signature.initSign(key);
        //根据初始化类型,这可更新要签名或验证的字节
        signature.update(data.getBytes());
        //signature.sign()签署或验证所有更新字节的签名
        return new String(Base64.encodeBase64(signature.sign()));
    }

2、验签

    /**
     * 验签
     *
     * @param srcData   原始字符串
     * @param publicKey 公钥
     * @param sign      签名
     */
    public static boolean verify(String srcData,PublicKey publicKey,String sign) throws Exception {
        byte[] keyBytes = publicKey.getEncoded();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(MD5_RSA);

        signature.initVerify(key);
        signature.update(srcData.getBytes());
        //signature.verify签署或验证所有更新字节的签名
        return signature.verify(Base64.decodeBase64(sign.getBytes()));

    }

八、测试

    // 公钥
    private static String publicKeyStrTestYan = "";
    // 私钥
    private static String privateKeyStrTestYan = "";
    // 加密后串
    private static String publicKeyStrTestYanjie = "";
    @PostMapping("/testRSAYan")
    public SystemResult testRSAYan(@RequestBody String data) {
        try {
            //生成密钥对
//            HashMap<String,String> keyPairMap = RSAUtilYan.getKeyPairMap();
//            String privateKey = keyPairMap.get("privateKey");
//            String publicKey = keyPairMap.get("publicKey");
//            System.out.println("私钥 => " + privateKey + "\n");
//            System.out.println("公钥 =>" + publicKey + "\n");
//            return SystemResult.ok(keyPairMap.toString());


            //RSA加密
//            String encryptData = RSAUtilYan.encrypt(data,publicKeyStrTestYan);
//            System.out.println("加密后内容 => " + encryptData + "\n");
//            return SystemResult.ok(encryptData);
//
//            // RSA解密
//            String decryptData = RSAUtilYan.decrypt(publicKeyStrTestYanjie, privateKeyStrTestYan);
//			  decryptData = java.net.URLDecoder.decode(decryptData, "UTF-8");
			 //转json
//			  params = com.alibaba.fastjson.JSONObject.parseObject(decryptData);
//            System.out.println("解密后内容 => " + decryptData + "\n");
//            return SystemResult.ok(decryptData);

            // RSA签名
            String sign = RSAUtilYan.sign(data, RSAUtilYan.getPrivateKey(privateKeyStrTestYan));
            // RSA验签
            boolean result = RSAUtilYan.verify(data, RSAUtilYan.getPublicKey(publicKeyStrTestYan), sign);
            System.out.println("验签结果 => " + result + "\n");
            return SystemResult.ok();
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("RSA加解密异常");
            return SystemResult.error("RSA加解密异常");
        }
    }

九、前端加解密

跟后端要私钥
拿到后端穿过来的密文之后,直接解密,如果解密之后和预期的数据不一样,要和后端沟通是什么原因
下面展示了一个:后端加密的时候是先将字符串转成json对象 再加密的;所以前端解密之后要再将json对象转化为字符串

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入jsencrypt.js文件 -->
    <script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>
</head>
<body>
   <script>
    //公钥
    var PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3+2kBT+EJq8PqSrleCgsddWtwuIDaNtSwWunuyaRuSGWhBJxFApWXv8xfdchhbw5ti/2z3w5ipAufXJ/5R9FwBGSGEivbpUUCpVuk7iFY8vE+yfZTobEkfJ0vsO9FllG9AofYDAP5dlKYfTnXpNv7HrPrZfleB5HOtXS1OMt02wIDAQAB';
    //私钥
    var PRIVATE_KEY = 'MIICXAIBAAKBgQC3+2kBT+EJq8PqSrleCgsddWtwuIDaNtSwWunuyaRuSGWhBJxFApWXv8xfdchhbw5ti/2z3w5ipAufXJ/5R9FwBGSGEivbpUUCpVuk7iFY8vE+yfZTobEkfJ0vsO9FllG9AofYDAP5dlKYfTnXpNv7HrPrZfleB5HOtXS1OMt02wIDAQABAoGBALb3QIL8hGjQt+JNc7EwvcMLHdEYu5PHiZbkotZFE9BVETSjWCFNI6WpKT8Z7C/xeOC6opB52F2ClMhkHfeTU5SpQx2YoRXjQGxCigTaRvlMo2q8q05sy4cxKpE+7c4yMaZSPldrx5HjLLlJzso7xngtHqnP/wQsbNnARhQ31tIhAkEA58D7SxU0i8UWSR1hPrXC4iPfDXTwtFOVyyHWCCId5fNFH6omlyHzleH4WLSYe/ZBAJRpPUqUeLlSKtkzonIgsQJBAMs693OXOeQpZdWUFlEl0hvcQFclaSID2TPbcL/doMslYd7tegyhBIrQRIzUQooZF5lbcsBLwb1hFPx0N7E6MUsCQH6pIC5W9pL1MkrffchyOoKxrDSElxFXJWURpxJm4wRMQpkdu12aNrDSAZMpkLUfT0Nr2WCgJCkez+OPNgMwcOECQGlMMBHv9MrGuECk7bs1wVs2DxAYDhTVsaAwvoZqqnkW8VKz8FzCwLu7lQjyoVc0EQogW6BOoB8jQeBbxs9Iu2kCQAFzAhRnjj1Rn2uvMqRCva+ez3RPaLHK4BzC5UdgF/qTu58+K29UqKSLenMB8ZZ1VQIJ83VnKSiIyHqeHBjl6LE=';
    //使用公钥加密
    var encrypt = new JSEncrypt();
    encrypt.setPublicKey('-----BEGIN PUBLIC KEY-----' + PUBLIC_KEY + '-----END PUBLIC KEY-----');
    var encrypted = encrypt.encrypt("张三");
    console.log('加密后数据:%o', encrypted);
    
    //使用私钥解密
    var decrypt = new JSEncrypt();
    decrypt.setPrivateKey('-----BEGIN RSA PRIVATE KEY-----'+PRIVATE_KEY+'-----END RSA PRIVATE KEY-----');
    var uncrypted = decrypt.decrypt(encrypted); 
    console.log('解密后数据:%o', uncrypted); // 张三


    // 下面这段密文就是后端传过来的json
    var uncrypted1 = decrypt.decrypt("evHC57KB+RRQdSZmFWoAR7KcViMW+P0GGjhIvOociFS7QWJwE63A+8XqGJuVs+WOVNO/NTuYEd78QJu8gHcVJvt3QumYqt7EPVNekQ2OTRuyi+bTSF8Xy9tj+GXs8wF+3jbJYDdOwgEciXVFxbWEXwH6/pu44FIQEjL376RetZg=");
    console.log('解密后数据:%o', JSON.parse(uncrypted1) ); // 安杰
    // 如果没转成字符串的话
    console.log('解密后数据:%o', uncrypted1); // \\u5b89\\u6770\
    </script> 
</body>
</html>

或者使用:

//安装
npm install jsencrypt
//引入
import JSEncrypt from 'jsencrypt'
//rsa加密
const encryptor = new JSEncrypt()                      // 创建加密对象实例
const pubKey = ''
encryptor.setPublicKey(pubKey)						   //设置公钥
const rsaPassWord = encryptor.encrypt('要加密的内容')   // 对内容进行加密

十、遇到的问题:RSA解密中文乱码解决,前端加密后端解密;

解决:
1、如果后端加密(需加密前对字符串进行操作):

data = java.net.URLEncoder.encode(data, "UTF-8");

如果前端加密:

var name = '中文测试'
var nameen = encodeURIComponent(name);
var name = encrypt.encrypt(nameen);
先用encodeURIComponent() 加密,再用rsa加密

2、后端解密(解密后对接过字符串进行操作)

decryptData = java.net.URLDecoder.decode(decryptData, "UTF-8");

前端解密

dncodeURIComponent()
  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
RSA加密是一种非对称加密算法,它需要使用公钥进行加密,私钥进行解密。Java实现RSA加密可以使用Java自带的加密javax.crypto。 以下是一个简单的RSA加密示例: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import javax.crypto.Cipher; public class RSAEncryption { public static void main(String[] args) throws Exception { // 生成密钥对 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); // 加密字符串 String message = "Hello, World!"; byte[] encryptedMessage = encrypt(message, publicKey); System.out.println("Encrypted message: " + new String(encryptedMessage)); // 解密字符串 String decryptedMessage = decrypt(encryptedMessage, privateKey); System.out.println("Decrypted message: " + decryptedMessage); } public static byte[] encrypt(String message, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(message.getBytes()); } public static String decrypt(byte[] encryptedMessage, PrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedMessage = cipher.doFinal(encryptedMessage); return new String(decryptedMessage); } } ``` 在上面的示例中,我们使用KeyPairGenerator类生成2048位的RSA密钥对,然后使用公钥加密一个字符串,再使用私钥解密该字符串。在加密和解密过程中,我们使用了Cipher类来进行加密和解密操作。在初始化Cipher实例时,我们需要指定加密/解密模式和密钥。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值