转载请注明出处://www.greatytc.com/p/286854ec9a41
数据加密的基本过程就是对原来为明文的文件或数据按某种加密算法进行处理,使其成为一段不可读的代码,通常称为“密文”,通过这种途径来达到保护原始数据的目的。通过解密方法或秘钥,经过解密过程,可以将密文还原成可读的原文。
MD5加密
md5加密是我们常用的一种加密算法,可以对明文进行处理产生一个128位(16字节)的散列值,为了便于展示和读写一般将128位的二进制数转换成32位16进制数(如:655A6E9A375DF4F82B730833C807AADD)。通常用在密码存储和文件的完整性校验上。
MD5加密算法实现
Java中提供了MessageDigest类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。
1.计算文件的md5值,方法一:
public static String getMD5(File f) {
BigInteger bi = null;
try {
byte[] buffer = new byte[8192];
int len = 0;
MessageDigest md = MessageDigest.getInstance("MD5");
FileInputStream fis = new FileInputStream(f);
while ((len = fis.read(buffer)) != -1) {
md.update(buffer, 0, len);
}
fis.close();
byte[] b = md.digest();
bi = new BigInteger(1, b);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(bi != null)
return bi.toString(16);
else
return "";
}
方法二:
public static String md5(File file) {
if (file == null || !file.isFile() || !file.exists()) {
return "";
}
FileInputStream in = null;
String result = "";
byte buffer[] = new byte[8192];
int len;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
in = new FileInputStream(file);
while ((len = in.read(buffer)) != -1) {
md5.update(buffer, 0, len);
}
byte[] bytes = md5.digest();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result += temp;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(null!=in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
2.计算字符串的md5值
public static String md5(String string) {
if (TextUtils.isEmpty(string)) {
return "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(string.getBytes());
String result = "";
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result += temp;
}
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
MD5加密的应用
1.对密码进行加密,移动端会将用户密码通过MD5加密转换后发送给服务器,服务器会在数据库中保存加密后的md5值。这样做的好处是不会直接发送明文密码、服务器管理人员也无法确切的知道密码。但是一旦拿到密码的md5值后仍然存在被暴力破解的可能性。
2.文件的完整性校验,在传递文件的过程中附带传递文件的md5值,接收端通过比较文件的md5值判断文件的完整性。
增强MD5的安全性
虽然MD5加密理论上是不可逆的但仍存在被暴力破解的可能性,我们可以通过一下方法加强MD5加密的安全性。
1.对明文多次MD5加密,对明文加密之后的MD5串再次进行MD5加密
2.MD5加盐(salt),基本过程是这样的:当需要对明文进行MD5加密的时候,程序会添加一个salt值跟明文一起进行MD5加密,这样可以极大增强MD5被破解的难度。salt值可以是随机字符串或者username+password这种形式,当使用随机字符串作为salt加密是通常需要将salt一起上传服务器进行保存。
下面是网络上提供的一种MD5加盐加密的使用方法(忘记在哪篇博客上看见的了,抱歉),该方法是将salt值和MD5码组合到一个48位的16进制数中,只要知道组合方式就能从改结果中取出salt和MD5码。
/**
* HexUtil类实现Hex(16进制字符串和)和字节数组的互转
*/
@SuppressWarnings("unused")
private static String md5Hex(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(str.getBytes());
return new String(new HexUtil().encode(digest));
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
return "";
}
}
/**
* 加盐MD5加密
*/
public static String getSaltMD5(String password) {
// 生成一个16位的随机数
Random random = new Random();
StringBuilder sBuilder = new StringBuilder(16);
sBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));
int len = sBuilder.length();
if (len < 16) {
for (int i = 0; i < 16 - len; i++) {
sBuilder.append("0");
}
}
// 生成最终的加密盐
String Salt = sBuilder.toString();
password = md5Hex(password + Salt);
char[] cs = new char[48];
for (int i = 0; i < 48; i += 3) {
//在结果中的每三位用中间位保存salt值
cs[i] = password.charAt(i / 3 * 2);
char c = Salt.charAt(i / 3);
cs[i + 1] = c;
cs[i + 2] = password.charAt(i / 3 * 2 + 1);
}
return String.valueOf(cs);
}
/**
* 验证加盐后是否和原文一致
*/
public static boolean getSaltverifyMD5(String password, String md5str) {
char[] cs1 = new char[32];
char[] cs2 = new char[16];
for (int i = 0; i < 48; i += 3) {
cs1[i / 3 * 2] = md5str.charAt(i);
cs1[i / 3 * 2 + 1] = md5str.charAt(i + 2);
cs2[i / 3] = md5str.charAt(i + 1);
}
String Salt = new String(cs2);
return md5Hex(password + Salt).equals(String.valueOf(cs1));
}
public static class HexUtil{
/**
* 字节流转成十六进制表示
*/
public static String encode(byte[] src) {
String strHex = "";
StringBuilder sb = new StringBuilder("");
for (int n = 0; n < src.length; n++) {
strHex = Integer.toHexString(src[n] & 0xFF);
// 每个字节由两个字符表示,位数不够,高位补0
sb.append((strHex.length() == 1) ? "0" + strHex : strHex);
}
return sb.toString().trim();
}
/**
* 字符串转成字节流
*/
public static byte[] decode(String src) {
int m = 0, n = 0;
int byteLen = src.length() / 2; // 每两个字符描述一个字节
byte[] ret = new byte[byteLen];
for (int i = 0; i < byteLen; i++) {
m = i * 2 + 1;
n = m + 1;
int intVal = Integer.decode("0x" + src.substring(i * 2, m) +
src.substring(m, n));
ret[i] = Byte.valueOf((byte)intVal);
}
return ret;
}
}