目录
背景
本来项目的后端是node,里面登录接口用的是后端生成RSA公钥和私钥,公钥给前端网页用来加密,node后端解密,一切很和谐,突然要我上一个Android应用,结果java和node两边就是无法通配。
原因 :默认的RSA加解密格式不一样,node默认的 'pkcs1_oaep ', 而java中默认的是pkcs8 。
解决方法:两边都采用同一种模式就好了,这里我修改node为pkcs8.
实现
一、node代码
1、引入依赖
npm install node-rsa
2、生成公钥和私钥
javascript
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、生成工具类
javascript
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】。
java
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));
}
}