JS加密、JAVA解密,有两条路:

  1. 根据jsencrypt步骤,使用bash命令生成公钥和私钥;
  2. 使用Java 代码生成公钥和私钥;

先看下第二种方式如何实现:

  • 项目中运行RasUtils工具类,生成公钥和私钥,并进行下测试
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.io.IOException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSAUtils {

    //生成秘钥对
    public static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }

    //获取公钥(Base64编码)
    static String getPublicKey(KeyPair keyPair) {
        PublicKey publicKey = keyPair.getPublic();
        byte[] bytes = publicKey.getEncoded();
        return new BASE64Encoder().encode((bytes));
    }

    //获取私钥(Base64编码)
    static String getPrivateKey(KeyPair keyPair) {
        PrivateKey privateKey = keyPair.getPrivate();
        byte[] bytes = privateKey.getEncoded();
        return new BASE64Encoder().encode((bytes));
    }

    //将Base64编码后的公钥转换成PublicKey对象
    static PublicKey string2PublicKey(String pubStr) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer((pubStr));
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }

    //将Base64编码后的私钥转换成PrivateKey对象
    static PrivateKey string2PrivateKey(String priStr) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer((priStr));
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }

    //公钥加密
    public static String publicEncrypt(String content, String publicKeyStr) throws Exception {
        PublicKey publicKey = RSAUtils.string2PublicKey(publicKeyStr);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] bytes = cipher.doFinal(content.getBytes());
        return new BASE64Encoder().encode(bytes);
    }

    //私钥解密
    public static byte[] privateDecrypt(String content, String privateKeyStr) throws Exception {
        PrivateKey privateKey = RSAUtils.string2PrivateKey(privateKeyStr);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] bytes = cipher.doFinal(new BASE64Decoder().decodeBuffer(content));
        return bytes;
    }


    public static void main(String[] args) {
        try {
            //===============生成公钥和私钥,公钥传给客户端,私钥服务端保留==================
            KeyPair keyPair = RSAUtils.getKeyPair();
            String publicKeyStr = RSAUtils.getPublicKey(keyPair);
            String privateKeyStr = RSAUtils.getPrivateKey(keyPair);
            System.out.println("RSA公钥Base64编码:" + publicKeyStr);
            System.out.println("RSA私钥Base64编码:" + privateKeyStr);

            //=================开始加密=================
            String message = "panda";
            //用公钥加密
            String publicEncrypt = RSAUtils.publicEncrypt(message, publicKeyStr);
            System.out.println("公钥加密并Base64编码的结果:" + publicEncrypt);


            //===================开始解密================
            //用私钥解密
            byte[] privateDecrypt = RSAUtils.privateDecrypt(publicEncrypt, privateKeyStr);
            //解密后的明文
            System.out.println("解密后的明文: " + new String(privateDecrypt));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行这个工具类可以看到对字符串加密解密成功;从输出中截取公钥和私钥;
公钥存储在JS端,供JS加密使用;
私钥保存在Java后端,供解密用;

  • 编写HTML页面进行字符串加密
<!doctype html>
<html>
  <head>
    <title>JavaScript RSA Encryption</title>
    <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
    <script src="去github中下载jsencrypt.js"></script>
    <script type="text/javascript">

      // Call this code when the page is done loading.
      $(function() {

        // Run a quick encryption/decryption when they click.
        $('#testme').click(function() {

          // Encrypt with the public key...
          var encrypt = new JSEncrypt();
          encrypt.setPublicKey('刚才Java生成的公钥');
          var encrypted = encrypt.encrypt('要加密的内容');
          console.log(encrypted);
        });
      });
    </script>
  </head>
  <body>
    
  </body>
</html>

页面加载完毕,就会在控制台输出加密后的字符串;你可以使用该加密串返回到java中,进行解密来验证.

到此为止,基本可以实现前端RSA加密,后端RSA解密了;

再来看下实现方法一

  1. 我们按照jsencrypt github中的步骤,一步一步使用bash生成公钥和私钥
    1.1 openssl genrsa -out rsa_1024_priv.pem 1024
    1.2 cat rsa_1024_priv.pem #输出私钥
    1.3 openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem
    1.4 cat rsa_1024_pub.pem #输出公钥
    1.5 使用github中下一步的html进行验证,也可以成功(代码略,大家可自行去github中查看)
  2. 在ResUtils中使用刚才生成的公钥进行解密,很大几率会抛出异常

algid parse error, not a sequence

  • 原因:私钥在使用前为pkcs1格式,而java在不引用第三方包的情况下无法直接使用pkcs1格式的秘钥,需要将其转化为pkcs8编码
  • 解决方案:

openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -out rsa_private_key_01.pem -nocrypt

使用rsa_private_key_01.pem中的秘钥即可