1. 加密解密
1.1 前端js加密概述
對系統安全性要求比較高,那麼需要選擇https協議來傳輸數據。當然很多情況下一般的web網站,如果安全要求不是很高的話,用http協議就可以了。在這種情況下,密碼的明文傳輸顯然是不合適的,因爲如果請求在傳輸過程中被截了,就可以直接拿明文密碼登錄網站了。
HTTPS(443)在HTTP(80)的基礎上加入了SSL(Secure Sockets Layer 安全套接層)協議,SSL依靠證書來驗證服務器的身份,併爲瀏覽器和服務器之間的通信加密。傳輸前用公鑰加密,服務器端用私鑰解密。
常用的對稱加密算法有DES、3DES(TripleDES)、AES、RC2、RC4、RC5和Blowfis。可以參考:常用加密算法的Java實現總結
這裏採用js端與java端互通的AES加密算法。
1.2 前後端加密解密
爲了保證通信過程中的保密性能,我們使用如下來進行前段加密後端解密。
1.2.1 引用的js加密庫
Cryptojs下載: 點擊下載
【如果沒有積分的可以下面留下郵箱,我發送到郵箱】
在頁面中引入如下文件:
<script src=".../jquery-2.2.4.min.js"></script>
<script src=".../aes.js"></script>
<script src=".../mode-ecb-min.js"></script>
1.2.2 js加密解密
var data = "my name is xx";
var srcs = CryptoJS.enc.Utf8.parse(data);
var key = CryptoJS.enc.Utf8.parse('o7H8uIM2O5qv65l2');//Latin1 w8m31+Yy/Nw6thPsMpO5fg==
function Encrypt(word){
var srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
return encrypted.toString();
}
function Decrypt(word){
var decrypt = CryptoJS.AES.decrypt(word, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
}
1.2.3 Java端加密解密(PKCS5Padding與js的Pkcs7一致)
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
public class EncryptUtil {
private static final String KEY = "abcdefgabcdefg12";
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
public static String base64Encode(byte[] bytes){
return Base64.encodeBase64String(bytes);
}
public static byte[] base64Decode(String base64Code) throws Exception{
return new BASE64Decoder().decodeBuffer(base64Code);
}
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
return cipher.doFinal(content.getBytes("utf-8"));
}
public static String aesEncrypt(String content, String encryptKey) throws Exception {
return base64Encode(aesEncryptToBytes(content, encryptKey));
}
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
return aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
}
public static void main(String[] args) throws Exception {
String content = "my name is";
System.out.println("加密前:" + content);
System.out.println("加密密鑰和解密密鑰:" + KEY);
String encrypt = aesEncrypt(content, KEY);
System.out.println(encrypt.length()+":加密後:" + encrypt);
String decrypt = aesDecrypt(encrypt, KEY);
System.out.println("解密後:" + decrypt);
}
}
1.2.4 後端解密前端使用如下方法
當我們直接在後端解密上述前端拿過來的密文時,發現密文是一個16進制的數,及經過base64的。 所以上述方法就行不通,就需要做一個轉換,使用如下解密方法:
//解密函數
public static String Decrypt(String src) throws Exception {
String key = KEY; // 與js的密鑰保持一致
try {
byte[] data = key.getBytes("utf-8");
byte[] raw = new byte[16];
byte[] plusbyte = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f };
for (int i = 0; i < 16; i++) {
if (data.length > i)
raw[i] = data[i];
else
raw[i] = plusbyte[0];
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
// byte[] encrypted1 = new Base64().decode(src);//base64
byte[] encrypted1 = toByteArray(src);// 十六進制
try {
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original, "utf-8");
return originalString;
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
public static byte[] toByteArray(String hexString) {
if (hexString.isEmpty())
throw new IllegalArgumentException("this hexString must not be empty");
hexString = hexString.toLowerCase();
final byte[] byteArray = new byte[hexString.length() / 2];
int k = 0;
for (int i = 0; i < byteArray.length; i++) {// 因爲是16進制,最多隻會佔用4位,轉換成字節需要兩個16進制的字符,高位在先
byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
byteArray[i] = (byte) (high << 4 | low);
k += 2;
}
return byteArray;
}
2. 隨機數生成器
import java.util.Random;
public class RandomUtil {
public static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String LETTERCHAR = "abcdefghijkllmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String NUMBERCHAR = "0123456789";
/**
* 返回一個定長的隨機字符串(只包含大小寫字母、數字)
* @param length 隨機字符串長度
* @return 隨機字符串
*/
public static String generateString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
}
return sb.toString();
}
/**
* 返回一個定長的隨機純字母字符串(只包含大小寫字母)
* @param length 隨機字符串長度
* @return 隨機字符串
*/
public static String generateMixString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(LETTERCHAR.charAt(random.nextInt(LETTERCHAR.length())));
}
return sb.toString();
}
/**
* 返回一個定長的隨機純大寫字母字符串(只包含大小寫字母)
*
* @param length
* 隨機字符串長度
* @return 隨機字符串
*/
public static String generateLowerString(int length) {
return generateMixString(length).toLowerCase();
}
/**
* 返回一個定長的隨機純小寫字母字符串(只包含大小寫字母)
*
* @param length
* 隨機字符串長度
* @return 隨機字符串
*/
public static String generateUpperString(int length) {
return generateMixString(length).toUpperCase();
}
/**
* 生成一個定長的純0字符串
*
* @param length
* 字符串長度
* @return 純0字符串
*/
public static String generateZeroString(int length) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
sb.append('0');
}
return sb.toString();
}
/**
* 根據數字生成一個定長的字符串,長度不夠前面補0
*
* @param num
* 數字
* @param fixdlenth
* 字符串長度
* @return 定長的字符串
*/
public static String toFixdLengthString(long num, int fixdlenth) {
StringBuffer sb = new StringBuffer();
String strNum = String.valueOf(num);
if (fixdlenth - strNum.length() >= 0) {
sb.append(generateZeroString(fixdlenth - strNum.length()));
} else {
throw new RuntimeException("將數字" + num + "轉化爲長度爲" + fixdlenth
+ "的字符串發生異常!");
}
sb.append(strNum);
return sb.toString();
}
/**
* 每次生成的len位數都不相同
*
* @param param
* @return 定長的數字
*/
public static int getNotSimple(int[] param, int len) {
Random rand = new Random();
for (int i = param.length; i > 1; i--) {
int index = rand.nextInt(i);
int tmp = param[index];
param[index] = param[i - 1];
param[i - 1] = tmp;
}
int result = 0;
for (int i = 0; i < len; i++) {
result = result * 10 + param[i];
}
return result;
}
}