目录
RSA算法实例
摘要
RSA加密流程
前端部分
后台代码
我的做法以及注意事项
在写web项目的时候,都会有用户登录的场景,如果使用明文传递到后台不管事get请求还是post请求都会造成用户的信息泄露,所以最好的方式就是把用户名和密码加密之后传到后台进行解密,然后再进行用户登录验证.加密方式有很多种,这里给大家介绍一下RSA非对称加密算法,关于RSA加密算法的原理可以自行百度.
RSA加密的大概步骤就是上图所示的.就是正常的用户登录验证步骤,只不过是加上了加密解密的步骤
下面给大家看一下具体的实例:
登录js代码
function login() {
if (!loginValidate()) {
return;
}
var publicKey = '';
//获取RSA公钥 base64加密之后的公钥
$.ajax({
url: "/user/get_publicKey",
method: "post",
async: false,
cache: false,
success: function (result) {
debugger;
if (result.success == "SUCCESS") {
publicKey = result.obj;
} else {
alert(result.msg);
return false;
}
}
});
debugger;
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
//前端加密
var userLoginName = encrypt.encrypt($("#username").val());
var userPassword = encrypt.encrypt($("#password").val());
var data = {
userLoginName: userLoginName,
userPassword: userPassword
};
$.ajax({
url: "/user/user_Login",
data: JSON.stringify(data),
dataType: "json",
method: "post",
contentType: "application/json; charset=UTF-8",
async: false,
cache: false,
success: function (result) {
if (result.success == "SUCCESS") {
pageSkippingOne("index/index");
} else {
alert(result.msg);
}
}
});
return false;
}
在登录的这个js代码里面,先发起一个请求去获取公钥,这里需要注意的是,这个公钥是通过base64加密之后的公钥,不是最原始RSA生成的公钥.还有前端在使用RSA加密的时候要引入jsencrypt.min.js,前端代码差不多就这样了
后台代码controller层的就不贴出来了,大家应该都会的.
先看一下我的RSAUtils和Base64Utils
public interface SystemConstants {
/**
* 项目存放用户session名
* 在接口中的只能存在常量 默认会在前面添加 public static final
*/
String LOGIN_USER = "LOGIN_USER";
/**
* 存放RSA公钥文件路径
*/
String RSA_PUBLIC_KEY_PATH = "E:\\honey-blog\\public_key.txt";
/**
* 存放RSA私钥文件路径
* */
String RSA_PRIVATE_KEY_PATH = "E:\\honey-blog\\private_key.txt";
}
public class Base64Utils {
public static final Logger logger = LoggerFactory.getLogger(Base64Utils.class);
public static final Base64.Encoder ENCODER = Base64.getEncoder();
public static final Base64.Decoder DECODER = Base64.getDecoder();
/**
* base64加密
* @param encodeText 明文
* @return
* */
public static byte[] encoder( byte[] encodeText) {
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encode(encodeText);
}
/**
* base64加密
* @param decodeText 密文
*/
public static byte[] decoder(byte [] decodeText) {
Base64.Decoder decoder = Base64.getDecoder();
return decoder.decode(decodeText);
}
}
public class RSAUtils {
public static final Logger logger = LoggerFactory.getLogger(RSAUtils.class);
public static final String ALGORITHM_NAME = "RSA";
/**
* 获取公钥
*
* @param
* @return
*/
public static String getPublicKey() {
String publicKey = "";
try {
publicKey = getKey(SystemConstants.RSA_PUBLIC_KEY_PATH);
} catch (IOException e) {
logger.error("获取公钥发生io流异常:", e);
} catch (NoSuchAlgorithmException e) {
logger.error("获取公钥发生异常:", e);
}
return publicKey;
}
/**
* 获取秘钥
*
* @param
* @return
*/
public static byte [] getPrivateKey() {
try {
return Base64Utils.decoder(getKey(SystemConstants.RSA_PRIVATE_KEY_PATH).getBytes());
} catch (IOException e) {
logger.error("获取秘钥发生io流异常:", e);
} catch (NoSuchAlgorithmException e) {
logger.error("获取秘钥发生异常:", e);
}
return null;
}
/**
* 生成RSA公钥和秘钥 存放在本地文件
*/
private static void generatePublicSecretKey() throws NoSuchAlgorithmException, IOException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_NAME);
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGenerator.initialize(1024, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
String publicKey = new String(Base64Utils.encoder(rsaPublicKey.getEncoded()));
String privateKey = new String(Base64Utils.encoder(rsaPrivateKey.getEncoded()));
//存放到本地文件
File publicKeyFile = new File(SystemConstants.RSA_PUBLIC_KEY_PATH);
File privateKeyFile = new File(SystemConstants.RSA_PRIVATE_KEY_PATH);
if (!publicKeyFile.exists()) {
publicKeyFile.createNewFile();
}
if (!privateKeyFile.exists()) {
privateKeyFile.createNewFile();
}
//写入文件
writeFile(publicKeyFile, publicKey);
writeFile(privateKeyFile, privateKey);
}
private static void writeFile(File file, String key) throws IOException {
//写入文件
FileOutputStream outputStram = new FileOutputStream(file);
byte[] bytes = new byte[512];
bytes = key.getBytes();
int bytesLength = bytes.length;
outputStram.write(bytes, 0, bytesLength);
outputStram.close();
}
/**
* 判断存放公钥和秘钥的文件夹是否存在
* 存在则直接读取里面的数据,不存在则新生成
* @param path
* @return
*/
private static String getKey(String path) throws IOException, NoSuchAlgorithmException {
File fiel = new File(path);
if (!fiel.exists() && path.equals(SystemConstants.RSA_PUBLIC_KEY_PATH)) {
generatePublicSecretKey();
}
InputStreamReader reader = new InputStreamReader(new FileInputStream(fiel));
BufferedReader bufferedReader = new BufferedReader(reader);
String key = "";
StringBuffer buffer = new StringBuffer();
key = bufferedReader.readLine();
while (key != null) {
buffer.append(key);
key = bufferedReader.readLine();
}
return String.valueOf(buffer);
}
/**
* RSA 私钥解密
* @param preContent 公钥加密之后的内容
* @return
* */
public static String privateKeyDecode(String preContent){
String content = "";
try {
byte[] privateKey = getPrivateKey();
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(ALGORITHM_NAME).generatePrivate(new PKCS8EncodedKeySpec(privateKey));
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
cipher.init(Cipher.DECRYPT_MODE, priKey);
content = new String(cipher.doFinal(Base64Utils.decoder(preContent.getBytes("UTF-8"))));
}catch (Exception e){
logger.error("RSA私钥解密出现异常:",e);
}
return content;
}
}
我的Base64Utils的Base64使用的是java.util包下的.
对于RSA加密算法,我的做法是,生成RSA公钥和私钥,通过base64加密之后,分别存放到不同的txt文件中,当前端发起请求去获取公钥的时候去判断存放公钥和私钥的文件是否存在,不存在就新生成公钥和私钥,存在就直接获取公钥,注意获取到txt中的公钥是通过base64加密了的,不要把取出来的这个通过base64解密,直接返回给前端,前端就拿到这个公钥去加密,然后把加密之后的数据返回给后台,这个时候也要注意, 获取私钥,这个时候你把私钥从txt文件中取出来 你就需要进行base64解密了,拿到原始的私钥去生成RSAPrivateKey,还有一点这个时候前端传回来的用户名和密码在通过公钥加密的时候也是经过base64加密处理了的,所以你要把从前端拿到的数据进行base64解密.
主要的代码差不读就是我贴出来的RSAUtils中的代码,整个过程中,你需要明白以及注意的是base64加密以及解密的使用.切记!切记!!切记!!! 重要的事情说三遍 一定要注意上文我说的有关base64的几个点,要不然有得你扣脑壳的时候.