惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
S
Securelist
P
Proofpoint News Feed
D
DataBreaches.Net
Cisco Talos Blog
Cisco Talos Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Project Zero
Project Zero
A
About on SuperTechFans
罗磊的独立博客
WordPress大学
WordPress大学
月光博客
月光博客
Latest news
Latest news
C
Cyber Attacks, Cyber Crime and Cyber Security
GbyAI
GbyAI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 三生石上(FineUI控件)
F
Fortinet All Blogs
W
WeLiveSecurity
Attack and Defense Labs
Attack and Defense Labs
V
Visual Studio Blog
Blog — PlanetScale
Blog — PlanetScale
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Privacy International News Feed
AI
AI
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Stack Overflow Blog
Stack Overflow Blog
M
MIT News - Artificial intelligence
Help Net Security
Help Net Security
T
Tor Project blog
V
Vulnerabilities – Threatpost
C
Cisco Blogs
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
MyScale Blog
MyScale Blog
雷峰网
雷峰网
MongoDB | Blog
MongoDB | Blog
Forbes - Security
Forbes - Security
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
T
Threat Research - Cisco Blogs
B
Blog RSS Feed
博客园 - 叶小钗
N
News and Events Feed by Topic
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Simon Willison's Weblog
Simon Willison's Weblog
C
CERT Recently Published Vulnerability Notes
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
N
News and Events Feed by Topic

山山仙人博客

自己动手实现NAS公网访问 我的2024-2025 个人养老金年化收益计算 Apple Container实践 Mermaid 语法概要 组建WireGuard网络 使用GitHub存储Helm包 详解Nginx获取客户端真实IP 生如夏花——与技术人的精神远游 Ack集群Pod独占EIP实践 我的2022-2023 Gradle打包工具入门 基于阿里云RAM+ACK托管版集群的RBAC授权 服务网格和Istio初识-续 服务网格和Istio初识 2021总结与公众号文章回顾 Golang与非对称加密 Ack集群Terway网络场景下的vSwitch扩容 Golang与对称加密
Golang与散列算法
2021-12-17 · via 山山仙人博客

golang

散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度。加密性强的散列一定是不可逆的,这就意味着通过散列结果,无法推出任何部分的原始信息。任何输入信息的变化,哪怕仅一位,都将导致散列结果的明显变化,这称之为雪崩效应。散列还应该是防冲突的,即找不出具有相同散列结果的两条信息。具有这些特性的散列结果就可以用于验证信息是否被修改。常用于保证数据完整性

单向散列函数一般用于产生消息摘要,密钥加密等,常见的有

  • MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种单向散列算法
  • SHA(Secure Hash Algorithm):可以对任意长度的数据运算生成一个160位的数值

哈希函数不是加密算法,其特征为单向性和唯一性

具体如下

  • 输入可以是任意长度
  • 输出是固定长度
  • 根据输入很容易计算出输出
  • 根据输出很难计算出输入(几乎不可能)
  • 两个不同的输入几乎不可能得到相同的输出

https://golang.google.cn/pkg/crypto/sha1/

1993年,安全散列算法(SHA)由美国国家标准和技术协会(NIST)提出,并作为联邦信息处理标准(FIPS PUB 180)公布;1995年又发布了一个修订版FIPS PUB 180-1,通常称之为SHA-1SHA-1是基于MD4算法的,并且它的设计在很大程度上是模仿MD4的。现在已成为公认的最安全的散列算法之一,并被广泛使用

SHA-1是一种数据加密算法,该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程 该算法输入报文的最大长度不超过264位,产生的输出是一个160位的报文摘要。输入是按512位的分组进行处理的。SHA-1是不可逆的、防冲突,并具有良好的雪崩效应

sha1SHA家族的五个算法之一(其它四个是SHA-224SHA-256SHA-384,和SHA-512)

SHA(Secure Hash Algorithm)安全散列算法,是一系列密码散列函数,有多个不同安全等级的版本:SHA-1,SHA-224,SHA-256,SHA-384,SHA-512

