数据安全是非常重要的,如用户相关信息、订单相关信息等。web应用程序可通过F12查看服务器API返回的信息。那么极容易造成信息泄露。
针对上面的问题。设计了一套信息加密形式。如果不足或者存在更好的方式,欢迎大家讨论指正。
RSA算法密钥长度的选择:
RSA算法密钥长度的选取直接关系到加解密、签名验签的安全强度和运算速度。密钥的长度越大,安全强度越高,算法运算速度越慢。所以RSA算法密钥的长度要结合项目的实际情况来选取,以求在安全和效率之间取得平衡。总体来说,现在市场上RSA密钥长度应用较多的是1024位和2048位。简称RSA1024算法和RSA2048算法。
RSA加密算法特性:
密钥长度增长一倍,公钥操作所需时间增加约4倍,私钥操作所需时间约增长8倍,公私钥生成时间约增长16倍。
一次能加密的密文长度与公钥长度成正比,如RSA1024,一次能加密的内容长度为 1024/8 = 128byte(包含填充字节)。所以非对称加密一般都用于加密对称加密算法的密钥,而不是直接加密内容。
加密后密文的长度为公钥的长度,例如公钥长度为1024Bit(128Byte),最后生成的密文固定为 1024Bit(128Byte)。
综上,当密文过长时,需要分开进行加密和解密。附上后台加解密代码:
package com.skysys.qicloud.service.utils;
import sun.misc.BASE64Decoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;
import java.util.HashMap;
public class RSAUtils {
/**
* 使用getPublicKey得到公钥,返回类型为PublicKey
*
* @paramv String to PublicKey
* @throws Exception
*/
public static RSAPublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
return publicKey;
}
/**
* 转换私钥
*
* @param
* @throws Exception
*/
public static RSAPrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
return privateKey;
}
/**
* 生成公钥和私钥
*
* @throws NoSuchAlgorithmException
*/
public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException {
HashMap<String, Object> map = new HashMap<String, Object>();
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
map.put("public", publicKey);
map.put("private", privateKey);
return map;
}
/**
* 私钥加密
* @param generatePrivate
* @param data
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws NoSuchPaddingException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws InvalidKeyException
* @throws IOException
*/
public static String testEncrypt(RSAPrivateKey generatePrivate,String data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, IOException{
Cipher ci = Cipher.getInstance("RSA");
ci.init(Cipher.ENCRYPT_MODE, generatePrivate);
byte[] bytes = data.getBytes();
int inputLen = bytes.length;
int offLen = 0;//偏移量
int i = 0;
ByteArrayOutputStream bops = new ByteArrayOutputStream();
while(inputLen - offLen > 0){
byte [] cache;
if(inputLen - offLen > 117){
cache = ci.doFinal(bytes, offLen,117);
}else{
cache = ci.doFinal(bytes, offLen,inputLen - offLen);
}
bops.write(cache);
i++;
offLen = 117 * i;
}
bops.close();
byte[] encryptedData = bops.toByteArray();
String encodeToString = java.util.Base64.getEncoder().encodeToString(encryptedData);
return encodeToString;
}
/**
* 私钥解密
* @param generateprivate
* @param data
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws NoSuchPaddingException
* @throws InvalidKeySpecException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws IOException
*/
public static String testDecrypt(RSAPrivateKey generateprivate,String data) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, IOException {
Cipher ci = Cipher.getInstance("RSA");
ci.init(Cipher.DECRYPT_MODE,generateprivate);
byte[] bytes = java.util.Base64.getDecoder().decode(data);
int inputLen = bytes.length;
int offLen = 0;
int i = 0;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while(inputLen - offLen > 0){
byte[] cache;
if(inputLen - offLen > 128){
cache = ci.doFinal(bytes,offLen,128);
}else{
cache = ci.doFinal(bytes,offLen,inputLen - offLen);
}
byteArrayOutputStream.write(cache);
i++;
offLen = 128 * i;
}
byteArrayOutputStream.close();
byte[] byteArray = byteArrayOutputStream.toByteArray();
return new String(byteArray);
}
}
前台使用node-rsa.js实现RSA加解密。需要注意的是
1. node-rsa加解密的填充方式是 pkcs1_oaep 。而在js中加密解密默认使用的是 pkcs1。所以需要加上key.setOptions({encryptionScheme: ‘pkcs1’})
2. 前台加密之后可能存在特殊字符,如“+”。加密字符串转base64编码时,特殊字符不会被转码,传输过程中特殊字符可能存在丢失,所以需要加上encodeURIComponent(x),可以将一些特殊字符转成编码
var NodeRSA = require('node-rsa');
//调用“获取”加密公钥获得返回值
var str ='MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL+vGeXIxSQGZ+rK4eYajnstMO2u3u0xZFWNFd3oXsKC6ZfSRvI9/Wkpvdc1tnbk0FkbscDHXON2Q89T+9ihg8r4uvZ6OYE4IWyVLrgZkLv9hdtil9R2o57nqKaN6YWGuYYFoLUq1R8H1hVDuJIsUmmEH9Bl4da3Gkg7SfTwFDiQIDAQAB'
//生成一对RSA密钥
var key = new NodeRSA({b: 512});
key.setOptions({encryptionScheme: 'pkcs1'})
var publicDer = key.exportKey('public-der');
var privateDer = key.exportKey('pkcs8-private-der');
var publicKeyStr = publicDer.toString('base64')
var privateKeyStr = privateDer.toString('base64')
console.log('publicKeyStr: ', publicKeyStr)
console.log('privateKeyStr: ', privateKeyStr)
//使用公钥2对秘钥1进行加密,使用x作为参数,调用“获取密钥接口”
var key2 = new NodeRSA();
key2.setOptions({encryptionScheme: 'pkcs1'})
key2.importKey('-----BEGIN PUBLIC KEY-----\n'+str+'-----END PUBLIC KEY-----', "public")
var x = key2.encrypt(privateKeyStr, 'base64');
console.log('encrypt :',encodeURIComponent(x))
//第二步中获得的公钥,对第三步的返回值进行解密,得到AES密钥
var publickey1= "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALIGLG60w2oR4LZrGzxaYDEfOVZFRqRwSvUUI7O7FqKRj11OCLL186DWVB8nL1csr/8BWBWbN2M/kFqQjresTLUCAwEAAQ==";
var key3 = new NodeRSA();
key3.setOptions({encryptionScheme: 'pkcs1'})
key3.importKey('-----BEGIN PUBLIC KEY-----\n'+publickey1+'-----END PUBLIC KEY-----', "public")
var data = "AgQeNnK8Pu/wEkgsp0at7j99BZwPAlRM4n/SYzxKM+lWTfzmt/2shqYO2fnLsrHUK6Ooww5lj9AjGOmR2erNDw==";
var AesKey = key3.decryptPublic(data, 'utf8');
console.log("AesKey:",AesKey);
使用Java进行RSA加解密,可以参考博文:https://www.cnblogs.com/jpfss/p/10207044.html