密码学奇妙之旅、03 HMAC单向散列消息认证码、Golang代码
HMAC 单向散列消息认证码
消息认证码MAC是用于确认完整性并进行认证的技术,消息认证码的输入包括任意长度的消息和一个发送者和接收者之间共享的密钥(可能还需要共享盐值)。
HMAC是使用单向散列函数来构造消息认证码的方法,任何高强度单向散列函数都可以被用于HMAC,具体方法如下图所示。
发送者需要同时把消息和认证码发送给接收者,接收者接收了两者,并根据接收到的消息和共享的密钥生成认证码进行比较。如果相同则消息未被篡改且认证成功。
MAC不能保证信息的机密性!MAC无法对第三方"C"证明,因为"A","B"两者都有密钥,都可以生成消息和MAC。因此第三方不知道是谁生成的,更不知道消息的真实性。MAC无法防止否认。

加盐
盐是通过伪随机数生成器生成的随机数,会和密钥一起被输入单向散列函数。
主要目的是为了防御字典攻击。字典攻击是一种事先进行计算并准备好候选密钥列表的方法。是一种暴力攻击破解手段。加了盐,密钥便多了n个数量级的可能,加大破解难度。
HMAC利用单向散列函数的单向性和抗碰撞性来保证无法根据MAC值推测出密钥。
代码
package main
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"fmt"
"hash"
"io"
)
var secretKey = "114514abcdefghijklmn"
var salt = generateSalt()
// 生成一个包含 16 字节数据的盐字符串
func generateSalt() string {
randomBytes := make([]byte, 16)
if _, err := rand.Read(randomBytes); err != nil {
return ""
}
return base64.URLEncoding.EncodeToString(randomBytes)
}
// 提供散列函数、密钥、盐值、消息返回HMAC
func HMAC(h func() hash.Hash, secretKey string, salt string, message string) []byte {
hash := hmac.New(h, []byte(secretKey))
io.WriteString(hash, message+salt)
return hash.Sum(nil)
}
func main() {
/* ----------------------------------- 发送方 ---------------------------------- */
message := "A请求B转账10000"
fmt.Println("\n\t消息: " + message)
fmt.Println("\t加盐: " + salt)
fmt.Printf("\n\tHMAC-Sha256: %x", HMAC(sha256.New, secretKey, salt, message))
fmt.Printf("\n\tHMAC-Sha256: %x", HMAC(sha512.New, secretKey, salt, message))
/* ----------------------------------- 修改一个字母 ---------------------------------- */
messageChange := "C请求B转账10000"
fmt.Printf("\n\n\tHMAC-Sha256: %x", HMAC(sha256.New, secretKey, salt, messageChange))
fmt.Printf("\n\tHMAC-Sha256: %x\n\n", HMAC(sha512.New, secretKey, salt, messageChange))
/* --------------------------- 接收方分别收到了发送者的消息、HMac值 -------------------------- */
// ^ 假定消息和HMAC均被黑客截获,黑客进行重放攻击
sendMessgage := message // @ 发送者发送消息
sendHMAC := string(HMAC(sha256.New, secretKey, salt, sendMessgage)) // @ 发送者计算HMAC并与消息一起发给接收者
hackerGetHMAC := sendHMAC // @ 黑客窃听到HMAC
hackerGetMessage := sendMessgage // @ 黑客窃听到消息
receiveHMAC := hackerGetHMAC // @ 接收者收到HMAC
receiveMessage := hackerGetMessage // @ 接收者收到MESSAGE
if string(HMAC(sha256.New, secretKey, salt, receiveMessage)) == receiveHMAC {
fmt.Println("\t第1次重放攻击" + message)
}
receiveHMAC = hackerGetHMAC // @ 接收者收到HMAC
receiveMessage = hackerGetMessage // @ 接收者收到MESSAGE
if string(HMAC(sha256.New, secretKey, salt, receiveMessage)) == receiveHMAC {
fmt.Println("\t第2次重放攻击" + message)
}
// ^ 假定消息和HMAC都是黑客发送的,但黑客并不知道密钥和盐值
sendMessgage = "今天是KFC V我小能喵喵喵50速速" // @ 发送者发送消息
sendHMAC = string(HMAC(sha256.New, "miyueshishenme", "114514", sendMessgage)) // @ 黑客计算HMAC并与消息一起发给接收者
receiveHMAC = sendHMAC // @ 接收者收到HMAC
receiveMessage = sendMessgage // @ 接收者收到MESSAGE
if string(HMAC(sha256.New, secretKey, salt, receiveMessage)) != receiveHMAC {
fmt.Println("\t消息不一致、认证失败")
}
}
PS C:\Users\小能喵喵喵\Desktop\Go\Cryptography\HMAC> go run .
消息: A请求B转账10000
加盐: S_XlM8K_dhAvsgch_N3o1w==
HMAC-Sha256: b8dd30d2a418262494f298bcdaf6c12f442c6e8f89a31822dad03561887f3bed
HMAC-Sha256: ba934567837ec98ba89853b09f6652ce56955cfeedd0c4495bd6cba7fc2f8293635fdc59b90180564bd0fdb1d1bffc52644fc2bd8164d6379ae11510e200954c
HMAC-Sha256: 2db84d209e2418f314fc5bb0583cfb50cde90d954d8493d3ed0e3b369fb092d7
HMAC-Sha256: 7b192cedb1d89fd71889189a0094e1df06d26d977bc3bed4f53b16928aa2d58084cb8890d52cb40f665bb9ac62eeb4092495efe7d59292470ed597a3536dea56
第1次重放攻击A请求B转账10000
第2次重放攻击A请求B转账10000
消息不一致、认证失败
如何防止重放攻击
- 给消息加序号,收发双方约定好
- 时间戳,收发双方必须考虑到通信延迟,还是会存在重放攻击的空间。
- 接收者发送一次性随机数,发送者HMAC该随机数后发送。确保当前消息只能发一次。
密码学奇妙之旅、03 HMAC单向散列消息认证码、Golang代码的更多相关文章
- 【Java-加密算法】对称加密、非对称加密、单向散列(转)
一提到加密,就会联想到数字签名,这两个经常被混淆的概念到底是什么呢? 加密:加密是一种以密码方式发送信息的方法.只有拥有正确密钥的人才能解开这个信息的密码.对于其他人来说,这个信息看起来就像是一系列随 ...
- 29.密码学知识-消息认证码MAC-6——2019年12月19日
1. 消息认证码 1.1 消息认证 消息认证码(message authentication code)是一种确认完整性并进行认证的技术,取三个单词的首字母,简称为MAC. 思考改进方案? 从哈希函数 ...
- 密码学初级教程(五)消息认证码MAC-Message Authentication Code
密码学家工具箱中的6个重要的工具: 对称密码 公钥密码 单向散列函数 消息认证码 数字签名 伪随机数生成器 MAC能识别出篡改和伪装,也就是既可以确认消息的完整性,也可以进行认证. 消息认证码的输入包 ...
- Shiro+springboot+mybatis+EhCache(md5+salt+散列)认证与授权-03
从上文:Shiro+springboot+mybatis(md5+salt+散列)认证与授权-02 当每次进行刷新时,都会从数据库重新查询数据进行授权操作,这样无疑给数据库造成很大的压力,所以需要引入 ...
- hmac库 密钥相关的哈希运算消息认证码
# -*- coding: cp936 -*- #xiaodeng #python 2.7.10 #HMAC是密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一 ...
- HMAC哈希消息认证码
收藏 137 14 hmac 编辑 HMAC是密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出. 中文名 哈希消息认证码 外文名 H ...
- Shiro+springboot+mybatis(md5+salt+散列)认证与授权-02
代码延续地址:Shiro+springboot+mybatis(md5+salt+散列)认证与授权-01 1.创建t_role角色表(比如管理员admin,普通用户user等),创建t_pers权限表 ...
- 密码学奇妙之旅、02 混合加密系统、AES、RSA标准、Golang代码
CTR 计数器模式 计数器模式CTR是分组密码模式中的一种.通过将逐次累加的计数器进行加密来生成密钥流的流密码.每次加密时会生成一个不同的值来作为计数器的初始值. 可以事先进行加密.解密的准备. 加密 ...
- Shiro+springboot+mybatis(md5+salt+散列)认证与授权-01
这个小项目包含了注册与登录,使用了springboot+mybatis+shiro的技术栈:当用户在浏览器登录时发起请求时,首先这一系列的请求会被拦截器进行拦截(ShiroFilter),然后拦截器根 ...
随机推荐
- Solution -「2020.12.26」 模拟赛
0x00 前言 一些吐槽. 考得很变态诶,看每道题平均两秒的时限就知道了... T1 降智了想到后缀懒得打. T2 口胡了假优化,结果和暴力分一样?? T3 黑题还绑点?? \(50 + 80 + 0 ...
- DQL条件查询模糊查询和约束概述
模糊查询 -- 查询姓马的有哪些? like SELECT * FROM student where name LIKE '马%'; -- 查询姓名第二个字是化的人 SELECT * FROM stu ...
- Redis 哈希Hash底层数据结构
1. Redis 底层数据结构 Redis数据库就像是一个哈希表,首先对key进行哈希运算得到哈希值再取模得到一个下标,每个元素是一个节点,节点之间形成链表.这感觉有点像Java中的HashMap. ...
- 使用Mpvue配合Weui开发面试题题库微信小程序,并且发布到正式环境
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_116 之前的一篇文章详细阐述了微信小程序开发的准备和入门以及环境搭建,这一次我们介绍如何将微信小程序如何上线,同时配合weui美化 ...
- Nginx 平滑升级、Nginx的一些基础配置
# Nginx 平滑升级 # 方案一:使用Nginx服务信号进行升级 # 1.将就版本的sbin目录下可执行nginx进行备份(mv nginx nginxold) # 2.将新版本 configur ...
- 服务器配置IP
1.服务器系统一般有两个或多个网卡.在企业中一般给服务器网卡配一个可连外网的IP,如172.16.20.22 255.255.255.0 172.16.20.1 方便联网下载安装部分软件,若没有VPN ...
- 选择结构——if控制语句单、双、多分支结构
1.if控制语句 概念: if控制语句共有3种不同形式,分别是单分支结构.双分支结构和多分支结构. (1)使用 if 语句实现单分支处理 语法格式: if(表达式){ 语句 } 流程图: 执行步骤: ...
- HDFS基础入门
HDFS简介 HDFS(全称:Hadoop Distribute File System)分布式文件系统,是Hadoop核心组成. HDFS中的重要概念 分块存储 HDFS中的文件在物理上是分块存储的 ...
- ASP.NET Core 6框架揭秘实例演示[32]:错误页面的集中呈现方式
由于ASP.NET是一个同时处理多个请求的Web应用框架,所以在处理某个请求过程中出现异常并不会导致整个应用的中止.出于安全方面的考量,为了避免敏感信息外泄,客户端在默认情况下并不会得到详细的出错信息 ...
- JavaScript基础回顾知识点记录2
js 使用嵌套for循环输出三角形 for(var i=0; i<5; i++){ //正三角 // for(var j=0; j<i+1; j++){ // document.write ...