Java的RSA非对称加密,与web,移动端配合

之前改造老系统,要求用RSA非对称加密,前前后后看了很多资料,现在总结梳理一下。

加密过程主要就是:生成一对公钥和私钥,公钥加密,私钥解密。

需要注意jdk1.8有base64的工具类,而1.8之前可以用sun.misc.BASE64Decoder/Encoder来替代。

1、Java后端代码

package rsa;

import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;
import java.util.*;

/**
 * @Author: dyf
 * @Date: 2019/10/17 10:04
 * @Description:
 */
public class RSAUtil {
    private static Map<Integer, String> keyMap = new HashMap<Integer, String>();  //用于封装随机产生的公钥与私钥

    //存取外部,私钥
    private RSAPrivateKey privateKey;
    //存取外部,公钥
    private RSAPublicKey publicKey;

    public static void main(String[] args) throws Exception {
        //生成公钥和私钥
        genKeyPair();
        //加密字符串
        String message = "Pass@2018";
        System.out.println("随机生成的公钥为:" + keyMap.get(0));
        System.out.println("随机生成的私钥为:" + keyMap.get(1));
        String messageEncode = encrypt(message,keyMap.get(0));
        System.out.println(message + "\t加密后的字符串为:" + messageEncode);
        String messageDecode = decrypt(messageEncode,keyMap.get(1));
        System.out.println("还原后的字符串为:" + messageDecode);

        String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmWaD9O2JBxswtqDRezaDfIqB9kESDNQR6aamftAhRaP4P50qhB8YIy+Scbl1CiFWi9XHlbocDF+5E37eN7RmDTXBP6k2iKm7nXDllw/7++ET5MKs8tqMHuvTcq7eUgnozrG+mY9tJvbmZgQcfiFSLqyH6lqWiPLW8APd3pzicKwIDAQAB";
        String privateKetStr = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKZZoP07YkHGzC2oNF7NoN8ioH2QRIM1BHppqZ+0CFFo/g/nSqEHxgjL5JxuXUKIVaL1ceVuhwMX7kTft43tGYNNcE/qTaIqbudcOWXD/v74RPkwqzy2owe69Nyrt5SCejOsb6Zj20m9uZmBBx+IVIurIfqWpaI8tbwA93enOJwrAgMBAAECgYAvrRp92Wo0zeQw5bd0wFxt9z+mHRX1wNkyuFvcIL4NjxjZuAFkm5S/aqhvyRXDfs2EcfIdvorFcTNh2/iAncakq9xoLyIKipF2KP4ZMl8YAMINdXPWOWrg7NP61VzJ30FjMfUxhEiRnJzEEXyl1m4mQdEhnV3wA9EZTYXC++ItSQJBANGL0S8tkJY01KCcwxb2kBszcokZiWfMP6r21JxLgqBLBbpzqrJDpWo5AyKA0PBVBLLAGNGU4qEJfUGsPt1howUCQQDLOlh+R+JpxXpSxXrirJDwXepfpJ9S6arG6b3z7FwUwl7JwkGlivfRLGBB3bGmmGlvl8sxW0810bXmb7palMlvAkEAxe++r0PpOhm5Z+XsWrqZMTiNzney1buXwJTcDK8/Os7jIFa2PSGtFQO5tFPeCcclYvwV9ZMf6GIgUXK1B0V9SQJAWYMvax+6aCAlCsQUpjaf+F9FVi8qRdjJ8acOlZuryzD5kyBOzd1x3d4P37MIBnrnJdHUG78+GlRuLDtV94PFXQJBAMEAxX/PR7EC93kG4ww1FgBSI1JF/pD1y/nlKoQxfbKqsswG0zMW/sRt6eGL4tgLW8bdpK6nGUQhTZmdqmpDE5k=";
        String messageEn = encrypt(message, publicKeyStr);
        System.out.println(message + "\t加密后的字符串为:" + messageEn);
        String messageDe = decrypt(messageEn, privateKetStr);
        System.out.println("还原后的字符串为:" + messageDe);

        //解密来自前端的密码
        String pswFromWeb = "EXpVZkMGQ4slQKOM/53+WQPGKKMF9Yqc2JbAUgs8U+4LHgwKFikhW5M+m5SzFvTR3HoRJ9PZRKYbBc1D8QdY39by0YbQD3ktntzjJYzULsvVDfD+PQVU73hqXlHFt0cIp1nPCaplN0soQkpbQ8N1AZLdtRFpT5OjWyabe/TNbgA=";
        System.out.println("解密前端密码为:" + decrypt(pswFromWeb, privateKetStr));

       
        //IOS端可以根据我们提供的公钥字符串来加密,然后后端解密;
        //也可以根据IOS端提供的私钥的.pem文件来解密
        String basePath = RSAUtil.class.getResource("/").getPath();
        //String publicKeyPath = basePath + "/rsa/rsa_public_key.pem";        // replace your public key path here
        String privateKeyPath = basePath + "/rsa/pkcs8_private_key.pem";     // replace your private path here
        String rsaBase46StringFromIOS = "h9Sunsga1YtCBCRmLoA1WJ/SZOtDJuwfTTzIrZx1qx977Y2UD7OKU4Hu9h1gzgNtGzUWP1enTdUERPbCCAeQ1w+JrB4/R/yfLTIeO/8jXoQHfv1ZIDcVkQfJRo+AZo5N/eHES7bBcYvXglKSp9C/urYtrTL/WepOXGu8Dy85sH0=";
        String privateKeyStrIOS = getKeyFromFile(privateKeyPath);
        System.out.println(RSAUtil.decryptIOS(rsaBase46StringFromIOS, privateKeyStrIOS));
    }

