javaweb项目使用RSA算法

1. RSA算法介绍

RSA算法是一种非对称算法,即是加密的密码和解密的密码是不一致的。因此对RSA的加密和加密的密码分为公钥和私钥。根据RSA的算法介绍,只要密钥的长度足够长,现在没有任何方法可以破解。而且这个算法的专利已经在2000921日失效,因此应该是可以任意使用的。

密钥获取:

选用PKCS#8生成密钥,选PKCS#1可能会导致解密失败

http://web.chacuo.net/netrsakeypair

1. javaweb使用RSA

1.1. 前端加密

要在前端加密密码,就要使用到jsencryptjs

1.1.1. jsencrypt下载

官网:http://travistidwell.com/jsencrypt/

 

github: https://github.com/travist/jsencrypt/releases

 

bin目录下面可以找到相关js

 

1.1.2. 代码示例

 1 //RSA加密
 2 function encryptRequest(reqUrl, data) {
 3     var publicKey = "****";
 4     var encrypt = new JSEncrypt();
 5     encrypt.setPublicKey(publicKey);
 6 // ajax请求发送的数据对象 
 7 var password = ‘xxxx’;
 8     // 将data数组赋给ajax对象 
 9 password  = encrypt.encrypt(password ); 
10  $.ajax({
11         type: 'post',
12         url: reqUrl,
13         data: password,
14         async:false, 
15         success: function(data){  
16                 return false;
17         }
18         error : function(XMLResponse) {
19             var msg = XMLResponse.responseText;
20             console.log(msg);
21         }
22     });
23 }

1.1. 后端解密

1.1.1. 相关工具类准备

1.1.1.1. Base64Utils 

Base64工具类,可以让rsa编码的乱码变成一串字符序列

  1 package cn.sinobest.common.misc;
  2  
  3 import java.io.ByteArrayInputStream;
  4 import java.io.ByteArrayOutputStream;
  5 import java.io.File;
  6 import java.io.FileInputStream;
  7 import java.io.FileOutputStream;
  8 import java.io.InputStream;
  9 import java.io.OutputStream;
 10 
 11 import org.apache.commons.codec.binary.Base64;
 12  
 13 
 14 /** */
 15 /**
 16  * <p>
 17  * BASE64编码解码工具包
 18  * </p>
 19  * <p>
 20  * 依赖javabase64-1.3.1.jar
 21  * </p>
 22  *  
 23  * @date 2012-5-19
 24  * @version 1.0
 25  */
 26 public class Base64Utils {
 27 
 28     /** */
 29     /**
 30      * 文件读取缓冲区大小
 31      */
 32     private static final int CACHE_SIZE = 1024;
 33 
 34     /** */
 35     /**
 36      * <p>
 37      * BASE64字符串解码为二进制数据
 38      * </p>
 39      * 
 40      * @param base64
 41      * @return
 42      * @throws Exception
 43      */
 44     public static byte[] decode(String base64str) throws Exception {
 45         Base64 base64 = new Base64();
 46         return base64.decode(base64str.getBytes());
 47     }
 48 
 49     /** */
 50     /**
 51      * <p>
 52      * 二进制数据编码为BASE64字符串
 53      * </p>
 54      * 
 55      * @param bytes
 56      * @return
 57      * @throws Exception
 58      */
 59     public static String encode(byte[] bytes) throws Exception {
 60         Base64 base64 = new Base64();
 61         return new String(base64.encode(bytes));
 62     }
 63 
 64     /** */
 65     /**
 66      * <p>
 67      * 将文件编码为BASE64字符串
 68      * </p>
 69      * <p>
 70      * 大文件慎用,可能会导致内存溢出
 71      * </p>
 72      * 
 73      * @param filePath
 74      *            文件绝对路径
 75      * @return
 76      * @throws Exception
 77      */
 78     public static String encodeFile(String filePath) throws Exception {
 79         byte[] bytes = fileToByte(filePath);
 80         return encode(bytes);
 81     }
 82 
 83     /** */
 84     /**
 85      * <p>
 86      * BASE64字符串转回文件
 87      * </p>
 88      * 
 89      * @param filePath
 90      *            文件绝对路径
 91      * @param base64
 92      *            编码字符串
 93      * @throws Exception
 94      */
 95     public static void decodeToFile(String filePath, String base64) throws Exception {
 96         byte[] bytes = decode(base64);
 97         byteArrayToFile(bytes, filePath);
 98     }
 99 
100     /** */
101     /**
102      * <p>
103      * 文件转换为二进制数组
104      * </p>
105      * 
106      * @param filePath
107      *            文件路径
108      * @return
109      * @throws Exception
110      */
111     public static byte[] fileToByte(String filePath) throws Exception {
112         byte[] data = new byte[0];
113         File file = new File(filePath);
114         if (file.exists()) {
115             FileInputStream in = new FileInputStream(file);
116             ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
117             byte[] cache = new byte[CACHE_SIZE];
118             int nRead = 0;
119             while ((nRead = in.read(cache)) != -1) {
120                 out.write(cache, 0, nRead);
121                 out.flush();
122             }
123             out.close();
124             in.close();
125             data = out.toByteArray();
126         }
127         return data;
128     }
129 
130     /** */
131     /**
132      * <p>
133      * 二进制数据写文件
134      * </p>
135      * 
136      * @param bytes
137      *            二进制数据
138      * @param filePath
139      *            文件生成目录
140      */
141     public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
142         InputStream in = new ByteArrayInputStream(bytes);
143         File destFile = new File(filePath);
144         if (!destFile.getParentFile().exists()) {
145             destFile.getParentFile().mkdirs();
146         }
147         destFile.createNewFile();
148         OutputStream out = new FileOutputStream(destFile);
149         byte[] cache = new byte[CACHE_SIZE];
150         int nRead = 0;
151         while ((nRead = in.read(cache)) != -1) {
152             out.write(cache, 0, nRead);
153             out.flush();
154         }
155         out.close();
156         in.close();
157     }
158 
159 }

