RSA加密---java和node兼容版(可直接复制使用)

时间:2024-05-03 10:15:59

目录

背景

实现

一、node代码

1、引入依赖

2、生成公钥和私钥

3、生成工具类

二、java代码

背景

本来项目的后端是node,里面登录接口用的是后端生成RSA公钥和私钥,公钥给前端网页用来加密,node后端解密,一切很和谐,突然要我上一个Android应用,结果java和node两边就是无法通配。

原因:默认的RSA加解密格式不一样,node默认的 'pkcs1_oaep', 而java中默认的是pkcs8

解决方法:两边都采用同一种模式就好了,这里我修改node为pkcs8.

实现

RSA测试网站https://livequeen.top

一、node代码

1、引入依赖

npm install node-rsa

2、生成公钥和私钥

const NodeRSA = require('node-rsa')

// 生成密文(和java通用版本)
var key = new NodeRSA({b: 1024})
var privateKey = key.exportKey('pkcs8-private')
var publicKey = key.exportKey('pkcs8-public-pem')

console.log(privateKey)
console.log(publicKey)

效果如下:

 

3、生成工具类

const NodeRSA = require('node-rsa')

var publicKey = '-----BEGIN PUBLIC KEY-----\n' +
  'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9WbdF8v9qt9u1nEbUnWLlDa/e\n' +
  '3gc67MhCgzRlwq+s7xVP6usKJbqB7FUIM0k1e7nx1eMgmpkL4y4sLjuWzms6OXo5\n' +
  'OFdb64RbdTKfo91bBVW9kWov8SiLL3/Y5NlEtG+uG0DWZSbBc73vPQlvUT/6Kuy9\n' +
  '7qFpCjXmyIDbHLUKQQIDAQAB\n' +
  '-----END PUBLIC KEY-----'

var privateKey = '-----BEGIN PRIVATE KEY-----\n' +
  'MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAL1Zt0Xy/2q327Wc\n' +
  'RtSdYuUNr97eBzrsyEKDNGXCr6zvFU/q6woluoHsVQgzSTV7ufHV4yCamQvjLiwu\n' +
  'O5bOazo5ejk4V1vrhFt1Mp+j3VsFVb2Rai/xKIsvf9jk2US0b64bQNZlJsFzve89\n' +
  'CW9RP/oq7L3uoWkKNebIgNsctQpBAgMBAAECgYB+KRK15oxL/KjFPpTrANptp0rx\n' +
  'AZprpmxf9K+qxabrYHkgwHNOVYkJHAAj8JfsrL1d5pbomFk01G9lPICzoGFMSaNA\n' +
  'kFlC15Td6/ERbDrIXjDjcggL8FfkWm1mb3UEZJsN/dLCclMDCEYnLMgfBKrj651+\n' +
  'Y9wvlqn0cltrIThbSQJBAO+U10ZHVnzO1A+FFN5NK7yoqGn/mOvwPIObEyASGznK\n' +
  'X0EpDcamt5giH7GrTaId24vILX1MpI+YamU3xzp3w/8CQQDKU6KUALBuKOLQrYW4\n' +
  '4wtdBiOSHsYbcMXJoXC+NAhwb6kz1aCnGRfxtzpVZmMtaoIzxuzmqdya09OTazyX\n' +
  'KjG/AkEAgqdM7wqgY9f3Va9hvgmfvHbNwWCeaKzOk4bSWz8EkfOHFuXomVj57oFN\n' +
  'f3rID4zw2b4E8LwHUjfwbdqJT51YyQJBAKsP/1tHIeRhqTNqIq9pN0hVUmnOnwzA\n' +
  'UlnhpyMJd0EpB1QOAKCG9NmnYyilQqE5dhA01kNHxn8ZLb9sYXQldp0CQQC1DOqN\n' +
  '5N8xx/k65MFgxIM/asyRhe6YCG7SCIAdyAau0S7v+Qf7R6tX4jWHWxhQfRl2dHKx\n' +
  'a3JZu+LOb8XwDxNQ\n' +
  '-----END PRIVATE KEY-----'

var key = new NodeRSA()
key.importKey(privateKey, 'pkcs8-private')
key.importKey(publicKey, 'pkcs8-public-pem')

