Base64的加密和解密
轉載:Java如何進行Base64的編碼(Encode)與解碼(Decode)?
Base64是一種能將任意Binary資料用64種字元組合成字串的方法,而這個Binary資料和字串資料彼此之間是可以互相轉換的,十分方便。在實際應用上,Base64除了能將Binary資料可視化之外,也常用來表示資料加密過後的內容。如果要使用Java程式語言來實作Base64的編碼與解碼功能,可以參考本篇文章的作法。
@Test
public void textDisplayMetrics() {
final Base64.Decoder decoder = Base64.getDecoder();
final Base64.Encoder encoder = Base64.getEncoder();
final String text = "字串文字";
byte[] textByte = new byte[0];
try {
textByte = text.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
final String encodedText = encoder.encodeToString(textByte);
System.out.println("編碼 encodedText ==" + encodedText);
try {
System.out.println("解碼 ==" + new String(decoder.decode(encodedText), "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
這是Java8中提供的方法,和傳統加密解密方法得到的值一致,之前的方法已經在Java9過期。
MD5加密
以下內容大部分轉載自:MD(Message Digest ) 消息摘要算法之MD5
實現
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
public class MD5Utils {
public static String md5(String s) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
byte[] btInput = s.getBytes();
// 獲得MD5摘要算法的 MessageDigest 對象
//// 如果輸入“SHA”,就是實現SHA加密
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字節更新摘要
mdInst.update(btInput);
// 獲得密文
byte[] md = mdInst.digest();
// 把密文轉換成十六進制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 對數據,進行MD5算法的信息摘要計算
*
* @param data 數據的字節數組
* @return
*/
public static String encryptMD5(byte[] data) {
try {
// 判斷數據的合法性
if (data == null) {
throw new RuntimeException("數據不能爲NULL");
}
// 獲取MD5算法
MessageDigest md5 = MessageDigest.getInstance("MD5");
// 加入要獲取摘要的數據
md5.update(data);
// 獲取數據的信息摘要
byte[] resultBytes = md5.digest();
// 將字節數組轉化爲16進制
String resultString = fromBytesToHex(resultBytes);
return resultString;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 對數據,進行MD5算法的信息摘要計算
*
* @param data 要進行計算信息摘要的數據
* @return
*/
public static String encryptMD5(String data) {
try {
// 判斷數據的合法性
if (data == null) {
throw new RuntimeException("數據不能爲NULL");
}
// 獲取MD5算法
MessageDigest md5 = MessageDigest.getInstance("MD5");
// 加入要獲取摘要的數據
md5.update(data.getBytes());
// 獲取數據的信息摘要
byte[] resultBytes = md5.digest();
// 將字節數組轉化爲16進制
String resultString = fromBytesToHex(resultBytes);
return resultString;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 計算給定文件的信息摘要
*
* @param path 文件的路徑
* @return
* @throws Exception
*/
public static String getMD5OfFile(String path) {
FileInputStream fis = null;
DigestInputStream dis = null;
String resultString = null;
try {
fis = new FileInputStream(new File(path));
dis = new DigestInputStream(fis, MessageDigest.getInstance("MD5"));
// 流輸入
byte[] buffer = new byte[1024];
int read = dis.read(buffer, 0, 1024);
while (read != -1) {
read = dis.read(buffer, 0, 1024);
}
MessageDigest md = dis.getMessageDigest();
byte[] resultBytes = md.digest();
// 將字節數組轉化爲16進制
resultString = fromBytesToHex(resultBytes);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 關閉流,釋放資源
close(fis, dis);
}
return resultString;
}
public static void close(Closeable... closeables) {
for (int i = 0; i < closeables.length; i++) {
if (closeables[i] != null) {
try {
closeables[i].close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 對數據,進行MD5算法的信息摘要計算,加入了salt
*
* @param data 數據的字節數組
* @param salt 加入的鹽
* @return
*/
public static String encryptMD5AndSalt(byte[] data, Object salt) {
try {
// 將data和鹽拼接
String datatemp = new String(data);
String data_salt = mergeDataAndSalt(datatemp, salt);
// 加入鹽後,數據的信息摘要
// 獲取MD5算法
MessageDigest md5 = MessageDigest.getInstance("MD5");
// 加入要獲取摘要的數據
md5.update(data_salt.getBytes());
// 獲取數據的信息摘要
byte[] resultBytes = md5.digest();
// 將字節數組轉化爲16進制
String resultString = fromBytesToHex(resultBytes);
return resultString;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 對數據,進行MD5算法的信息摘要計算,加入了salt
*
* @param data 數據的字節數組
* @param salt 加入的鹽
* @return
*/
public static String encryptMD5AndSalt(String data, Object salt) {
try {
// 完成數據和鹽的拼接
String data_salt = mergeDataAndSalt(data, salt);
// 加入鹽後,數據的信息摘要
// 獲取MD5算法
MessageDigest md5 = MessageDigest.getInstance("MD5");
// 加入要獲取摘要的數據
md5.update(data_salt.getBytes());
// 獲取數據的信息摘要
byte[] resultBytes = md5.digest();
// 將字節數組轉化爲16進制
String resultString = fromBytesToHex(resultBytes);
return resultString;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 用於數據和salt的拼接
*
* @param data 要計算數據摘要的數據
* @param salt 加入的鹽
* @return
*/
private static String mergeDataAndSalt(String data, Object salt) {
if (data == null) {
data = "";
}
if ((salt == null) || "".equals(salt)) {
return data;
} else {
return data + "{" + salt.toString() + "}";
}
}
/**
* @param encPass 加入鹽後,計算的數據摘要
* @param rawPass 加鹽前的數據
* @param salt 要加入的鹽
* @return
*/
public static boolean isPasswordValid(String encPass, String rawPass,
Object salt) {
String data1 = encPass;
String data2 = encryptMD5AndSalt(rawPass, salt);
return data2.equals(data1);
}
/**
* 將給定的字節數組,轉化爲16進制數據
*
* @param resultBytes
* @return
*/
private static String fromBytesToHex(byte[] resultBytes) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < resultBytes.length; i++) {
if (Integer.toHexString(0xFF & resultBytes[i]).length() == 1) {
builder.append("0").append(
Integer.toHexString(0xFF & resultBytes[i]));
} else {
builder.append(Integer.toHexString(0xFF & resultBytes[i]));
}
}
return builder.toString();
}
}
測試:
@Test
public void textDisplayMetrics() {
final String text = "字串文字";
byte[] textByte = new byte[0];
try {
textByte = text.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(" MD5 encryptMD5 ==" + MD5Utils.encryptMD5(text));
System.out.println(" MD5 getMd5 ==" + com.alibaba.motu.tbrest.utils.MD5Utils.getMd5(textByte));
System.out.println(" MD5 getMd5 ==" + com.alibaba.motu.tbrest.utils.MD5Utils.getMd5Hex(textByte));
System.out.println(" MD5 encrypt ==" + com.taobao.android.tlog.protocol.utils.MD5Utils.encrypt(textByte));
System.out.println(" MD5 encryptMD5 ==" + MD5Utils.encryptMD5(textByte));
}
控制檯輸出:
MD5 encryptMD5 ==c48582ace57f8d96c315138a2ed34148
MD5 getMd5 ==[B@504bae78
MD5 getMd5 ==c48582ace57f8d96c315138a2ed34148
MD5 encrypt ==c48582ace57f8d96c315138a2ed34148
MD5 encryptMD5 ==c48582ace57f8d96c315138a2ed34148
我原本的MD5加密是用的 com.taobao.android.tlog.protocol.utils.MD5Utils.encrypt()這個方法。
經過測試,證明都好用~
MD5是什麼?
MD5全稱爲“Message Digest Algorithm 5”,中文名“消息摘要算法第五版”,又可以稱爲消息摘要算法之MD5
消息摘要算法一個三種:
-
MD (Message Digest) 消息摘要算法
-
SHA(Secure Hash Algorithm) 安全散列算法
-
MAC(Message Authentication Code) 消息認證碼算法
MD5的特點:
- 壓縮性:任意長度的數據,算出的MD5值長度都是固定的。
- 容易計算:從原數據計算出MD5值很容易。
- 抗修改性:對原數據進行任何改動,哪怕只修改1個字節,所得到的MD5值都有很大區別。
- 弱抗碰撞:已知原數據和其MD5值,想找到一個具有相同MD5值的數據(即僞造數據)是非常困難的。
- 強抗碰撞:想找到兩個不同的數據,使它們具有相同的MD5值,是非常困難的。
MD5實現講解:
轉載 Java 自帶的加密類MessageDigest類(加密MD5和SHA):
/**
* 由於MD5 與SHA-1均是從MD4 發展而來,它們的結構和強度等特性有很多相似之處
* SHA-1與MD5 的最大區別在於其摘要比MD5 摘要長 32 比特(1byte=8bit,相當於長4byte,轉換16進制後比MD5多8個字符)。
* 對於強行攻擊,:MD5 是2128 數量級的操作,SHA-1 是2160數量級的操作。
* 對於相同摘要的兩個報文的難度:MD5是 264 是數量級的操作,SHA-1 是280 數量級的操作。
* 因而,SHA-1 對強行攻擊的強度更大。 但由於SHA-1 的循環步驟比MD5 多(80:64)且要處理的緩存大(160 比特:128 比特),SHA-1 的運行速度比MD5 慢。
*
* @param source 需要加密的字符串
* @param hashType 加密類型 (MD5 和 SHA)
* @return
*/
public static String getHash(String source, String hashType) {
// 用來將字節轉換成 16 進製表示的字符
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest md = MessageDigest.getInstance(hashType);
md.update(source.getBytes()); // 通過使用 update 方法處理數據,使指定的 byte數組更新摘要 (爲什麼需要先使用update方法 有的md5方法中怎麼不使用?)
byte[] encryptStr = md.digest(); // 獲得密文完成哈希計算,產生128 位的長整數
char str[] = new char[16 * 2]; // 每個字節用 16 進製表示的話,使用兩個字符
int k = 0; // 表示轉換結果中對應的字符位置
for (int i = 0; i < 16; i++) { // 從第一個字節開始,對每一個字節,轉換成 16 進制字符的轉換
byte byte0 = encryptStr[i]; // 取第 i 個字節
str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字節中高 4 位的數字轉換, >>> 爲邏輯右移,將符號位一起右移
str[k++] = hexDigits[byte0 & 0xf]; // 取字節中低 4 位的數字轉換
}
return new String(str); // 換後的結果轉換爲字符串
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
URL加密和解密
實現
import com.yoshin.company.blogdemo.utils.LogUtils;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class UrlEncodeUtils {
private static final String TAG = "UrlEncodeUtils";
public static String toURLEncoded(String paramString) {
if (paramString == null || paramString.equals("")) {
LogUtils.w(TAG, "toURLEncoded error:" + paramString);
return "";
}
try {
String str = new String(paramString.getBytes(), "UTF-8");
str = URLEncoder.encode(str, "UTF-8");
return str;
} catch (Exception localException) {
LogUtils.e(TAG, "toURLEncoded error:" + paramString, localException);
}
return "";
}
public static String toURLDecoded(String paramString) {
if (paramString == null || paramString.equals("")) {
LogUtils.w(TAG, "toURLDecoded error:" + paramString);
return "";
}
try {
String str = new String(paramString.getBytes(), "UTF-8");
str = URLDecoder.decode(str, "UTF-8");
return str;
} catch (Exception localException) {
LogUtils.e(TAG, "toURLDecoded error:" + paramString, localException);
}
return "";
}
}
測試:
@Test
public void textDisplayMetrics() {
final String text = "字串文字";
System.out.println(" toURLEncoded ==" + UrlEncodeUtils.toURLEncoded(text));
System.out.println(" toURLDecoded ==" + UrlEncodeUtils.toURLDecoded(text));
}
結果:
toURLEncoded ==%E5%AD%97%E4%B8%B2%E6%96%87%E5%AD%97
toURLDecoded ==字串文字
URL爲何需要加密?
發送給服務端的請求中的參數值,如果含有特殊符號,需要是做URLEncode,服務端纔可以正常解析,否則可能會出錯。
URLEncode主要是把一些特殊字符轉換成轉移字符,比如:&要轉換成&這樣的。