密码加盐

加盐是为了防止暴力破解密码

————————

加密算法进行反向查询地址http://www.cmd5.com/

一、密码加盐

       加盐加密是一种对系统登录口令的加密方式,它实现的方式是将每一个口令同一个叫做”盐“(salt)的n位随机数相关联。无论何时只要口令改变,随机数就改变。随机数以未加密的方式存放在口令文件中,这样每个人都可以读。不再只保存加密过的口令,而是先将口令和随机数连接起来然后一同加密,加密后的结果放在口令文件中。

二、几种常见的破解密码的方法

        最简单、常见的破解方式当属字典破解(Dictionary Attack)和暴力破解(Brute Force Attack)方式。这两种方法说白了就是猜密码。

 

clip_image003

 

           字典破解和暴力破解都是效率比较低的破解方式。如果你知道了数据库中密码的哈希值,你就可以采用一种更高效的破解方式,查表法(Lookup Tables)。还有一些方法,比如逆向查表法(Reverse Lookup Tables)、彩虹表(Rainbow Tables)等,都和查表法大同小异。现在我们来看一下查表法的原理。

        查表法不像字典破解和暴力破解那样猜密码,它首先将一些比较常用的密码的哈希值算好,然后建立一张表,当然密码越多,这张表就越大。当你知道某个密码的哈希值时,你只需要在你建立好的表中查找该哈希值,如果找到了,你就知道对应的密码了。

 

clip_image004

三、为密码加盐(Salt)

        从上面的查表法可以看出,即便是将原始密码加密后的哈希值存储在数据库中依然是不够安全的。那么有什么好的办法来解决这个问题呢?答案是加盐。盐(Salt)是什么?就是一个随机生成的字符串。我们将盐与原始密码连接(concat)在一起(放在前面或后面都可以),然后将concat后的字符串加密。采用这种方式加密密码,查表法就不灵了(因为盐是随机生成的)。

 

clip_image005

三、Java工具类实现

 

  1.  
    package com.sangame.core.utils;
  2.  
     
  3.  
    import org.apache.commons.codec.binary.Hex;
  4.  
    import java.security.MessageDigest;
  5.  
     
  6.  
    /**
  7.  
    * 加盐加密工具类
  8.  
    */
  9.  
    public class EncryptedUtil {
  10.  
    /**
  11.  
    * 加盐字符串,长度必须为16位。
  12.  
    */
  13.  
    private final static String salt = "aaaaaaaaaaaaaa3a";
  14.  
     
  15.  
    /**
  16.  
    * 生成含有加盐的密码
  17.  
    */
  18.  
    public static String generate(String password) {
  19.  
    return generate(password, null);
  20.  
    }
  21.  
     
  22.  
    /**
  23.  
    * 生成含有加盐的密码
  24.  
    */
  25.  
    public static String generate(String password, String userName) {
  26.  
    String salt = getSalt(userName);
  27.  
    password = md5Hex(password + salt);
  28.  
    char[] cs1 = password.toCharArray();
  29.  
    char[] cs2 = salt.toCharArray();
  30.  
    char[] cs = new char[48];
  31.  
    for (int i = 0; i < 48; i += 3) {
  32.  
    cs[i] = cs1[i / 3 * 2];
  33.  
    cs[i + 1] = cs2[i / 3];
  34.  
    cs[i + 2] = cs1[i / 3 * 2 + 1];
  35.  
    }
  36.  
    return new String(cs).toUpperCase();
  37.  
    }
  38.  
     
  39.  
    private static String getSalt(String salt){
  40.  
    if(salt == null || salt.length() == 0){
  41.  
    return EncryptedUtil.salt;
  42.  
    }
  43.  
    if(salt.length() <= 16 ){
  44.  
    return getStringLen8(salt) + EncryptedUtil.salt.substring(7, 15);
  45.  
    } else {
  46.  
    return salt.substring(4, 12) + EncryptedUtil.salt.substring(2, 10);
  47.  
    }
  48.  
    }
  49.  
     
  50.  
    public static String getStringLen8(String salt){
  51.  
    if(salt.length() == 8){
  52.  
    return salt;
  53.  
    }
  54.  
    if(salt.length() > 8){
  55.  
    return salt.substring(1, 9);
  56.  
    } else {
  57.  
    return getStringLen8(salt + salt);
  58.  
    }
  59.  
    }
  60.  
     
  61.  
    /**
  62.  
    * 校验密码是否正确
  63.  
    */
  64.  
    public static boolean verify(String password, String md5) {
  65.  
    char[] cs = md5.toLowerCase().toCharArray();
  66.  
    char[] cs1 = new char[32];
  67.  
    char[] cs2 = new char[16];
  68.  
    for (int i = 0; i < 48; i += 3) {
  69.  
    cs1[i / 3 * 2] = cs[i];
  70.  
    cs1[i / 3 * 2 + 1] = cs[i + 2];
  71.  
    cs2[i / 3] = cs[i + 1];
  72.  
    }
  73.  
    String salt = new String(cs2);
  74.  
    return md5Hex(password + salt).equals(new String(cs1));
  75.  
    }
  76.  
     
  77.  
    /**
  78.  
    * 获取十六进制字符串形式的MD5摘要
  79.  
    */
  80.  
    private static String md5Hex(String src) {
  81.  
    try {
  82.  
    MessageDigest md5 = MessageDigest.getInstance("MD5");
  83.  
    byte[] bs = md5.digest(src.getBytes());
  84.  
    return new String(new Hex().encode(bs));
  85.  
    } catch (Exception e) {
  86.  
    return null;
  87.  
    }
  88.  
    }
  89.  
    }

 

posted @ 2020-11-07 00:15  Ander2015  阅读(147)  评论(0编辑  收藏  举报