    /**
     * 随机生成密钥对
     * @throws NoSuchAlgorithmException
     */
    public static void genKeyPair() throws NoSuchAlgorithmException {
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器,密钥大小为96-1024位
        keyPairGen.initialize(1024,new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
        String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        // 得到私钥字符串
        String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        // 将公钥和私钥保存到Map
        keyMap.put(0,publicKeyString);  //0表示公钥
        keyMap.put(1,privateKeyString);  //1表示私钥
    }
    /**
     * RSA公钥加密
     *
     * @param encodeStr
     *            加密字符串
     * @param publicKeyStr
     *            公钥
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encrypt( String encodeStr, String publicKeyStr ) throws Exception{
        //base64编码的公钥
        byte[] decoded = Base64.getDecoder().decode(publicKeyStr);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(encodeStr.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * RSA私钥解密
     *
     * @param decodeStr
     *            加密字符串
     * @param privateKeyStr
     *            私钥
     * @return 铭文
     * @throws Exception
     *             解密过程中的异常信息
     */
    public static String decrypt(String decodeStr, String privateKeyStr) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.getDecoder().decode(decodeStr.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.getDecoder().decode(privateKeyStr);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    public static String decryptIOS(String decodeStr, String privateKeyStr) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.getDecoder().decode(decodeStr.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = new BASE64Decoder().decodeBuffer(privateKeyStr);//不知道为什么,这里只有用sum.misc的base64解码,不会报错
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    public static String getKeyFromFile(String filePath) throws Exception {
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        String line = null;
        List<String> list = new ArrayList<String>();
        while ((line = bufferedReader.readLine()) != null){
            list.add(line);
        }

        // remove the firt line and last line
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 1; i < list.size() - 1; i++) {
            stringBuilder.append(list.get(i)).append("\r");
        }

        String key = stringBuilder.toString();
        return key;
    }

    /**
     * 从字符串中加载公钥
     * @param publicKeyStr 公钥数据字符串
     * @throws Exception 加载公钥时产生的异常
     */
    public void loadPublicKey(String publicKeyStr) throws Exception{
        byte[] buffer= Base64.getDecoder().decode(publicKeyStr);
        KeyFactory keyFactory= KeyFactory.getInstance("RSA");
        X509EncodedKeySpec keySpec= new X509EncodedKeySpec(buffer);
        this.publicKey= (RSAPublicKey) keyFactory.generatePublic(keySpec);
    }


    public void loadPrivateKey(String privateKeyStr) throws Exception{
        byte[] buffer= Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec keySpec= new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory= KeyFactory.getInstance("RSA");
        this.privateKey= (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    }

    /**
     * 字节数据转字符串专用集合
     */
    private static final char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * 字节数据转十六进制字符串
     * @param data 输入数据
     * @return 十六进制内容
     */
    public static String byteArrayToString(byte[] data){
        StringBuilder stringBuilder= new StringBuilder();
        for (int i=0; i<data.length; i++){
            //取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
            stringBuilder.append(HEX_CHAR[(data[i] & 0xf0)>>> 4]);
            //取出字节的低四位 作为索引得到相应的十六进制标识符
            stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
            if (i<data.length-1){
                stringBuilder.append(' ');
            }
        }
        return stringBuilder.toString();
    }


    /**
    * 根据指定私钥对数据进行签名(默认签名算法为"SHA1withRSA")
    *
    * @param data 要签名的数据
    * @param priKey 私钥
    * @return
    */
    public static byte[] signData(byte[] data, PrivateKey priKey) {
        return signData(data, priKey, "SHA1withRSA");
    }

    /**
     * 根据指定私钥和算法对数据进行签名
     *
     * @param data 要签名的数据
     * @param priKey 私钥
     * @param algorithm 签名算法
     * @return
     */
    public static byte[] signData(byte[] data, PrivateKey priKey,
                                  String algorithm) {
        try {
            Signature signature = Signature.getInstance(algorithm);
            signature.initSign(priKey);
            signature.update(data);
            return signature.sign();
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 用指定的公钥进行签名验证(默认签名算法为"SHA1withRSA")
     *
     * @param data 数据
     * @param sign 签名结果
     * @param pubKey 公钥
     * @return
     */
    public static boolean verifySign(byte[] data, byte[] sign, PublicKey pubKey) {
        return verifySign(data, sign, pubKey, "SHA1withRSA");
    }

    /**
     *
     * @param data  数据
     * @param sign 签名结果
     * @param pubKey 公钥
     * @param algorithm 签名算法
     * @return
     */
    public static boolean verifySign(byte[] data, byte[] sign, PublicKey pubKey, String algorithm) {
        try {
            Signature signature = Signature.getInstance(algorithm);
            signature.initVerify(pubKey);
            signature.update(data);
            return signature.verify(sign);
        } catch (Exception ex) {
            return false;
        }
    }
}

2、前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>RSA加密前端代码</title>
    <script src="jsencrypt.js" type="text/javascript"></script>
    <script>
//        var encrypt = new JSEncrypt();
//        encrypt.setPublicKey($('#pubkey').val()); //设置公钥
//        var encrypted = encrypt.encrypt($('#input').val()); //加密
//        console.log(encrypted);

//        // Decrypt with the private key...
//        var decrypt = new JSEncrypt();
//        decrypt.setPrivateKey($('#privkey').val()); //设置私钥
//        var uncrypted = decrypt.decrypt(encrypted); //解密
        var encrypt = new JSEncrypt();
        var publicKey='MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmWaD9O2JBxswtqDRezaDfIqB9kESDNQR6aamftAhRaP4P50qhB8YIy+Scbl1CiFWi9XHlbocDF+5E37eN7RmDTXBP6k2iKm7nXDllw/7++ET5MKs8tqMHuvTcq7eUgnozrG+mY9tJvbmZgQcfiFSLqyH6lqWiPLW8APd3pzicKwIDAQAB';
        encrypt.setPublicKey(publicKey);
        console.log(encrypt.encrypt('Pass@2018'));


    </script>
</head>
<body>

</body>
</html>

附上jsencrypt.js的下载地址:

http://travistidwell.com/jsencrypt/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值