防伪装,防窜扰,保证信息的合法性和完整性

算法流程:

  • 填充,使得数据长度对512求余的结果为448

  • 在信息摘要后面附加64bit,表示原始信息摘要的长度

  • 初始化h0h4,每个h都是32

  • h0h4历经80轮复杂的变换

  • h0h4拼接起来,构成160位,返回

常用函数

  • New:创建Hash对象用于计算字节/字符sha1
  • Sum:计算字节切片sha1

package main

import (

"crypto/sha1"

"fmt"

)

func main() {

data := []byte("This page intentionally left blank.")

fmt.Printf("%x\n", sha1.Sum(data))

}

sha256sha512同理

使用示例

package main

import (

"crypto/sha1"

"fmt"

"io"

)

// sha1散列算法

func sha1Hash(msg string) (hashData []byte) {

h := sha1.New()

io.WriteString(h, msg)

hashData = h.Sum(nil)

return

}

func main() {

msg := "This is the message to hash!"

// sha1

sha1Data := sha1Hash(msg)

fmt.Printf("SHA1: %x\n", sha1Data)

}

https://golang.google.cn/pkg/crypto/md5/

MD5Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2MD3MD4

  • 算法流程跟SHA-1大体相似

  • MD5的输出是128位,比SHA-1短了32

  • MD5相对易受密码分析的攻击,运算速度比SHA-1

常用函数

  • New:创建Hash对象用于计算字节/字符md5

  • Sum:计算字节切片md5

import (

"crypto/md5"

"fmt"

)

func main() {

// 最基础的使用方式: Sum 返回数据的MD5校验和

fmt.Printf("%x\n", md5.Sum([]byte("测试数据")))

}

基本使用-直接计算

package main

import (

"crypto/md5"

"encoding/hex"

"fmt"

)

func main() {

// 结果是byte类型的数组

bytes := md5.Sum([]byte("i am geek"))

// 转换为32位小写

fmt.Printf("%x\n", bytes) // 397f77c74db1e25084653531a8046f21

// 转换为字符串

x := fmt.Sprintf("%x\n", bytes)

fmt.Println(x) // 397f77c74db1e25084653531a8046f21

fmt.Println(hex.EncodeToString(bytes[:])) // 397f77c74db1e25084653531a8046f21

}

大量数据-散列计算

package main

import (

"crypto/md5"

"fmt"

)

func main() {

// 较大时,分开批量计算

m := md5.New()

m.Write([]byte("i am"))

m.Write([]byte(" geek"))

fmt.Printf("%x\n", m.Sum(nil)) // 397f77c74db1e25084653531a8046f21

}

因为二者均由MD4导出,SHA-1MD5彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:

  • 对强行供给的安全性:最显著和最重要的区别是SHA-1摘要比MD5摘要长32位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD52128数量级的操作,而对SHA-1则是2160数量级的操作。这样,SHA-1对强行攻击有更大的强度。
  • 对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1显得不易受这样的攻击。
  • 速度:在相同的硬件上,SHA-1的运行速度比MD5

https://golang.google.cn/pkg/crypto/hmac/

Hmac算法也是一种哈希算法,它可以利用MD5SHA1等哈希算法。不同的是,Hmac还需要一个密钥, 只要密钥发生了变化,那么同样的输入数据也会得到不同的签名,因此,可以把Hmac理解为用随机数“增强”的哈希算法

常用函数

  • New:创建Hash对象用于计算字节/字符hmac
  • Equal:比较hmac值是否相等

Hs256实现

package main

import (

"crypto/hmac"

"crypto/sha256"

"fmt"

"io"

)