1.1.1.1. RsaUtil

RsaUtil工具类,可以调用里面的方法,产生公钥私钥对,和采用公钥加密,私钥加密等

package cn.sinobest.common.misc;
 
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
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;

import javax.crypto.Cipher;

/** */
/**
 * <p>
 * RSA公钥/私钥/签名工具包
 * </p>
 * <p>
 * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)
 * </p>
 * <p>
 * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
 * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>
 * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
 * </p>
 *   
 * @version 1.0
 */
public class RSAUtils {

    /** */
    /**
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";

    /** */
    /**
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /** */
    /**
     * 获取公钥的key
     */
    private static final String PUBLIC_KEY = "RSAPublicKey";

    /** */
    /**
     * 获取私钥的key
     */
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /** */
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /** */
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /** */
    /**
     * <p>
     * 生成密钥对(公钥和私钥)
     * </p>
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /** */
    /**
     * <p>
     * 用私钥对信息生成数字签名
     * </p>
     * 
     * @param data
     *            已加密数据
     * @param privateKey
     *            私钥(BASE64编码)
     * 
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64Utils.encode(signature.sign());
    }

    /** */
    /**
     * <p>
     * 校验数字签名
     * </p>
     * 
     * @param data
     *            已加密数据
     * @param publicKey
     *            公钥(BASE64编码)
     * @param sign
     *            数字签名
     * 
     * @return
     * @throws Exception
     * 
     */
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        signature.update(data);
        return signature.verify(Base64Utils.decode(sign));
    }

    /** */
    /**
     * <P>
     * 私钥解密
     * </p>
     * 
     * @param encryptedData
     *            已加密数据
     * @param privateKey
     *            私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /** */
    /**
     * <p>
     * 公钥解密
     * </p>
     * 
     * @param encryptedData
     *            已加密数据
     * @param publicKey
     *            公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /** */
    /**
     * <p>
     * 公钥加密
     * </p>
     * 
     * @param data
     *            源数据
     * @param publicKey
     *            公钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        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();
        return encryptedData;
    }

    /** */
    /**
     * <p>
     * 私钥加密
     * </p>
     * 
     * @param data
     *            源数据
     * @param privateKey
     *            私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        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();
        return encryptedData;
    }

    /** */
    /**
     * <p>
     * 获取私钥
     * </p>
     * 
     * @param keyMap
     *            密钥对
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return Base64Utils.encode(key.getEncoded());
    }

    /** */
    /**
     * <p>
     * 获取公钥
     * </p>
     * 
     * @param keyMap
     *            密钥对
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return Base64Utils.encode(key.getEncoded());
    }

    /**
     * java端公钥加密
     */
    public static String encryptedDataOnJava(String data, String PUBLICKEY) {
        try {
            data = Base64Utils.encode(encryptByPublicKey(data.getBytes(), PUBLICKEY));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return data;
    }

    /**
     * java端私钥解密
     */
    public static String decryptDataOnJava(String data, String PRIVATEKEY) {
        String temp = "";
        try {
            byte[] rs = Base64Utils.decode(data);
            temp = new String(RSAUtils.decryptByPrivateKey(rs, PRIVATEKEY),"UTF-8"); //以utf-8的方式生成字符串

        } catch (Exception e) {
            e.printStackTrace();
        }
        return temp;
    }

}

1.1.1. 后端实例

1 public class TestAction {
2     private static final String PrivateKey = "***";
3     
4     public void test(String password) {
5         password = RSAUtils.decryptDataOnJava(password, PrivateKey);
6         System.out.println("密码是:"+password);
7     }
8 }

该文档参考以下两篇文章:

https://www.cnblogs.com/Leo_wl/p/5763243.html
https://www.cnblogs.com/nanyangke-cjz/p/5898361.html

原文地址:https://www.cnblogs.com/bestlmc/p/11669544.html