相信各位在後端辛勞奮戰的各位程序員弟弟們,都曾在項目中遇到各種需要加密算法的場景吧,前端時間也是遇到幾個需要加密算法的集成項目,所以總結一個較爲常見的加密算法,以便於記錄和分享。
1、Md5+base64字符加密
這種加密算法在java中算是比較常見並且也比較簡單的一種算法,下面看他的具體實現方法。
我這裏的具體案例是把用戶名進行Md5加密然後將組合字符再進行encode64字符加密輸出,兩個算法算是柔和了一下。
安全係數:低
密鑰:無
public static String generateAuthorization(String username, String password) {
String md5Pwd = DigestUtils.md5Hex(password);
String pair = username + ":" + md5Pwd;
return Base64.encodeBase64String(pair.getBytes());
}
2、將字符轉換爲Unicode加密
其實這種應該不算是一種加密方式因爲他的方法通用完全可以方解開
常用於項目中的中文顯示配置文件中的字符存放,和更改,比如一些固定框架位置的顯示字符。方便個性化的更改和配置。
安全係數:低
密鑰:無
public static String stringToUnicode(String string) {
StringBuffer unicode = new StringBuffer();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i); // 取出每一個字符
unicode.append("\\u" +Integer.toHexString(c));// 轉換爲unicode
}
return unicode.toString();
}
3、DES加密
這種加密方式算是比較安全的一種加密方法,因爲他加入的密鑰形式,只要密鑰不泄露應該是安全的。
這裏要注意的是密鑰應該是用8位字符以上的密鑰進行加密,否則會有問題,詳情可以百度一下。
DES加密方式有很多種選擇性也很多這裏的加密方式爲:EDS 加密模式ECB 填充 PKCS5Padding加密 key seeyonsso 輸出 base64 字符集 utf-8
安全係數:高
密鑰:有
* EDS 加密模式ECB 填充 PKCS5Padding加密 key seeyonsso 輸出 base64 字符集 utf-8
*/
public static String EncryptString(String strText, String sKey) {
// MD5加密
// String md5s = EncryptMD5.getMD5(strText);
try {
SecureRandom random = new SecureRandom();
byte[] bkey =(sKey.substring(0,8)).getBytes();
DESKeySpec deskey = new DESKeySpec(bkey);
// 創建一個密鑰工廠,然後用它把DESKeyspec轉換成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(deskey);
// cipher對象實際完成加密操作
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
// cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
// 用密鑰初化Cipher對象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
// 現在,獲取數據並加密
// // 正式執行加密操作
// String str = md5s + strText;
byte[] t = strText.getBytes("UTF-8");
byte[] bResult = cipher.doFinal(t);
// 1、加密完byte[] 後,需要將加密了的byte[] 轉換成base64保存,如:
BASE64Encoder base64encoder = new BASE64Encoder();
String encode=base64encoder.encode(bResult);
return encode;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
順便附上解密方法(前提是知道加密的密鑰才行)
/*
* 解密
*/
public static String DecryptString(String strText, String sKey) {
// DES算法要求有一個可信任的隨機數源
SecureRandom random = new SecureRandom();
// 創建一個DesKeySpec對象
byte[] bkey = (sKey.substring(0,8)).getBytes();
DESKeySpec desKey = null;
try {
desKey = new DESKeySpec(bkey);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
// 創建一個密鑰工廠
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 將DESKeySpec對象轉換成SecretKey對象
SecretKey secreKey = null;
try {
secreKey = keyFactory.generateSecret(desKey);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
// Cipher對象實際完成解密操作
Cipher cipher = null;
try {
cipher = Cipher.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
// 用密鑰初始化Cipher對象
try {
cipher.init(Cipher.DECRYPT_MODE, secreKey, random);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
// 真正開始解密
// 2、解密前,需要將加密後的字符串從base64轉回來再解密,如:
BASE64Decoder base64decoder = new BASE64Decoder();
// byte[] encodeByte = base64decoder.decodeBuffer(strText);
byte[] encodeByte;
byte[] b;
try {
encodeByte = base64decoder.decodeBuffer(strText);
//encodeByte = BASE64Decoder.decodeBuffer(new String( strText.getBytes(),"UTF-8"));
b = cipher.doFinal(encodeByte);
String s = new String(b, "UTF-8");
return s;
} catch (IOException e) {
e.printStackTrace();
}catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
4、AES-128-cbc加密方式
AES-128-cbc加密方式,加密所需要的密鑰AES_KEY爲實現約定。初始變量(IV)值爲 '0000000000000000' (16個0)。 gllue_private_token的值爲當前13位時間戳(整數, 距離unix epoch的毫秒數),郵箱通過AES加密方式加密後,再用base64編碼並url編碼後形成。所需的空格數爲使得s的長度爲16的倍 數。
舉例來說,1477971027294,system@gllue.com,, 通過密鑰eqs214hvIHEY7Reg加密後的token值應 該爲 :
ARP%2B5XryVt0Wo47jlMFwZPUq253azoOR3WODCThFJBU%3D
java實現方法:
/**
* 加密
* @param key
* @param initVector
* @param value
* @return
*/
public static String encrypt(String key,String initVector,String value){
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
//SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
System.out.println("value: "+value.length()+" value: " +value);
byte[] encrypted = cipher.doFinal(value.getBytes("UTF-8"));
//System.out.println("encrypted string: " +Base64.encodeBase64String(encrypted));
System.out.println("encrypted String: "+Base64.encodeBase64String(encrypted));
return Base64.encodeBase64String(encrypted);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 填充
* @param input
* @return
*/
public static String paddingString(String input){
int length = 16;
int diff = length-input.length()%length;
System.out.println("inputLengh: "+input.length()+" paddingDiff: "+diff);
String result = input;
for (int i=0 ;i<diff;i++){
result = result + ' ';
}
System.out.println("paddingResult: "+result);
return result;
}
//執行
public static void main2(String[] args) {
//舉例來說,1477971027294,system@gllue.com,,
//通過密鑰eqs214hvIHEY7Reg加密後的token值應 該爲
//ARP%2B5XryVt0Wo47jlMFwZPUq253azoOR3WODCThFJBU%3D
//String aes_key = "86uL6IWz5ax55o6l";
String aes_key = "86uL6IWz5ax55o6I";
String initVector = "0000000000000000";
System.out.println("aes_key: "+aes_key);
//String before = new Date().getTime()+ ",[email protected],";
String before = new Date().getTime()+ ",system@gllue.com,";
System.out.println("時間戳:"+new Date().getTime()+" before: "+before);
String padding = paddingString(before);
System.out.println("padding: "+padding);
System.out.println("padding lenght: "+padding.length());
String enString = encrypt(aes_key, initVector, padding) ;
String encodeString = null;
try {
encodeString = URLEncoder.encode(enString,"UTF-8").replace("+", "%20");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("enString: "+enString);
System.out.println("enCodeString: "+encodeString);
}
Python實現方法(咋也看不懂咋也不敢問):
import time
import base64 from urllib i
mport quote ,unquote
def pad_text(raw, BS):
raw += (BS - len(raw) % BS) * ' '
print raw return raw
class AESCrypto(object):
def __init__(self, key=None, iv=None):
from Crypto.Cipher import AES
if not iv:
iv = '0' * 16
self.ins = AES.new(key, AES.MODE_CBC, iv)
def encrypt(self, txt):
txt = pad_text(txt, 16)
return base64.encodestring(self.ins.encrypt(txt))
def decrype(self, txt):
origin = self.ins.decrypt(base64.decodestring(txt))
origin.strip()
return origin
aes_key = 'XIguDLSNoLRfoVLT'
timestamp = int(time.time() * 1000)
email = '[email protected]' gllue_private_token = AESCrypto(aes_key).encrypt('{},{},'.format(timestamp, email))
urlencode = quote(gllue_private_token)
print gllue_private_token
print urlencode
print AESCrypto(aes_key).decrype(gllue_private_token)
c#:
public static string AESEncrypt(string toEncrypt, string key, string iv)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.IV = ivArray;
rDel.Mode = CipherMode.CBC;
rDel.Padding = PaddingMode.Zeros;
ICryptoTransform cTransform = rDel.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
5、記錄一個實戰案例
這個加密方式比較特殊,因爲對接的系統是c#語言但是我們系統是java這就導致接口的加密算法可能同樣的方法但是兩種語言加密出來的字符是不一樣的,下面是對方的加密方式:
C#加密方式:
public static string MD5_Encode(string PwdStr, bool Is16Bite)
{
string result = "";
if (PwdStr == null || PwdStr == "")
{
return PwdStr;
}
byte[] In = Encoding.Default.GetBytes(PwdStr);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] Out = md5.ComputeHash(In);
result = BitConverter.ToString(Out).Replace("-", "");
if (Is16Bite)
{
result = result.Substring(7, 16);
}
return result;
}
java:
通過流程圖上的加密方式可以看到雖然是C#語言但是也是用的base64+md5加密,只不過稍微多了幾步操作,但是實際上用java同樣的方式加密出來的東西還是有些不一樣,通過不段的測試和試驗找出了規律:java md5加密字符出來的都是大寫的字符,而C#加密都是小寫的用md5加密後轉換一下大小寫就可以了。
//md5加密 濟邦
public static String generateAuthorizationjibang(String EmpCode, String CustomerCode,String token) {
BASE64Encoder base64encoder = new BASE64Encoder();
BASE64Decoder base64decoder = new BASE64Decoder();
String digest = null;
try {
String md5Byte = (EmpCode+CustomerCode+ new String(base64decoder.decodeBuffer(token),"utf-8"));
String digmd5 = DigestUtils.md5Hex((md5Byte));
digest = base64encoder.encode((digmd5.toUpperCase()).getBytes("utf-8"));
System.out.println("==============LogincallbackPage generateAuthorizationjibang digest:"+digest);
} catch (Exception e) {
System.out.println("==============LogincallbackPage generateAuthorizationjibang error!: "+e);
}
return digest;
}