相信各位在后端辛劳奋战的各位程序员弟弟们,都曾在项目中遇到各种需要加密算法的场景吧,前端时间也是遇到几个需要加密算法的集成项目,所以总结一个较为常见的加密算法,以便于记录和分享。
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()+ ",yolanda.fang@gllue.com,";
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 = 'system@gllue.com' 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;
}