[TOC]
# 消息认证码
![](https://box.kancloud.cn/09ac625acdabe44c3cab78eb2a86586b_605x518.png)
## go消息认证码的使用
> 有一个包: crypto/hmac
~~~
> func New(h func() hash.Hash, key []byte) hash.Hash
> - 返回值: hash接口
> - 参数1: 函数函数的函数名
> sha1.new
> md5.new
> sha256.new
> - 参数2: 秘钥
>
> 第二步: 添加数据
> 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
> }
> type Writer interface {
> Write(p []byte) (n int, err error)
> }
> 第三步: 计算散列值
~~~
## 使用步骤
![](https://box.kancloud.cn/5f500ca1ab2ff0febcf39590b803828c_772x474.png)
> 1. 前提条件:
> - 在消息认证码生成的一方和校验的一方, 必须有一个秘钥
> - 双方约定好使用同样的哈希函数对数据进行运算
> 2. 流程:
> - 发送者:
> - 发送原始法消息
> - 将原始消息生成消息认证码
> - ((原始消息) + 秘钥) * 函数函数 = 散列值(消息认证码)
> - 将消息认证码发送给对方
> - 接收者:
> - 接收原始数据
> - 接收消息认证码
> - 校验:
> - ( 接收的消息 + 秘钥 ) * 哈希函数 = 新的散列值
> - 通过新的散列值和接收的散列值进行比较
~~~
// 生成消息认证码
func GenerateHamc(plainText, key []byte)[]byte {
// 1.创建哈希接口, 需要指定使用的哈希算法, 和秘钥
myhash := hmac.New(sha1.New, key)
// 2. 给哈希对象添加数据
myhash.Write(plainText)
// 3. 计算散列值
hashText := myhash.Sum(nil)
return hashText
}
// 验证消息认证码
func VerifyHamc(plainText, key, hashText []byte) bool {
// 1.创建哈希接口, 需要指定使用的哈希算法, 和秘钥
myhash := hmac.New(sha1.New, key)
// 2. 给哈希对象添加数据
myhash.Write(plainText)
// 3. 计算散列值
hamc1 := myhash.Sum(nil)
// 4. 两个散列值比较
return hmac.Equal(hashText, hamc1)
}
func main () {
src := []byte("在消息认证码中,需要发送者和接收者之间共享密钥,而这个密钥不能被主动攻击者Mallory获取。" +
"如果这个密钥落入Mallory手中,则Mallory也可以计算出MAC值,从而就能够自由地进行篡改和伪装攻击," +
"这样一来消息认证码就无法发挥作用了。")
key := []byte("helloworld")
hamc1 := GenerateHamc(src, key)
bl := VerifyHamc(src, key, hamc1)
//fmt.Printf("校验结果: %t\n", bl)
fmt.Println(bl)
}
~~~
## 消息认证码的问题
1. 弊端
- 有秘钥分发困难的问题
2. 无法解决的问题
- 不能进行第三方证明
- 不能防止否认
- 基础
- 简介
- 主要特征
- 变量和常量
- 编码转换
- 数组
- byte与rune
- big
- sort接口
- 和mysql类型对应
- 函数
- 闭包
- 工作区
- 复合类型
- 指针
- 切片
- map
- 结构体
- sync.Map
- 随机数
- 面向对象
- 匿名组合
- 方法
- 接口
- 权限
- 类型查询
- 异常处理
- error
- panic
- recover
- 自定义错误
- 字符串处理
- 正则表达式
- json
- 文件操作
- os
- 文件读写
- 目录
- bufio
- ioutil
- gob
- 栈帧的内存布局
- shell
- 时间处理
- time详情
- time使用
- new和make的区别
- container
- list
- heap
- ring
- 测试
- 单元测试
- Mock依赖
- delve
- 命令
- TestMain
- path和filepath包
- log日志
- 反射
- 详解
- plugin包
- 信号
- goto
- 协程
- 简介
- 创建
- 协程退出
- runtime
- channel
- select
- 死锁
- 互斥锁
- 读写锁
- 条件变量
- 嵌套
- 计算单个协程占用内存
- 执行规则
- 原子操作
- WaitGroup
- 定时器
- 对象池
- sync.once
- 网络编程
- 分层模型
- socket
- tcp
- udp
- 服务端
- 客户端
- 并发服务器
- Http
- 简介
- http服务器
- http客户端
- 爬虫
- 平滑重启
- context
- httptest
- 优雅中止
- web服务平滑重启
- beego
- 安装
- 路由器
- orm
- 单表增删改查
- 多级表
- orm使用
- 高级查询
- 关系查询
- SQL查询
- 元数据二次定义
- 控制器
- 参数解析
- 过滤器
- 数据输出
- 表单数据验证
- 错误处理
- 日志
- 模块
- cache
- task
- 调试模块
- config
- 部署
- 一些包
- gjson
- goredis
- collection
- sjson
- redigo
- aliyunoss
- 密码
- 对称加密
- 非对称加密
- 单向散列函数
- 消息认证
- 数字签名
- mysql优化
- 常见错误
- go run的错误
- 新手常见错误
- 中级错误
- 高级错误
- 常用工具
- 协程-泄露
- go env
- gometalinter代码检查
- go build
- go clean
- go test
- 包管理器
- go mod
- gopm
- go fmt
- pprof
- 提高编译
- go get
- 代理
- 其他的知识
- go内存对齐
- 细节总结
- nginx路由匹配
- 一些博客
- redis为什么快
- cpu高速缓存
- 常用命令
- Go 永久阻塞的方法
- 常用技巧
- 密码加密解密
- for 循环迭代变量
- 备注
- 垃圾回收
- 协程和纤程
- tar-gz
- 红包算法
- 解决golang.org/x 下载失败
- 逃逸分析
- docker
- 镜像
- 容器
- 数据卷
- 网络管理
- 网络模式
- dockerfile
- docker-composer
- 微服务
- protoBuf
- GRPC
- tls
- consul
- micro
- crontab
- shell调用
- gorhill/cronexpr
- raft
- go操作etcd
- mongodb