java中的加解密之MD5和加盐详解编程语言

java中的加解密之MD5和加盐详解编程语言

很多人都用MD5+Base64方式存储密码,这种存储方式 方便、速度快而且由于MD5杂凑算法的几乎不可还原性,攻击者只能通过”猜”去破解密码。

但是MD5对相同的数据返回的信息永远是一样的,”123456″通过MD5+Base64编码后,永远是”4QrcOUm6Wau+VuBX8g+IPg==”,攻击者只需要一个简单的sql就可以知道有几个用户密码是”123456″,这样十分危险。

//这个循环无论执行几次,返回都是一样。  

static void t3(){  

    for(int i=0;i<5;i++){  

        try {  

            String inputPwd = “123456”;  

            MessageDigest md;  

            BASE64Encoder b64Encoder = new BASE64Encoder();  

            byte[] bys = null;  

              

            md = MessageDigest.getInstance(“MD5″,”SUN”);  

            md.reset();  

            md.update(inputPwd.getBytes(“UTF-8”));  

            bys = md.digest();  

            System.out.println(“编码后:”+b64Encoder.encode(bys));              

        } catch (Exception e) {  

            e.printStackTrace();  

        }  

    }  

}

一种简单有效的解决方法,就是在MD5杂凑前加点随机码,这样攻击者将无法通过一个简单的SQL语句来查找密码是”123456″的用户。

随机码长度是应该固定,且同用户输入的密码一起进行MD5杂凑,随机码应该在Base64编码后的固定位置。

校验时,先取出随机码,再同输入一起进行MD5杂凑,与以前存储的密码比较是否一致。

import java.security.MessageDigest;  

import java.util.Random;  

import sun.misc.BASE64Encoder;  

/**

 * 对帐号口令加密

 */  

public class PasswdEncryption {  

    private static final MessageDigest md;  

    private static final BASE64Encoder b64Encoder;  

      

    static{  

        try {  

            md = MessageDigest.getInstance(“MD5”, “SUN”);  

            b64Encoder = new BASE64Encoder();  

        } catch (Exception e) {  

            throw new RuntimeException(e);  

        }  

    }  

      

    /**

     * 检查密码

     * @param inputPasswd 用户输入的密码

     * @param storePasswd 已存储的密码

     * @return true:通过检查,false:未通过

     */  

     

    public static boolean checkPasswd(String inputPasswd, String storePasswd){  

        boolean ok = false;  

        try{  

            byte[] saltBys = storePasswd.substring(0,2).getBytes(“UTF-8”);  

            String inPwd = toPasswd(inputPasswd, saltBys);  

            ok = inPwd.equals(storePasswd);  

        }catch(Exception ex){  

            ex.printStackTrace();  

            ok = false;  

        }

        return ok;  

    }  

      

    /**

     * 将客户输入的密码加密

     * @param inputPasswd

     * @return

     */  

      

    public static String toPasswd(String inputPasswd){  

        byte[] salt = getSaltOfASCII(2);  

        return toPasswd(inputPasswd, salt);  

    }  

      

    /**

     * 将客户输入的密码加密

     * @param inputPasswd 客户输入的密码  

     * @param salt 盐

     * @return 加密后的字符串

     */  

    private static String toPasswd(String inputPasswd, byte[] salt){  

        String pwd = “”;  

        try{              

            md.reset();  

            md.update(salt);  

            md.update(inputPasswd.getBytes(“UTF-8”));  

            byte[] bys = md.digest();;  

            //1:AASLexNtFtI7e1IuQIg88ZNA==  

            //879:AA/lCM5NEwVQJ25YYomE1ldQ==  

            //1000:AARXKQat7z+/iu2w6KpKgLQA==  

              //for(int i=0; i<1000; i++){  

              //md.reset();  

              //bys = md.digest(bys);  

              //}            

            pwd += (char)salt[0];  

            pwd += (char)salt[1];  

            pwd += b64Encoder.encode(bys);            

        }catch(Exception ex){  

            ex.printStackTrace();  

            pwd = “”;  

        }  

        return pwd;  

    }  

      

    /**

     * 返回指定长度的盐(ASCII码)

     * @param len 长度

     * @return

     */  

    private static byte[] getSaltOfASCII(int len){  

        byte[] salt = new byte[len];  

        Random rand = new Random();  

        for(int i=0; i<len; i++){  

          //salt[i] = ‘A’;  

            salt[i] = (byte) ((rand.nextInt(‘~’-‘!’)+’!’) & 0x007f);  

        }

        return salt;  

    }  

}  

//测试类:

public class Test8 {  

    public static void main(String[] args){  

        t2();  

      //t1();  

    }  

      

    static void t2(){  

        String[] userPwds = {  

                “123456”,  

                “123456”,  

                “123456”,  

                “123456”,  

                “123456”,  

                “1234561”, //error input  

        };  

          

        //通过t1()得到  

        String[] dbPwds = {  

                “u:rkoqEBZ+IZlcugSyVkhNVg==”,  

                “vDEbVZ9JlSveGnB/Qdz69aAQ==”,  

                “hbgon/TjwH8s7YSuqVSDl9Yg==”,  

                “0-ExML8oTOSCeF3ETf1yvDHg==”,  

                “1TeHpWiXOhx5ilscC6D6G98g==”,  

                “1TeHpWiXOhx5ilscC6D6G98g==”,  

        };  

          

        String msg = “”;  

          

        for(int i=0,end=dbPwds.length; i<end; i++){  

            msg  = “user input passwd:”+userPwds[i];  

            msg += “,db store passwd:”+dbPwds[i];  

            msg += “,check passwd:”+PasswdEncryption.checkPasswd(userPwds[i],dbPwds[i]);  

              

            System.out.println(msg);  

        }  

    }  

      

    /**

     * 加密测试

     */  

    static void t1(){  

        String pwd = “123456”;  

        String pwd1 = null;//PasswdEncryption.toPasswd(pwd);  

          

        for(int i=0; i<5; i++){  

            pwd1 = PasswdEncryption.toPasswd(pwd);  

              

            System.out.println(pwd1);  

        }  

    }  

}  

t1()结果显示,在很小的情况下会出现相同的加密后密码,攻击者很难用一个简单SQL去查找同一密码的用户。

t2()则可以用同一个密码”123456″验证,多个加密后的密码。

java中的加解密之MD5和加盐详解编程语言

转载请注明来源网站:blog.ytso.com谢谢!

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/14722.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论