// 加密
function encryption (data) {
  try {
    const dataEncry = key.encrypt(data, 'base64')
    // 返回结果
    return JSON.stringify({
      code: 200,
      data: dataEncry
    })
  } catch (e) {
    // 返回错误
    return JSON.stringify({
      code: 500,
      data: e
    })
  }
}

// 解密
function decryption (data) {
  try {
    const dataDecry = key.decrypt(data, 'utf8')
    // 返回结果
    return JSON.stringify({
      code: 200,
      data: dataDecry
    })
  } catch (e) {
    // 返回错误
    return JSON.stringify({
      code: 500,
      data: e
    })
  }
}

module.exports = {
  encryption,
  decryption
}

二、java代码

1、直接上工具类

注意:java代码中的公钥不需要开头和结尾的【-----BEGIN PUBLIC KEY-----】这个,只需要保留中间的密钥就好,且不要留有换行符【\n】。

import android.os.Build;

import androidx.annotation.RequiresApi;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * Rsa加解密工具(node后端通用版本)
 */
public class RsaUtil {

    /**
     * Rsa加密
     * @param data 需要加密的数据
     * @return 返回密文
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String encrypt(String data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        byte[] dataBytes = data.getBytes();
        if (dataBytes.length > 214) throw new RuntimeException("不能一次性加密超过214字节的数据");
        String pubKey =
                "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9WbdF8v9qt9u1nEbUnWLlDa/e" +
                "3gc67MhCgzRlwq+s7xVP6usKJbqB7FUIM0k1e7nx1eMgmpkL4y4sLjuWzms6OXo5" +
                "OFdb64RbdTKfo91bBVW9kWov8SiLL3/Y5NlEtG+uG0DWZSbBc73vPQlvUT/6Kuy9" +
                "7qFpCjXmyIDbHLUKQQIDAQAB";
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] keyBytes = decoder.decode(pubKey);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PublicKey pk = kf.generatePublic(spec);

        byte[] cipherText;
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pk);
        cipherText = cipher.doFinal(dataBytes);
        Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(cipherText);
    }

    /**
     * Rsa解密
     * @param data 需要解密的数据
     * @return 明文
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String decrypt(String data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
        String privateKey =
                "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAL1Zt0Xy/2q327Wc" +
                        "RtSdYuUNr97eBzrsyEKDNGXCr6zvFU/q6woluoHsVQgzSTV7ufHV4yCamQvjLiwu" +
                        "O5bOazo5ejk4V1vrhFt1Mp+j3VsFVb2Rai/xKIsvf9jk2US0b64bQNZlJsFzve89" +
                        "CW9RP/oq7L3uoWkKNebIgNsctQpBAgMBAAECgYB+KRK15oxL/KjFPpTrANptp0rx" +
                        "AZprpmxf9K+qxabrYHkgwHNOVYkJHAAj8JfsrL1d5pbomFk01G9lPICzoGFMSaNA" +
                        "kFlC15Td6/ERbDrIXjDjcggL8FfkWm1mb3UEZJsN/dLCclMDCEYnLMgfBKrj651+" +
                        "Y9wvlqn0cltrIThbSQJBAO+U10ZHVnzO1A+FFN5NK7yoqGn/mOvwPIObEyASGznK" +
                        "X0EpDcamt5giH7GrTaId24vILX1MpI+YamU3xzp3w/8CQQDKU6KUALBuKOLQrYW4" +
                        "4wtdBiOSHsYbcMXJoXC+NAhwb6kz1aCnGRfxtzpVZmMtaoIzxuzmqdya09OTazyX" +
                        "KjG/AkEAgqdM7wqgY9f3Va9hvgmfvHbNwWCeaKzOk4bSWz8EkfOHFuXomVj57oFN" +
                        "f3rID4zw2b4E8LwHUjfwbdqJT51YyQJBAKsP/1tHIeRhqTNqIq9pN0hVUmnOnwzA" +
                        "UlnhpyMJd0EpB1QOAKCG9NmnYyilQqE5dhA01kNHxn8ZLb9sYXQldp0CQQC1DOqN" +
                        "5N8xx/k65MFgxIM/asyRhe6YCG7SCIAdyAau0S7v+Qf7R6tX4jWHWxhQfRl2dHKx" +
                        "a3JZu+LOb8XwDxNQ";
        //64位解码加密后的字符串
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] inputByte = decoder.decode(data.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = decoder.decode(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        return new String(cipher.doFinal(inputByte));
    }
}