第一次写文章,不知道怎么写,写的不好或者不对的地方请大家指出,本人肯定会虚心接纳。
对于数据加密和为什么需要数据加密,网上的文章一搜就一大片,以博主那三脚猫的知识就不和大家解释啦(??)。
进入正题,博主所在公司开发的项目,无论是app端还是h5网页,和后端都以json数据交互,也就是常说的一套接口给所有前端使用,所以彻底解放了博主写接口的压力,哈哈??。
既然涉及数据交互,肯定不能避免数据安全的问题,自然而然我们就会想到对数据进行加密和解密。现在博主接触到的数加密和解密算法是对称算法(AES)和非对称算法(RSA),当然还有其他算法,但我们也不需要研究太多,够用就行,开发不就是这样嘛??。我们传递的数据被非法用户窃取,如果使用AES算法,这个算法的优势就是加解密速度快,由于秘钥也保存在前端(如果是保存app,还需要费劲的破解app;但如果是保存在网页,这个博主不说大家也知道)基本没有安全保障,如果使用RSA算法,那基本安全无忧,但RSA算法对数据加密和解密非常的耗时,当然这个也受限于服务器哈,如果服务器性能很强,直接使用RSA对数据加密解密就行,如果服务器性能有限,可以继续看博主接下来的方式。
如果我们的AES秘钥不能或者很难被获取到,是不是就解决安全性的问题啦。那我们如何来保证AES秘钥很难被获取呢?没错,用RSA来保证,首先AES秘钥都是随机的,然后我们使用RSA算法,对AES的秘钥进行加密解密,这个其实就是数字信封技术,博主小小的卖弄一波哈??。
画个图来解释我们这个加密解密过程,帮助大家理解。
1:首先客户端存储着RSA公钥,就算非法用户拿到RSA公钥,他也很难根据公钥和加密数据进行解密,这个算法已经保证了,支付宝
也是使用RSA来对数据加密,所以大家可以放心使用RSA算法。
2:客户端随机生成AES的秘钥,这个秘钥长度必须是16的倍数,这个是经过项目检验得到验证,然后使用RSA公钥对AES产生的秘钥
进行加密发送给服务端。
3:服务端使用RSA秘钥对已经过RSA公钥加密的AES秘钥进行解密,得到AES的秘钥,保存起来;接下来比较重要的就是产生临时会
话号,为什么需要这个会话号呢?因为我们的场景下可能是不需要用户登录的,为了标识这个用户,我们得产生一个会话号,这个
必须是保证唯一性,因为我们得根据这个会话号去标识当前的请求用户,还有一个作用就是根据这个会话号来对应不同
的AES秘钥。博主是将会话号保存在redis中,当然也有很多方案,这个看项目需求。
4:接下来就开始进行客户端和服务端数据交互,当然如果我们在未登录情况下,注意客户端得传递临时会话号,否则服务端找不到
AES秘钥就没办法对数据解密和加密
说了那么多理论的东西,是不是有些急不可待看看怎么取实现了呐。废话不多说,上代码。
RSAHelper.java
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.junit.Test;
import org.springframework.util.Base64Utils;
public class RSAHelper {
public static final String PUBLIC_KEY_VALUES = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgl0qiFQP8P/Wv5ZXRe78wxU3h7f/5xkh0ChiJ0f4Md0KZv0cSOzBGptNC41tL6cg1qKNPcEuJH296jet/T0Q+cD2tuofHtnB4ghhhCVHT8gkxhV+DJ61BquUIRrhJwj8jU3pw/klY+gIiiOfJFz2Hpar6Lyp+KCTZTyljg0vKPQIDAQAB";
public static final String PRIVATE_KEY_VALUES = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKCXSqIVA/w/9a/lldF7vzDFTeHt//nGSHQKGInR/gx3Qpm/RxI7MEam00LjW0vpyDWoo09wS4kfb3qN639PRD5wPa26h8e2cHiCGGEJUdPyCTGFX4MnrUGq5QhGuEnCPyNTenD+SVj6AiKI58kXPYelqvovKn4oJNlPKWODS8o9AgMBAAECgYEAgmW2vVtxK/9HYPd8Kmhf+5sKPX0Cz+8YX9jeyfIQZlDkbHErpXsYHRZTDsoMFN0Uq7VuPg/B1esHmyzn3y0fDIU1MYcrxBGtKWm1AxwpTcCafsQ3VakkMRkTD8QNZXqcyctB4aRIVWq3p3556zHEIwyxUMCr4UDUKjilJBi/q2ECQQDf1N4Gi1eWnkFuVjD6mJ6bfGJ04l8DajIdt/N/a/J4O1TlPMnaBons5cg/evatsiZvRHYsXeoWygaJhCcoap8JAkEAt6uzQXxfM/oNSZj5voIgZc2xhMWej7bAYYS6Q9/n5KNkybtWSHYe8lbJc4Q4/eYzinDwMYRxVNFR0WuUwafqlQJAPjlkG7ei+tk14WGOriu9dAYpLMs9lKpyEjbwN00gE/KSkEPM7ZKBx1y9xX/+kZ0D+Ey0+XKGQB2boaEebaruWQJAXHeivVtCCsbenajYQuL8MISH1JIxK6UT4YSSyc0Vz/O6sB0SaVSea97peLCeiKS2WgJVynglHlBrYoVI1N4WqQJBAJt92JHPMlvsKcmeVgQS5LmobsYc5EYUQ0sHUpvQJ26/hh2pDBKxYmyhl1TNuEVfsjuvDbdfPzn9MMqDt5RPbcc=";
/**
* RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024
*/
public static final int KEY_SIZE = 1024;
/**
* 生成公钥、私钥对(keysize=1024)
*/
public static RSAHelper.KeyPairInfo getKeyPair() {
return getKeyPair(KEY_SIZE);
}
/**
* 生成公钥、私钥对
*
* @param keySize
* @return
*/
public static RSAHelper.KeyPairInfo getKeyPair(int keySize) {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(keySize);
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey oraprivateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey orapublicKey = (RSAPublicKey) keyPair.getPublic();
RSAHelper.KeyPairInfo pairInfo = new RSAHelper.KeyPairInfo(keySize);
//公钥
byte[] publicKeybyte = orapublicKey.getEncoded();
String publicKeyString = Base64.encodeBase64String(publicKeybyte);//Base64.encode(publicKeybyte);
pairInfo.setPublicKey(publicKeyString);
//私钥
byte[] privateKeybyte = oraprivateKey.getEncoded();
String privateKeyString = Base64.encodeBase64String(privateKeybyte);//Base64.encode(privateKeybyte);
pairInfo.setPrivateKey(privateKeyString);
return pairInfo;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取公钥对象
*
* @param publicKeyBase64
* @return
* @throws InvalidKeySpecException
* @throws NoSuchAlgorithmException
*/
public static PublicKey getPublicKey(String publicKeyBase64)
throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicpkcs8KeySpec =
new X509EncodedKeySpec(Base64.decodeBase64(publicKeyBase64));//Base64.decode(publicKeyBase64)
PublicKey publicKey = keyFactory.generatePublic(publicpkcs8KeySpec);
return publicKey;
}
/**
* 获取私钥对象
*
* @param privateKeyBase64
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PrivateKey getPrivateKey(String privateKeyBase64)
throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA")</