func main() {

key := []byte("1234567890abcdefg")

// 创建hmac hash对象

hash := hmac.New(sha256.New, key)

// 写入字符串计算散列

io.WriteString(hash, "hi,geek")

// 计算hmac散列

fmt.Printf("%x\n", hash.Sum(nil)) // 89fda53d5e71e8c87adb15f8bf11c2c931af019a5c040321e243b82a3bb45ee5

hash2 := hmac.New(sha256.New, key)

hash2.Write([]byte("hi,geek"))

fmt.Println(hmac.Equal(hash2.Sum(nil), hash.Sum(nil))) // true

}

使用示例

package main

import (

"crypto/hmac"

"fmt"

"io"

)

// 使用sha1的Hmac散列算法

func hmacHash(msg string, key string) (hashData []byte) {

k := []byte(key)

mac := hmac.New(sha1.New, k)

io.WriteString(mac, msg)

hashData = mac.Sum(nil)

return

}

func main() {

msg := "This is the message to hash!"

// hmac

hmacData := hmacHash(msg, "The key string!")

fmt.Printf("HMAC: %x\n", hmacData)

}

  • 用户密码的存储

  • 文件上传/下载完整性校验

  • mysql大字段的快速对比

  • 数字签名(区块链,比特币)

示例代码

package main

import (

"crypto/md5"

"crypto/sha1"

"encoding/hex"

"fmt"

)

func Sha1(data string) string {

sha1 := sha1.New()

sha1.Write([]byte(data))

return hex.EncodeToString(sha1.Sum(nil))

}

func Md5(data string) string {

md5 := md5.New()

md5.Write([]byte(data))

return hex.EncodeToString(md5.Sum(nil))

}

func main() {

data := "abcdefg"

fmt.Printf("SHA-1: %s\n", Sha1(data))

fmt.Printf("MD5: %s\n", Md5(data))

}

一个实际的例子,用户名密码校验

密码校验则是一个很常见的问题, 当我们设计用户中心时,是一个必不可少的功能, 为了安全,我们都不会保存用户的明文密码, 最好的方式就是保存为Hash, 这样即使是数据泄露了,也不会导致用户的明文密码泄露(hash的过程是不可逆的)

示例需求如下

  • 能校验密码
  • 用户可以修改密码
  • 修改密码时,禁止使用最近已经使用过的密码

// NewHashedPassword 生产hash后的密码对象

func NewHashedPassword(password string) (*Password, error) {

bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10)

if err != nil {

return nil, err

}

return &Password{

Password: string(bytes),

CreateAt: ftime.Now().Timestamp(),

UpdateAt: ftime.Now().Timestamp(),

}, nil

}

type Password struct {

// hash过后的密码

Password string

// 密码创建时间

CreateAt int64

// 密码更新时间

UpdateAt int64

// 密码需要被重置

NeedReset bool

// 需要重置的原因

ResetReason string

// 历史密码

History []string

// 是否过期

IsExpired bool

}

// Update 更新密码

func (p *Password) Update(new *Password, maxHistory uint, needReset bool) {

p.rotaryHistory(maxHistory)

p.Password = new.Password

p.NeedReset = needReset

p.UpdateAt = ftime.Now().Timestamp()

if !needReset {

p.ResetReason = ""

}

}

// IsHistory 检测是否是历史密码

func (p *Password) IsHistory(password string) bool {

for _, pass := range p.History {

err := bcrypt.CompareHashAndPassword([]byte(pass), []byte(password))

if err == nil {

return true

}

}

return false

}

// HistoryCount 保存了几个历史密码

func (p *Password) HistoryCount() int {

return len(p.History)

}

func (p *Password) rotaryHistory(maxHistory uint) {

if uint(p.HistoryCount()) < maxHistory {

p.History = append(p.History, p.Password)

} else {

remainHistry := p.History[:maxHistory]

p.History = []string{p.Password}

p.History = append(p.History, remainHistry...)

}

}

// CheckPassword 判断password 是否正确

func (p *Password) CheckPassword(password string) error {

err := bcrypt.CompareHashAndPassword([]byte(p.Password), []byte(password))

if err != nil {

return exception.NewUnauthorized("user or password not connrect")

}

return nil

}