数据加密的基本过程就是对原来为明文的文件或数据按某种加密算法进行处理,使其成为一段不可读的代码,通常称为“密文”,通过这种途径来达到保护原始数据的目的。通过解密方法或秘钥,经过解密过程,可以将密文还原成可读的原文。
MD5加密
md5加密是我们常用的一种加密算法,可以对明文进行处理产生一个128位(16字节)的散列值,为了便于展示和读写一般将128位的二进制数转换成32位16进制数(如:655A6E9A375DF4F82B730833C807AADD)。通常用在密码存储和文件的完整性校验上。
MD5加密算法实现
Java中提供了MessageDigest类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。
1.计算文件的md5值,方法一:
publicstaticStringgetMD5(File f){ BigInteger bi =null;try{byte[] buffer =newbyte[8192];intlen =0; MessageDigest md = MessageDigest.getInstance("MD5"); FileInputStream fis =newFileInputStream(f);while((len = fis.read(buffer)) != -1) { md.update(buffer,0, len); } fis.close();byte[] b = md.digest(); bi =newBigInteger(1, b); }catch(NoSuchAlgorithmException e) { e.printStackTrace(); }catch(IOException e) { e.printStackTrace(); }if(bi !=null)returnbi.toString(16);elsereturn""; }
方法二:
publicstaticStringmd5(File file) {if(file ==null|| !file.isFile() || !file.exists()) {return""; } FileInputStreamin=null;Stringresult =""; byte buffer[] =newbyte[8192]; int len;try{ MessageDigest md5 = MessageDigest.getInstance("MD5");in=newFileInputStream(file);while((len =in.read(buffer)) !=-1) { md5.update(buffer,0, len); } byte[] bytes = md5.digest();for(byte b : bytes) {Stringtemp = 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(); } } }returnresult; }
2.计算字符串的md5值
publicstaticStringmd5(Stringstring){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; }returnresult; }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")privatestaticStringmd5Hex(String str){try{ MessageDigest md = MessageDigest.getInstance("MD5");byte[] digest = md.digest(str.getBytes());returnnewString(newHexUtil().encode(digest)); }catch(Exception e) { e.printStackTrace(); System.out.println(e.toString());return""; } }/**
* 加盐MD5加密
*/publicstaticStringgetSaltMD5(String password){// 生成一个16位的随机数Random random =newRandom(); StringBuilder sBuilder =newStringBuilder(16); sBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));intlen = sBuilder.length();if(len <16) {for(inti =0; i <16- len; i++) { sBuilder.append("0"); } }// 生成最终的加密盐String Salt = sBuilder.toString(); password = md5Hex(password + Salt);char[] cs =newchar[48];for(inti =0; i <48; i +=3) {//在结果中的每三位用中间位保存salt值cs[i] = password.charAt(i /3*2);charc = Salt.charAt(i /3); cs[i +1] = c; cs[i +2] = password.charAt(i /3*2+1); }returnString.valueOf(cs); }/**
* 验证加盐后是否和原文一致
*/publicstaticbooleangetSaltverifyMD5(String password, String md5str){char[] cs1 =newchar[32];char[] cs2 =newchar[16];for(inti =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 =newString(cs2);returnmd5Hex(password + Salt).equals(String.valueOf(cs1)); }publicstaticclassHexUtil{/**
* 字节流转成十六进制表示
*/publicstaticStringencode(byte[] src){ String strHex =""; StringBuilder sb =newStringBuilder("");for(intn =0; n < src.length; n++) { strHex = Integer.toHexString(src[n] &0xFF);// 每个字节由两个字符表示,位数不够,高位补0sb.append((strHex.length() ==1) ?"0"+ strHex : strHex); }returnsb.toString().trim(); }/**
* 字符串转成字节流
*/publicstaticbyte[] decode(String src) {intm =0, n =0;intbyteLen = src.length() /2;// 每两个字符描述一个字节byte[] ret =newbyte[byteLen];for(inti =0; i < byteLen; i++) { m = i *2+1; n = m +1;intintVal = Integer.decode("0x"+ src.substring(i *2, m) + src.substring(m, n)); ret[i] = Byte.valueOf((byte)intVal); }returnret; } }