5. 单向散列函数

"单向散列函数 --- 获取消息的指纹"

5.1 什么是单向散列函数

28.密码学知识-hash函数-5——2019年12月19日-LMLPHP

28.密码学知识-hash函数-5——2019年12月19日-LMLPHP

5.2 关于术语

5.3 单向散列函数的性质

  • 根据任意长度的消息计算出固定长度的散列值

  • 能够快速计算出散列值

  • 消息不同散列值也不同

    28.密码学知识-hash函数-5——2019年12月19日-LMLPHP

    28.密码学知识-hash函数-5——2019年12月19日-LMLPHP

  • 具备单向性

    28.密码学知识-hash函数-5——2019年12月19日-LMLPHP

5.4 单向散列函数的实际应用

5.4.1 检测软件是否被篡改

28.密码学知识-hash函数-5——2019年12月19日-LMLPHP

5.4.2 消息认证码

5.4.3 数字签名

5.4.6 伪随机数生成器

5.4.7 一次性口令

5.5 常用的单向散列函数

5.5.1 MD4、MD5

5.5.2 Go中使用MD5

  • 需要导入的包

    import (
    "crypto/md5"
    "encoding/hex"
    )
  • 计算Md5的方式1

    func getMD5_1(str []byte) string {
    // 1. 计算数据的md5
    result := md5.Sum(str)
    fmt.Println(result)
    fmt.Printf("%x\n", result)
    // 2. 数据格式化为16进制格式字符串
    res := fmt.Sprintf("%x", result)
    fmt.Println(res)
    // --- 这是另外一种格式化切片的方式
    res = hex.EncodeToString(result[:])
    fmt.Println("res: ", res)
    return res
    }

    重要函数说明:

    1. 返回数据data的MD5校验和

      函数所属的包: "crypto/md5"
      func Sum(data []byte) [Size]byte
      - 参数 data: 原始数据
      - 返回值: 经过md5计算之后得到的数据, 长度为 16字节(byte)
    2. 将字符串编码为16进制格式

      函数所属的包: "encoding/hex"
      func EncodeToString(src []byte) string
      - 参数 src: 要转换的数据
      - 返回值: 转换之后得到的16进制格式字符串
  • 计算Md5的方式2

    func getMD5_2(str []byte) string {
    // 1. 创建一个使用MD5校验的Hash对象`
    myHash := md5.New()
    // 2. 通过io操作将数据写入hash对象中
    io.WriteString(myHash, "hello")
    //io.WriteString(myHash, ", world")
    myHash.Write([]byte(", world"))
    // 3. 计算结果
    result := myHash.Sum(nil)
    fmt.Println(result)
    // 4. 将结果转换为16进制格式字符串
    res := fmt.Sprintf("%x", result)
    fmt.Println(res)
    // --- 这是另外一种格式化切片的方式
    res = hex.EncodeToString(result)
    fmt.Println(res) return res
    }

    重要函数说明:

    1. 创建一个新的使用MD5校验的hash.Hash接口

      函数所属的包: "crypto/md5"
      func New() hash.Hash

      Hash是一个被所有hash函数实现的公共接口。

      type Hash interface {
      // 通过嵌入的匿名io.Writer接口的Write方法向hash中添加更多数据,永远不返回错误
      io.Writer
      // 返回添加b到当前的hash值后的新切片,不会改变底层的hash状态
      Sum(b []byte) []byte
      // 重设hash为无数据输入的状态
      Reset()
      // 返回Sum会返回的切片的长度
      Size() int
      // 返回hash底层的块大小;Write方法可以接受任何大小的数据,
      // 但提供的数据是块大小的倍数时效率更高
      BlockSize() int
      } "io" 包中 Writer 接口用于包装基本的写入方法。
      type Writer interface {
      Write(p []byte) (n int, err error)
      }
    2. 通过io操作将数据写入hash对象中

      # 第一种方式
      函数所属的包: "io"
      func WriteString(w Writer, s string) (n int, err error)
      - 参数 w: 实现了/包含Writer接口的对象
      - 参数 s: 要添加到IO对象中的数据
      - 返回值 n: 数据长度
      - 返回值 err: 错误信息
      # 第二种方式
      使用md5包中的New()方法得到的hash.Hash接口(假设名为: myHash)添加数据
      myHash.Write([]byte("测试数据"))
    3. 使用hash.Hash接口中的Sum方法计算结果

      Sum(b []byte) []byte
      - 参数 b: 将b中的数据进行哈希计算, 结果添加到原始数据的前面,
      一般情况下该参数指定为空, 即: nil
      - 返回值: 进行哈希运算之后得到的结果

5.5.3 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512

MD4128bit16byte
MD5128bit16byte
SHA-1160bit20byte
SHA-224224bit28byte
SHA-256256bit32byte
SHA-384384bit48byte
SHA-512512bit64byte

5.5.4 Go中对SHA-1、SHA-2的使用

  • 需要导入的包

    import (
    "crypto/sha1"
    "encoding/hex"
    "crypto/sha256"
    "crypto/sha512"
    )
  • 使用sha1计算文件指纹

    func getSha1(src string) string {
    // 1. 打开文件
    fp, err := os.Open(src)
    if err != nil {
    return "文件打开失败"
    }
    // 2. 创建基于sha1算法的Hash对象
    myHash := sha1.New()
    // 3. 将文件数据拷贝给哈希对象
    num, err := io.Copy(myHash, fp)
    if err != nil {
    return "拷贝文件失败"
    }
    fmt.Println("文件大小: ", num)
    // 4. 计算文件的哈希值
    tmp1 := myHash.Sum(nil)
    // 5. 数据格式转换
    result := hex.EncodeToString(tmp1)
    fmt.Println("sha1: ", result) return result
    }
05-11 17:44