加密:MD5?SHA-256?哈希值?MD5加盐?

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

为什么要用哈希函数来加密密码——哈希函数是单向、不可逆的
哈希函数:把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值

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

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

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

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

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

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

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

注:但不意味着存储经过哈希函数加密后的密码就是绝对的安全!
    
单向不可逆的理解:比如我知道MD5加盐加密后的密码,但我无法通过加密密码推算你的原始密码长什么样,因为加密后的值原始信息是残缺的。

MD5、sha1、sha256 都是 不同的哈希函数

美国政府以前广泛采用SHA-1算法,在2005年被我国山东大学的王小云教授发现了安全漏洞,所以现在比较常用SHA-1加长的变种,比如SHA-256。

MD5密码数据库的数据量已经非常庞大了,大部分常用密码都可以通过MD5摘要反向查询到密码明文。
所以为了安全,一般会用 MD5加盐。

盐是什么?
对每个用户,系统在保存密码时,会随机生成一个16位的随机数,拼接在用户密码前或后,进行MD5加密,生成摘要。再按规则(可能是插在摘要前,也可能插再摘要第13位后等)插入到摘要,形成48位数字符串——————每个用户的“盐”都不同。

校验密码的过程,是通过用户名,查找对应的加密密码,按规则提取出16位随机数(“盐”),再按照 密码+盐 再MD5加密的方式生成 摘要。再按规则插入16位的盐。 如果得到的产物与用户表密码一致。则用户校验通过。

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
————————————————
版权声明:本文代码参考CSDN博主「叮叮叮会过去的」的原创文章
原文链接:https://blog.csdn.net/chending_cd/article/details/101195375

 类似资料: