
Java实现MD5加盐加密和MD5与SHA-1混合加盐加密两种方式
现在一般的MD5加密在网上随随便便就能够解密,解密的网站有以下几个:
PMD5http://pmd5.com/CMD5http://www.cmd5.com/站长工具http://tool.chinaz.com/tools/md5.aspx好了介绍了这么多密码解密的网站,现在我们来介绍如何提高密码的安全性,来防止上面的网站轻松破解我们的密码。
MD5加盐加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| package com.scaffolding.demo.utils;
import java.security.MessageDigest; import java.util.Random;
public class MD5Util {
private static String hex(byte[] arr) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < arr.length; ++i) { sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1, 3)); } return sb.toString(); }
private static String md5Hex(String str) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(str.getBytes()); return hex(digest); } catch (Exception e) { e.printStackTrace(); System.out.println(e.toString()); return ""; } }
public static String getSaltMD5(String password) { 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) { 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 void main(String[] args) { String plaintext = "123456";
String ciphertext = MD5Util.getSaltMD5(plaintext); System.out.println("加盐后MD5:" + ciphertext); System.out.println("是否是同一字符串:" + MD5Util.getSaltverifyMD5(plaintext, ciphertext)); }
}
|
输出结果为:
加盐后MD5:e9a97f49db0f20911ab1d815624b33e75a3236e76040f509
是否是同一字符串:true
这时,我们可以把加盐后的 加密密码 拿到 MD5加密网上去验证是否能够解密(这里我只列举其中一个网站进行验证,你们也可以自行拿去各个MD5加密网站上去验证)

我们可以看到,MD5加密网站已经无法破解我们加密的密码了,所以MD5加盐加密的密码相对来说还是比较安全的。
MD5和SHA-1混合加盐加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| package com.scaffolding.demo.utils;
import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random;
public class MD5Utils {
public static String md5AndSha(String inputText) { return sha(md5(inputText)); }
public static String md5(String inputText) { return encrypt(inputText, "md5"); }
public static String sha(String inputText) { return encrypt(inputText, "sha-1"); }
private static String encrypt(String inputText, String algorithmName) { if (inputText == null || "".equals(inputText.trim())) { throw new IllegalArgumentException("请输入要加密的内容"); } if (algorithmName == null || "".equals(algorithmName.trim())) { algorithmName = "md5"; } String encryptText = null; try { MessageDigest m = MessageDigest.getInstance(algorithmName); m.update(inputText.getBytes("UTF8")); byte s[] = m.digest(); return hex(s); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return encryptText; }
private static String hex(byte[] arr) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < arr.length; ++i) { sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1, 3)); } return sb.toString(); }
public static String getSaltMd5AndSha(String password) { 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 = md5AndSha(password + salt);
char[] cs = new char[48]; for (int i = 0; i < 48; i += 3) { 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 getSaltverifyMd5AndSha(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); String encrypPassword = md5AndSha(password + salt);
encrypPassword = encrypPassword.substring(0, encrypPassword.length() - 8);
return encrypPassword.equals(String.valueOf(cs1)); }
public static void main(String[] args) { String plaintext = "123456";
String ciphertext = MD5Utils.getSaltMd5AndSha(plaintext); System.out.println("加盐后MD5:" + ciphertext); System.out.println("是否是同一字符串:" + MD5Utils.getSaltverifyMd5AndSha(plaintext, ciphertext)); }
}
|
眼睛比较明亮的朋友,可能会发现 MD5 和 SHA-1 混合加盐加密 与 MD5 加盐加密 的 getSaltverifyMD5(String password, String md5str) 方法有些不同,是的,MD5和SHA-1混合加盐加密 的 getSaltverifyMD5(String password, String md5str) 多了下面这一行代码:
1 2
| encrypPassword = encrypPassword.substring(0 , encrypPassword.length() - 8);
|
就会有人问了,为什么要去掉加密密码的最后8位数,而MD5加盐加密却不要?其实这是有原因的
我们可以看到密码为 123456 经过 MD5、MD5和SHA-1 混合加密的结果:
MD5 :e10adc3949ba59abbe56e057f20f883e (32位数)
MD5和SHA-1 :10470c3b4b1fed12c3baac014be15fac67c6e815 (40位数)
发现有什么不同了没?两种加密之后的密码长度是不是 不一样了 经过MD5加密之后的密码长度为32,而MD5和SHA-1的为40
而我们在 getSaltMd5AndSha (与getSaltMD5代码相同,只是方法名称不一样)中定义的
盐长度为 16位数(即 StringBuilder sBuilder = new StringBuilder(16) ;)
加盐加密后的密码长度为 48位数 (即 char[] cs = new char[48]; )
加盐加密后的密码长度 = 盐长度 + MD5加密的密码长度 (即 48 = 16 + 32 )
长度刚刚等于48位数,所以char[] cs 刚好可以把 密码和盐全部都存储起来,可是MD5和SHA-1 加密的密码长度为40,即
48 < 40 + 16,还会有八位数不能够存储到char[] cs 中, 这也就意味着 char[] cs 只能够存储 MD5和SHA-1 加密密码的前32位数 和 16位数的盐,MD5和SHA-1 加密密码的最后八位会丢失,而在验证加盐后是否和原密码一致的getSaltverifyMd5AndSha(String password, String md5str)方法中,我们定义的 char[] cs1 = new char[32];(即去掉盐之后的MD5和SHA-1 加密密码)只有32位数,而MD5和SHA-1 加密密码实际位数有40位数,那么在进行encrypPassword.equals(String.valueOf(cs1) ) 时,就会返回false,即原密码与加密密码验证不一致。
所以要解决这个问题,就是把MD5和SHA-1 加密的密码结果 去掉最后8位数,再进行比较,这样就可以验证原密码是否与加密密码一致了。