精华内容
下载资源
问答
  • MD5加密 MD5加盐

    2019-09-23 10:19:26
    MD5算法的原理可简要的叙述为:MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。...

    MD5算法的原理可简要的叙述为:MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

    (一):为什么要用哈希函数来加密密码

        1、如果开发者需要保存密码(比如网站用户的密码),要考虑如何保护这些密码数据,网站用户密码的泄露是一件非常严重的事情,容易引起用户恐慌,所以在安全方面是重中之重,直接将密码以明文写入数据库中是极不安全的,因为任何可以打开数据库的人,都将可以直接看到这些密码。

        2、解决的办法是将密码加密后再存储进数据库,比较常用的加密方法是使用哈希函数(Hash Function)。哈希函数的具体定义,网上和相关书籍中有很多,简单地说,它的特性如下:

        (1)原始密码经哈希函数计算后得到一个哈希值;

        (2)改变原始密码,哈希函数计算出的哈希值也会相应改变;

        (3) 同样的密码,哈希值也是相同的;

        (4) 哈希函数是单向、不可逆的。也就是说从哈希值,你无法推算出原始的密码是多少;

        有了哈希函数,我们就可以将密码的哈希值存储进数据库。用户登录网站的时候,我们可以检验用户输入密码的哈希值是否与数据库中的哈希值相同。由于哈希函数是不可逆的,即使有人打开了数据库,也无法看到用户的密码是多少。

        注:但不意味着存储经过哈希函数加密后的密码就是绝对的安全!

    (二):几种常见的破解密码的方法

        简单、常见的破解方式当属字典破解(Dictionary Attack)和暴力破解(Brute Force Attack)方式。

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

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

    (三):为密码加盐(Salt

        从查表法可以看出,即便是将原始密码加密后的哈希值存储在数据库中依然是不够安全的。那么有什么好的办法来解决这个问题呢?答案是加盐值(salt)

        盐(Salt)是什么?就是一个随机生成的字符串。我们将盐与原始密码连接(concat)在一起(放在前面或后面都可以),然后将concat后的字符串加密。采用这种方式加密密码,查表法就不灵了(因为盐是随机生成的);Salt这个值是由系统随机生成的,并且只有系统知道。即便两个用户使用了同一个密码,由于系统为它们生成的salt值不同,散列值也是不同的。

     

     


    Java实现

    package com.md5.demo;
    import java.math.BigInteger;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    /**
     * 普通的MD加密
     * @author peaceliu
     *
     */
    public class MD5Utils {
        /**
         * 使用md5的算法进行加密
         */
        public static String md5(String plainText) {
            byte[] secretBytes = null;
            try {
                secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException("没有md5这个算法!");
            }
            String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
            // 如果生成数字未满32位,需要前面补0
            for (int i = 0; i < 32 - md5code.length(); i++) {
                md5code += "0";
            }
            return md5code;
        }
        public static void main(String[] args) {
            System.out.println(md5("lhp"));
        }
    }

    MD5加盐 

    • 一般使用的加盐:
      md5(Password+UserName),即将用户名和密码字符串相加再MD5,这样的MD5摘要基本上不可反查。
      但有时候用户名可能会发生变化,发生变化后密码即不可用了(验证密码实际上就是再次计算摘要的过程)。
      ----------
    • 因此我们做了一个非常简单的加盐算法,每次保存密码到数据库时,都生成一个随机16位数字,将这16位数字和密码相加再求MD5摘要,然后在摘要中再将这16位数字按规则掺入形成一个48位的字符串。
    • 在验证密码时再从48位字符串中按规则提取16位数字,和用户输入的密码相加再MD5。按照这种方法形成的结果肯定是不可直接反查的,且同一个密码每次保存时形成的摘要也都是不同的。
    package com.md5.demo;
    import java.security.MessageDigest;
    import java.util.Random;
    import org.apache.commons.codec.binary.Hex;
    /**
     * MD5加盐加密
     */    
    public class PasswordUtil {
        /**
         * 生成含有随机盐的密码
         */
        public static String generate(String password) {
            Random r = new Random();
            StringBuilder sb = new StringBuilder(16);
            sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
            int len = sb.length();
            if (len < 16) {
                for (int i = 0; i < 16 - len; i++) {
                    sb.append("0");
                }
            }
            String salt = sb.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 new String(cs);
        }
        /**
         * 校验密码是否正确
         */
        public static boolean verify(String password, String md5) {
            char[] cs1 = new char[32];
            char[] cs2 = new char[16];
            for (int i = 0; i < 48; i += 3) {
                cs1[i / 3 * 2] = md5.charAt(i);
                cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
                cs2[i / 3] = md5.charAt(i + 1);
            }
            String salt = new String(cs2);
            return md5Hex(password + salt).equals(new String(cs1));
        }
        /**
         * 获取十六进制字符串形式的MD5摘要
         */
        public static String md5Hex(String src) {
            try {
                MessageDigest md5 = MessageDigest.getInstance("MD5");
                byte[] bs = md5.digest(src.getBytes());
                return new String(new Hex().encode(bs));
            } catch (Exception e) {
                return null;
            }
        }
    }

    测试

        public static void main(String[] args) {
            // 加密+加盐
            String password1 = generate("admin");
            System.out.println("结果:" + password1 + "   长度:"+ password1.length());
            // 解码
            System.out.println(verify("admin", password1));
            // 加密+加盐
            String password2= generate("admin");
            System.out.println("结果:" + password2 + "   长度:"+ password2.length());
            // 解码
            System.out.println(verify("admin", password2));
        }


    python

    md5加密

    >>> import hashlib
    >>> 
    >>> password = '123456789'
    >>> # 生成MD5对象
    >>> md5 = hashlib.md5()
    >>> # 对数据加密
    >>> md5.update(password.encode('utf-8'))
    >>> # 获取密文
    >>> pwd = md5.hexdigest()
    >>> 
    >>> print(pwd)
    25f9e794323b453885f5181f1b624d0b
    >>>
    

    md5加盐

    >>> import hashlib
    >>> # 生成MD5对象 并加盐
    >>> md5 = hashlib.md5(b'12345')
    >>> # 要加密的密码
    >>> password = '123456789'
    >>> # 对数据加密
    >>> md5.update(password.encode('utf-8'))
    >>> # 获取密文
    >>> pwd = md5.hexdigest()
    >>>
    >>> print(pwd)
    1664ef4c91b2efe3b444c5139e566666

    finally

    #---------------------------------------------------
    #   Python3简单密码加盐程序
    #   通过随机生成4位salt,与原始密码组合,通过md5加密
    #---------------------------------------------------
    #   导入哈希md5模块
    from hashlib import md5
    #   导入随机数模块
    from random import Random
    #   获取由4位随机大小写字母、数字组成的salt值
    def create_salt(length = 4):
      salt = ''
      chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
      #   获取chars的最大下标
      len_chars = len(chars)-1
      random = Random()
      for i in range(length):
      #   每次随机从chars中抽取一位,拼接成一个salt值
      salt += chars[random.randint(0,len_chars)]
        return salt
    
    #  获取原始密码+salt的md5值
    def create_md5(pwd,salt):
      md5_obj = md5()
      md5_obj.update((pwd+salt).encode('utf-8'))
      return md5_obj.hexdigest()
    
     #   随机密码
     pwd = input("请输入密码:")
     #   随机生成的4位salt
     salt = create_salt()
     #   加密后的密码
     md5_pwd = create_md5(pwd,salt)
                  
     # 输出效果如下
     请输入密码:123
     密码:123
     salt:DY6Z
     md5加密后的密码:3861786c18d0edce6dd6d446b9a33625

    暂时先写个这样,有的话再补充。

    展开全文
  • 一、项目背景  在使用HTTP协议传输文本,... 如果是验签,双方约定一个共同的盐值,针对要传输的字符串进行BASE64加盐加密,再对MD5进行加盐加密,即可保证安全性。 三、实现代码 3.1 base64加密工具类 import

    一、项目背景

     在使用HTTP协议传输文本,接入第三方接口时,同时需要一个验签环节,在数据库密码入库是也需要一个加密环节,为了提高安全性,可以采用BASE64加盐后再进行加密的算法。

    二,实现原理

     如果是验签,双方约定一个共同的盐值,针对要传输的字符串进行BASE64加盐加密,再对MD5进行加盐加密,即可保证安全性。

    三、实现代码

    3.1 base64加密工具类

    import com.lianqian.urs.common.enums.SignTypeEnum;
    import com.lianqian.urs.common.exception.ServiceException;
    import org.apache.commons.codec.binary.Base64;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.UnsupportedEncodingException;
    
    
    public class ArgsSignUtil {
    
    	private static final Logger LOGGER = LoggerFactory.getLogger(ArgsSignUtil.class);
    
    	/**
    	 * 待签名字符串等号符
    	 */
    	@SuppressWarnings("unused")
    	private static final String SIGN_EQUAL_CHAR = "=";
    	/**
    	 * 待签名字符串键值对连接符
    	 */
    	@SuppressWarnings("unused")
    	private static final String SIGN_JOINER_CHAR = "&";
    
    	/**
    	 * @Description: 验证签名
    	 */
    	public static boolean checkArgsSignByType(SignTypeEnum signType, String inputJons, String signKey, String sign) {
    		try {
    			String strToSign = genStrToSignByArgsJsonAndCid(inputJons, signKey, signType);
    			// rsa签名
    			if (SignTypeEnum.RSA.equals(signType)) {
    				LOGGER.debug("sign:" + sign);
    				LOGGER.debug("checksign-key:" + signKey);
    				return RSAAndDESUtils.verify(strToSign.getBytes("UTF-8"), signKey, sign.getBytes("UTF-8"));
    			} else if (SignTypeEnum.MD5.equals(signType)) {// md5签名(默认md5签名,非rsa签名即为md5签名)
    				String md5Sign = MessageDigest5.encrypt(strToSign, "UTF-8");
    				LOGGER.debug("接口请求md5签名:" + sign); 
    				LOGGER.debug("待md5签名字符串:" + strToSign);
    				LOGGER.debug("生成请求md5签名:" + md5Sign);
    				return sign.equalsIgnoreCase(md5Sign);
    			} else {
    				return false;
    			}
    		} catch (Exception e) {
    			LOGGER.error("验签失败:signType-{},data-{},signKey-{},sign-{}", signType, inputJons, signKey, sign, e);
    		}
    		return false;
    	}
    
    
    	public static boolean checkOpenApiSignByType(SignTypeEnum signType, String inputJson, String signKey, String sign) {
    		try {
    			String strToSign = genStrToSignForOpenApi(inputJson, signKey, signType);
    			// rsa签名
    			if (SignTypeEnum.RSA.equals(signType)) {
    				LOGGER.debug("三方签名:" + sign);
    				LOGGER.debug("签名公钥:" + signKey);
    				return RSAAndDESUtils.doCheck(strToSign, sign, signKey);
    			} else if (SignTypeEnum.MD5.equals(signType)) {
    				String md5Sign = MessageDigest5.encrypt(strToSign, "UTF-8");
    				LOGGER.debug("三方签名:" + sign);
    				LOGGER.debug("待md5签名字符串:" + strToSign);
    				LOGGER.debug("生成请求md5签名:" + md5Sign);
    				return sign.equalsIgnoreCase(md5Sign);
    			} else {
    				return false;
    			}
    		} catch (Exception e) {
    			LOGGER.error("验签失败:signType-{},data-{},signKey-{},sign-{}", signType, inputJson, signKey, sign, e);
    		}
    		return false;
    	}
    
    	/**
    	 * @Description: 生成待签名的字符串
    	 * @Author: panjl
    	 * @Since: 2014年11月5日上午11:18:45
    	 * @param inputJson
    	 *            业务参数json串
    	 * @param md5Key
    	 *            渠道签名key
    	 * @param signType
    	 * @return
    	 */
    	private static String genStrToSignByArgsJsonAndCid(String inputJson, String md5Key, SignTypeEnum signType) {
    
    		// 拼接要生成签名的字符串
    		StringBuilder strToSign = new StringBuilder();
    		strToSign.append(inputJson);
    		if (SignTypeEnum.MD5.equals(signType)) {
    			// 添加渠道md5签名key
    			strToSign.append(md5Key);
    		}
    		String result = strToSign.toString();
    		LOGGER.debug("生成待签名字符串0为:" + result);
    		return result;
    	}
    
    
    	public static String genStrToSignForOpenApi(String inputJson, String md5Key, SignTypeEnum signType) {
    
    		StringBuilder strToSign = new StringBuilder();
    		strToSign.append(inputJson);
    		if (SignTypeEnum.MD5.equals(signType)) {
    			strToSign.append(Base64.encodeBase64String(inputJson.getBytes()));
    			strToSign.append(md5Key);
    		}
    		String result = strToSign.toString();
    		LOGGER.debug("生成待签名字符串为:" + result);
    		return result;
    	}
    
    	/**
    	 * @Description: 根据签名类型生成签名
    	 */
    	public static String genSignByType(SignTypeEnum signType, String input, String signKey) throws UnsupportedEncodingException {
    		try {
    			String result = "";
    			String strToSign = genStrToSignByArgsJsonAndCid(input, signKey, signType);
    			if (SignTypeEnum.RSA.equals(signType)) {
    				result = RSAAndDESUtils.sign(strToSign.getBytes("UTF-8"), signKey);
    				//result = URLEncoder.encode(result, "UTF-8");
    			} else if (SignTypeEnum.MD5.equals(signType)) {
    				result = MessageDigest5.encrypt(strToSign, "UTF-8");
    			}
    			LOGGER.debug("sign-key:" + signKey);
    			LOGGER.debug("生成签名:" + result);
    			return result;
    		} catch (RuntimeException e) {
    			e.printStackTrace();
    			return "";
    		} catch (Exception e) {
    			throw new ServiceException(Constant.FAILED_OTHERS, "签名生成失败");
    		}
    	}
    }
    

     加密类型的枚举类

    public enum SignTypeEnum {
        MD5("MD5", 1, "MD5签名"), RSA("RSA", 10, "RSA签名");
        private String code;
        private Integer index;
        private String desc;
    
        private SignTypeEnum(String code, Integer index, String desc) {
            this.code = code;
            this.index = index;
            this.desc = desc;
        }
    
        /**
         * @Description: 获取默认的签名类型
         */
        public static SignTypeEnum getDefaultSignType() {
            return SignTypeEnum.MD5;
        }
    
        /**
         * @Description: 根据签名类型码获取签名类型
         * @Author: panjl
         * @Since: 2014年11月26日上午10:12:28
         * @param code
         * @return
         */
        public static SignTypeEnum getByCode(String code) {
            SignTypeEnum ret = null;
            for (SignTypeEnum signType : SignTypeEnum.values()) {
                if (signType.getCode().equals(code)) {
                    ret = signType;
                    break;
                }
            }
            return ret;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    
        /**
         * @return the index
         */
        public Integer getIndex() {
            return index;
        }
    
        /**
         * @param index
         *            the index to set
         */
        public void setIndex(Integer index) {
            this.index = index;
        }
    
    }

    3.2 MD5加密工具类
    public class MessageDigest5 {
    
    	public static String encrypt(String input) throws NoSuchAlgorithmException {
    		MessageDigest msgDigest = MessageDigest.getInstance("MD5");
    		msgDigest.update(input.getBytes());
    		return byteToHex(msgDigest.digest());
    	}
    
    	public static String encrypt(String input, String charset) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    		MessageDigest msgDigest = MessageDigest.getInstance("MD5");
    		msgDigest.update(input.getBytes(charset));
    		return byteToHex(msgDigest.digest());
    	}
    
    	public static String byteToHex(byte[] b) {
    		StringBuffer sBuffer = new StringBuffer();
    		for (int i = 0; i < b.length; i++) {
    			String sTemp = Integer.toHexString(b[i] & 0xFF);
    			if (sTemp.length() == 1)
    				sBuffer.append("0");
    			sBuffer.append(sTemp);
    		}
    		return sBuffer.toString();
    	}
    
    	public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    		
    		System.out.println(encrypt("{\"DomainOrderId\":\"nqDEvnInprf4WeYJrwt3gOBhdBFRey2o\",\"PolicyholderName\":\"托尔斯\",\"Birthday\":\"1987-09-09\",\"Mobile\":\"13438970025\"}ltdj_key", "UTF-8"));
    	}
    }
    3.3 调用方法

    					String blackUserJson = JSON.toJSONString(blackUserRecord);
    					String strToSign = ArgsSignUtil.genStrToSignForOpenApi(blackUserJson, Constant.BLACKUSER_MD5_KEY,
    							SignTypeEnum.getByCode(blackUserReq.getSignType()));
    					String md5Sign = MessageDigest5.encrypt(strToSign, Constant.ENCOD_CHARSET_UTF8);














     

    展开全文
  • Md5加密

    2017-10-29 15:28:54
    了解原理md5加密算法是不可逆的 也就是说是不能够通过解码来获取源来的字符串的 如果需要验证密码是否正确 需要对待验证的密码进行同样的MD5加密 然后和数据库中存放的加密后的结果进行对比类型 普通的md5 salt的...

    了解

    这里写图片描述

    原理

    md5加密算法是不可逆的 也就是说是不能够通过解码来获取源来的字符串的 如果需要验证密码是否正确 需要对待验证的密码进行同样的MD5加密 然后和数据库中存放的加密后的结果进行对比

    类型

    • 普通的md5
    • 加salt的md5 可以随机生成盐salt 然后和我们要加密的字符串进行拼接 之后再用md5进行加密 然后在拼接上我们刚刚的salt

    Java实现

    import java.io.IOException;
    import java.io.InputStream;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    /**
     * Author: Starry.Teng
     * Email: tengxing7452@163.com
     * Date: 17-10-10
     * Time: 下午9:27
     * Describe: MD5加密工具类
     */
    public class MD5Util {
    
        /**
         * 普通md5加密
         * @param text
         * @return
         */
        public static String getMD5(String text){
            try {
                MessageDigest digest = MessageDigest.getInstance("md5");
                byte[] buffer = digest.digest(text.getBytes());
                // byte -128 ---- 127
                StringBuffer sb = new StringBuffer();
                for (byte b : buffer) {
                    int a = b & 0xff;
                    // Log.d(TAG, "" + a);
                    String hex = Integer.toHexString(a);
    
                    if (hex.length() == 1) {
                        hex = 0 + hex;
                    }
                    sb.append(hex);
                }
                return sb.toString();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * md5加密+salt
         * @param text
         * @return
         */
        public static String getMD5(String text,String salt){
            try {
                 return getMD5(getMD5(text)+getMD5(salt)); //分别加密在加密
            }catch (Exception e){
                e.printStackTrace();
            }
            return "";
        }
        /**
         * 任意文件转换成Md5
         * @param in
         * @return
         */
        public static String getMD5(InputStream in) {
            try {
                MessageDigest digester = MessageDigest.getInstance("MD5");
                byte[] bytes = new byte[8192];
                int byteCount;
                while ((byteCount = in.read(bytes)) > 0) {
                    digester.update(bytes, 0, byteCount);
                }
                byte[] digest = digester.digest();
    
                // byte -128 ---- 127
                StringBuffer sb = new StringBuffer();
                for (byte b : digest) {
                    int a = b & 0xff;
                    String hex = Integer.toHexString(a);
    
                    if (hex.length() == 1) {
                        hex = 0 + hex;
                    }
    
                    sb.append(hex);
                }
    
                return sb.toString();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    in = null;
                }
            }
            return null;
        }
    
        public static String decrypt(){
            return null;
        }
    
        // 测试主函数
        public static void main(String args[]) {
            String s = new String("tengxing");
            System.out.println(getMD5(s));
            System.out.println(getMD5("同学"));
            System.out.println(getMD5(s+"同学"));
    
        }
    
    
    }
    展开全文
  • MD5加盐加密

    2017-09-03 18:12:25
    结果就是一种加密算法,其原理还是很简单的:盐(Salt),在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。 以上这句话是维基...

    刚开始师兄给我说这个东西的时候还以为是什么很高级的东西,结果就是一种加密算法,其原理还是很简单的:

    盐(Salt),在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。
    以上这句话是维基百科上对于 Salt 的定义,但是仅凭这句话还是很难理解什么叫 Salt,以及它究竟起到什么作用。

    第一代密码

    早期的软件系统或者互联网应用,数据库中设计用户表的时候,大致是这样的结构:

    mysql> desc User;
    +———-+————–+——+—–+———+——-+
    | Field | Type | Null | Key | Default | Extra |
    +———-+————–+——+—–+———+——-+
    | UserName | varchar(50) | NO | | | |
    | PassWord | varchar(150) | NO | | | |
    +———-+————–+——+—–+———+——-+
    数据存储形式如下:

    mysql> select * from User;
    +———-+———-+
    | UserName | PassWord |
    +———-+———-+
    | lichao | 123 |
    | akasuna | 456 |
    +———-+———-+
    主要的关键字段就是这么两个,一个是登陆时的用户名,对应的一个密码,而且那个时候的用户名是明文存储的,如果你登陆时用户名是 123,那么数据库里存的就是 123。这种设计思路非常简单,但是缺陷也非常明显,数据库一旦泄露,那么所有用户名和密码都会泄露,后果非常严重。参见 《CSDN 详解 600 万用户密码泄露始末》。

    第二代密码

    为了规避第一代密码设计的缺陷,聪明的人在数据库中不在存储明文密码,转而存储加密后的密码,典型的加密算法是 MD5 和 SHA1,其数据表大致是这样设计的:

    mysql> desc User;
    +———-+————–+——+—–+———+——-+
    | Field | Type | Null | Key | Default | Extra |
    +———-+————–+——+—–+———+——-+
    | UserName | varchar(50) | NO | | | |
    | PwdHash | char(32) | NO | | | |
    +———-+————–+——+—–+———+——-+
    数据存储形式如下:

    mysql> select * from User;
    +———-+———————————-+
    | UserName | PwdHash |
    +———-+———————————-+
    | lichao | 202cb962ac59075b964b07152d234b70 |
    | akasuna | 250cf8b51c773f3f8dc8b4be867a9a02 |
    +———-+———————————-+
    假如你设置的密码是 123,那么数据库中存储的就是 202cb962ac59075b964b07152d234b70 或 40bd001563085fc35165329ea1ff5c5ecbdbbeef。当用户登陆的时候,会把用户输入的密码执行 MD5(或者 SHA1)后再和数据库就行对比,判断用户身份是否合法,这种加密算法称为散列。

    严格地说,这种算法不能算是加密,因为理论上来说,它不能被解密。所以即使数据库丢失了,但是由于数据库里的密码都是密文,根本无法判断用户的原始密码,所以后果也不算太严重。

    第三代密码

    本来第二代密码设计方法已经很不错了,只要你密码设置得稍微复杂一点,就几乎没有被破解的可能性。但是如果你的密码设置得不够复杂,被破解出来的可能性还是比较大的。

    好事者收集常用的密码,然后对他们执行 MD5 或者 SHA1,然后做成一个数据量非常庞大的数据字典,然后对泄露的数据库中的密码就行对比,如果你的原始密码很不幸的被包含在这个数据字典中,那么花不了多长时间就能把你的原始密码匹配出来。这个数据字典很容易收集,CSDN 泄露的那 600w 个密码,就是很好的原始素材。

    于是,第三代密码设计方法诞生,用户表中多了一个字段:

    mysql> desc User;
    +———-+————-+——+—–+———+——-+
    | Field | Type | Null | Key | Default | Extra |
    +———-+————-+——+—–+———+——-+
    | UserName | varchar(50) | NO | | | |
    | Salt | char(50) | NO | | | |
    | PwdHash | char(32) | NO | | | |
    +———-+————-+——+—–+———+——-+
    数据存储形式如下:

    mysql> select * from User;
    +———-+—————————-+———————————-+
    | UserName | Salt | PwdHash |
    +———-+—————————-+———————————-+
    | lichao | 1ck12b13k1jmjxrg1h0129h2lj | 6c22ef52be70e11b6f3bcf0f672c96ce |
    | akasuna | 1h029kh2lj11jmjxrg13k1c12b | 7128f587d88d6686974d6ef57c193628 |
    +———-+—————————-+———————————-+
    Salt 可以是任意字母、数字、或是字母或数字的组合,但必须是随机产生的,每个用户的 Salt 都不一样,用户注册的时候,数据库中存入的不是明文密码,也不是简单的对明文密码进行散列,而是 MD5( 明文密码 + Salt),也就是说:

    MD5(‘123’ + ‘1ck12b13k1jmjxrg1h0129h2lj’) = ‘6c22ef52be70e11b6f3bcf0f672c96ce’
    MD5(‘456’ + ‘1h029kh2lj11jmjxrg13k1c12b’) = ‘7128f587d88d6686974d6ef57c193628’
    当用户登陆的时候,同样用这种算法就行验证。

    由于加了 Salt,即便数据库泄露了,但是由于密码都是加了 Salt 之后的散列,坏人们的数据字典已经无法直接匹配,明文密码被破解出来的概率也大大降低。

    是不是加了 Salt 之后就绝对安全了呢?淡然没有!坏人们还是可以他们数据字典中的密码,加上我们泄露数据库中的 Salt,然后散列,然后再匹配。但是由于我们的 Salt 是随机产生的,假如我们的用户数据表中有 30w 条数据,数据字典中有 600w 条数据,坏人们如果想要完全覆盖的坏,他们加上 Salt 后再散列的数据字典数据量就应该是 300000* 6000000 = 1800000000000,一万八千亿啊,干坏事的成本太高了吧。但是如果只是想破解某个用户的密码的话,只需为这 600w 条数据加上 Salt,然后散列匹配。可见 Salt 虽然大大提高了安全系数,但也并非绝对安全。

    实际项目中,Salt 不一定要加在最前面或最后面,也可以插在中间嘛,也可以分开插入,也可以倒序,程序设计时可以灵活调整,都可以使破解的难度指数级增长。

    PS,文中所谓第一、二、三代密码的称呼,是我自己 YY 的。

    转载自:为什么要在密码里加点“盐”

    如果什么事md5的话可以看看imooc的课程:
    PHP加密技术专题
    1-2 md5信息加密算法 (16:16)
    虽然用的是php语言讲解的,但还是十分易懂的

    最后附上一段可运行的MD5算法和MD5加盐算法:

    public class md5 {
    
    MD5加密算法:
    
    //    public static String getMD5(String str) {
    //        try {
    //            // 生成一个MD5加密计算摘要
    //            MessageDigest md = MessageDigest.getInstance("MD5");
    //            // 计算md5函数
    //            md.update(str.getBytes());
    //            // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
    //            // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
    //            return new BigInteger(1, md.digest()).toString(16);
    //        } catch (Exception e) {
    //            System.out.println("MD5加密出现错误");
    //        }
    //        return str;
    //    }
    
        public static void main(String[] args) {
            String pwd="password";
            //MD5加盐算法:
            System.out.println(getMD5WithSalt(pwd));
        }
    
    
        /**
         * MD5加密工具类
         */
    
            /**
             * 获取MD5字符串
             */
            public static String getMD5(String content) {
                try {
                    MessageDigest digest = MessageDigest.getInstance("MD5");
                    digest.update(content.getBytes());
                    return getHashString(digest);
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            private static final String SALT = "0fdfa5e5a88bebae640a5d88e7c84708";
    
            /**
             * 获取加盐的MD5字符串
             */
            public static String getMD5WithSalt(String content) {
                return getMD5(getMD5(content) + SALT);
            }
    
            private static String getHashString(MessageDigest digest) {
                StringBuilder builder = new StringBuilder();
                for (byte b : digest.digest()) {
                    builder.append(Integer.toHexString((b >> 4) & 0xf));
                    builder.append(Integer.toHexString(b & 0xf));
                }
                return builder.toString();
            }
    
    }
    展开全文
  • 今天简单的讲一讲–Java使用MD5算法加密, 支持加盐。 为什么要使用MD5算法加密加盐? 盐被称作“Salt值”,这个值是由系统随机生成的,并且只有系统知道。即便两个用户使用了同一个密码,由于系统为它们生成的...
  • MD5+salt盐加密

    2019-09-19 10:14:23
    MD5算法的原理可简要的叙述为:MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。...
  • 文章目录系列文章目录MD5登录MD5加密MD5加盐EasyUI提示框和下拉菜单提示框下拉框登录退出功能切换皮肤的研究 MD5登录 MD5加密 我们在项目中,数据库中存储密码一般是不存储明文的,否则很不安全 一般使用MD5加密 MD5...
  • MD5加密简介

    2020-10-26 14:11:00
    目录特点关于撞库破解关于MD5加盐算法原理 MD5全称:message-digest algorithm 5 翻译过来就是:信息 摘要 算法 5 特点 长度固定: 不管多长的字符串,加密后长度都是一样长 作用:方便平时信息的统计和管理 易计算: ...
  • Python实现md5二次及多次加盐加密

    千次阅读 2018-10-22 15:30:07
    在第一次md5加密后,再加盐进行二次md5加密 用处: 一般用在密码,交易密码之类的密码安全和验证(将前端传入的密码参数进行md5(md5()+salt)加密与数据库中保存的数据进行对比,如果相同则密码验证成功, 银行的...
  • MD5盐值加密

    2016-06-12 16:55:47
    盐值加密-MD5 博客分类:  加密技术   什么叫盐值加密 Spring security怎样进行盐值加密  ...以前的md5原理是  ...密码密文=md5算法(密码明文);...加盐(盐值加密)的算法很多  Spring security用
  • 经常说的“MD5加密”,就是它→信息-摘要算法。 在下载一些东西时,经常在一些压缩包属性里,看到md5值。而且这个下载页面,很可能会在某一个地方,写了一句,此文件的MD5值为XXXXXXXXX。这有什么作用呢? 白话...
  • 此外,为避免加密过的字符串被破解我们有时候需要对发送的字符串进行加盐处理即在原有字符串的基础上再拼接一串字符串,然后在进行md5加密处理。 动态密码加密的原理类似上面提到的加盐处理,即每次在发送给服务器...
  • 盐值加密-MD5

    2014-08-28 12:36:00
    盐值加密-MD5 什么叫盐值加密 Spring security怎样进行盐值加密 以前的md5原理是 ...密码密文=md5算法(密码明文)...加盐(盐值加密)的算法很多 Spring security用的是: 密码密文=md5算法(密码明文...
  • BCrypt加密:是一种加盐的加密方法,MD5加密时候,同一个密码经过hash的时候生成的是同一个hash值,在大数据的情况下,有些经过md5加密的方法将会被破解.使用BCrypt进行加密,同一个密码每次生成的hash值都是不相同...
  • 加盐哈希

    千次阅读 2018-09-02 00:18:06
    md5已经是一种十分安全的加密方法了,但是通过彩虹表依旧可以破解(彩虹表原理),那么我们伟大机智的程序员们就想出了在密码后一段序列然后再md5加密的方法,这个后面加上的序列就是所谓的 “ ” 。...
  •  总结一句话就是:以前直接用密码明文简单的MD5加密一下已经不安全了!需要加盐!加随机的盐!加长长的盐!  链接在此:http://blog.sibo.me/2014/05/14/hashing-security.html  如果不想看长篇大论,最后的...
  • MD5校验值

    千次阅读 2018-08-25 20:38:48
    MD5加盐 MD5是什么? MD5:全称是Message Digest Algorithm 5,译为“消息摘要算法第5版” 原理、效果与特点 原理:文件”指纹” 世界上没有两个完全一模一样的指纹(不同的文件加密之后,不会出现两个一样...
  • 密码加密的算法

    千次阅读 2015-07-05 02:34:05
    加密原理:采用不同的加密算法对字符串进行加盐加密处理。 用以防止密文被md5字典进行反向暴力破解。 采用美国家安全局公布的加密算法(RFC 4357)加密,不采用自己创建的加密算法,以避免有安全漏洞。
  • password加密的算法

    2017-07-01 21:03:00
    加密原理:採用不同的加密算法对字符串进行加盐加密处理。 用以防止密文被md5字典进行反向暴力破解。 採用美国家安全局发布的加密算法(RFC 4357)加密,不採用自己创建的加密算法,以避免有安全漏洞。 下面是基于...
  • hmac算法是加密的hash算法,它需要一个hash算法(比如sha256获取md5等)和一个密匙key,在hash计算的过程中将密匙key混入,产生一个和原来hash算法相同位数的hash值。 在大多数情况下,我们甚至可以将hamc算法看做是...
  • 对于大部分商城类项目来说 加密都是一个比较头疼的事情了 我采用的加密相对来说是比较安全的了 拥有RSA和MD5的加签比对 还有加盐处理 不过这次我只讲加密处理的框架级思想 对于加密算法与比对 还是大家自己去...
  • 然后数据库是 加盐加密算法,加 salt 配合 md5, 因为帮亲戚写网页,框架原理什么的还不是很懂,调试这能用,先记在这,以后读源码,写项目再回这参考 配置类: package com.ywfcake.demo.config; import ...
  • Spring Security 中的盐值加密

    千次阅读 2011-12-07 10:52:07
     在 Spring Security 文档中有这么一句话: "盐值的原理非常简单,就是先把密码和盐值指定的内容合并在一起,再使用md5对合并后的内容进行演算,这样一来,就算密码是一个很常见的字符串,再加上用户名,最后算出来...
  • 4.MySQL

    2021-03-01 09:29:51
    MD5破解网站的原理,背后有一个字典,MD5加密前的值,加密后的值 加盐 加密 先加盐,在加密 加密加盐流程: 用户输入明文密码后,后台生成盐值,再将盐值与明文密码拼接,然后将拼接后的结果进行加密,生成密...
  • java常用加密算法之pbkdf2

    千次阅读 2018-08-20 11:51:29
     常见的加密算法,如MD5,此类算法为单向的,无法通过逆向破解,但由于技术的不断进步,可以通过字典和暴力破解。后来人们通过加盐来增加密码的安全性,但彩虹表的出现让这种方式也变得不安全。以至于出现了现在的...
  • POST请求方式一定程度下保证了安全性,即在url上看不到参数,但可以在浏览器开发者工具中可以看到参数,为防止篡改,则可以采用一些加密协议,如:https、加签名、加密手段(MD5加盐、base64、DES、sha1)等。...

空空如也

空空如也

1 2
收藏数 40
精华内容 16
关键字:

md5加密加盐原理