消息认证码(go语言实践)

1. 什么是消息认证码

消息认证码(message authentication code)是一种确认完整性并进行认证的技术,取三个单词的首字 母,简称为MAC。

消息认证码的输入包括任意长度的消息和一个发送者与接收者之间 共享的密钥 ,它可以输出固定长度的数 据,这个数据称为 MAC值

根据任意长度的消息输出固定长度的数据,这一点和单向散列函数很类似。但是单向散列函数中计算散列
值时不需要密钥,而消息认证码中则需要使用发送者与接收者之间共享的密钥。

要计算MAC必须持有共享密钥,没有共享密钥的人就无法计算MAC值,消息认证码正是利用这一性质来完 成认证的。此外,和单向散列函数的散列值一样,哪怕消息中发生1比特的变化,MAC值也会产生变化,消 息认证码正是利用这一性质来确认完整性的。

单向散列函数与消息认证码的比较.png

2. 消息认证码的使用步骤

我们以Alice银行和Bob银行的故事为例,来讲解一下消息认证码的使用步骤:


消息认证码的使用步骤.png
  1. 发送者Alice与接收者Bob事先共享密钥。
  2. 发送者Alice根据汇款请求消息计算MAC值(使用共享密钥)。
  3. 发送者Alice将汇款请求消息和MAC值两者发送给接收者Bob。
  4. 接收者Bob根据接收到的汇款请求消息计算MAC值(使用共享密钥)。
  5. 接收者Bob将自己计算的MAC值与从Alice处收到的MAC值进行对比。
  6. 如果两个MAC值一致,则接收者Bob就可以断定汇款请求的确来自Alice(认证成功);如果不一致,则可以断定消息不是来自Alice(认证失败)。

3. HMAC

3.1. HMAC介绍

HMAC是一种使用单向散列函数来构造消息认证码的方法(RFC2104),其中HMAC的H就是Hash的意思。

HMAC中所使用的单向散列函数并不仅限于一种,任何高强度的单向散列函数都可以被用于HMAC,如果将来设计出新的单向散列函数,也同样可以使用。

使用SHA-I、MD5、RIPEMD-160所构造的HMAC,分别称为HMAC-SHA-1、HMAC-MD5和HMAC-RlPEMD。

使用HMAC通过秘钥将消息生成消息认证码的内部实现.png

通过上述流程我们可以看出,最后得到的MAC值,一定是一个和输入的消息以及密钥都相关的长度固定的比特序列。

3.2. Go中对HMAC的使用

生成消息认证码:

/*
 * 生成消息认证码(短消息)
 * src: 消息原像
 * key: hmac秘钥
 * hashType: hash类型
 */
func GenerateHMACFromBytes(src, key []byte, hashType byhash.KHashType) ([]byte, error) {

    hash := func() (h func() hash.Hash) {
        switch hashType {
        case byhash.KHashTypeMd5:
            return md5.New
        case byhash.KHashTypeSha1:
            return sha1.New
        case byhash.KHashTypeSha256:
            return sha256.New
        case byhash.KHashTypeSha512:
            return sha512.New
        default:
            return nil
        }
    }()

    if hash == nil {
        return nil, errors.New("ERROR:WRONG kHashType")
    }

    // 1. 创建一个底层采用hashType算法的 byhash.Hash 接口
    myHmac := hmac.New(hash, key)

    // 2. 添加测试数据
    myHmac.Write(src)

    // 3. 计算结果
    result := myHmac.Sum(nil)
    return result, nil
}

验证消息认证码:

/*
 * 验证消息认证码(短消息)
 * res: mac值
 * src: 消息原像
 * key: hmac秘钥
 * hashType: hash类型
 */
func VerifyHMACFromBytes(res, src, key []byte, hashType byhash.KHashType) (bool, error) {

    hash := func() (h func() hash.Hash) {
        switch hashType {
        case byhash.KHashTypeMd5:
            return md5.New
        case byhash.KHashTypeSha1:
            return sha1.New
        case byhash.KHashTypeSha256:
            return sha256.New
        case byhash.KHashTypeSha512:
            return sha512.New
        default:
            return nil
        }
    }()

    if hash == nil {
        return false, errors.New("ERROR:WRONG kHashType")
    }

    // 1. 创建一个底层采用hashType算法的 hash.Hash 接口
    myHmac := hmac.New(hash, key)

    // 2. 添加测试数据
    myHmac.Write(src)

    // 3. 计算结果
    result := myHmac.Sum(nil)

    // 4. 比较结果
    return hmac.Equal(res, result), nil
}

4. 消息认证码的密钥配送问题

在消息认证码中,需要发送者和接收者之间共享密钥,而这个密钥不能被主动攻击者Mallory获取。如果这个密 钥落入Mallory手中,则Mallory也可以计算出MAC值,从而就能够自由地进行篡改和伪装攻击,这样一来消息认 证码就无法发挥作用了。

发送者和接收者需要共享密钥,这一点和我们介绍的对称加密很相似。实际上,对称加密的密钥配送问题在消
息认证码中也同样会发生。关于秘钥的配送后边章节会介绍如何使用非对称加密的方式进行解决。

5. 消息认证码无法解决的问题

假设发送者Alice要向接收者Bob发送消息,如果使用了消息认证码,接收者Bob就能够断定自己收到的消息与发 送者Alice所发出的消息是一致的,这是因为消息中的MAC值只有用Alice和Bob之间共享的密钥才能够计算出来, 即便主动攻击者Mallory篡改消息,或者伪装成Alice发送消息,Bob也能够识别出消息的篡改和伪装。

但是,消息认证码也不能解决所有的问题,例如“对第三方证明"和“防止否认",这两个问题就无法通过消息认证 码来解决。下面我们来逐一解释一下。

5.1. 对第三方证明

假设Bob在接收了来自Alice的消息之后,想要向第三方验证者Victor证明这条消息的确是Alice发送的,但是用消 息认证码无法进行这样的证明,这是为什么呢?

首先,Victor要校验MAC值,就需要知道Alice和Bob之间共享的密钥。

假设Bob相信Victor, 同意将密钥告诉Victor,即便如此,Victor也无法判断这条消息是由Alice发送的,因为Victor可 以认为:“即使MAC值是正确的,发送这条消息的人也不一定是Alice,还有可能是Bob。"

能够计算出正确MAC值的人只有Alice和Bob,在他们两个人之间进行通信时,可以断定是对方计算了MAC值,这 是因为共享这个密钥的双方之中,有一方就是自己。然而,对于第三方Victor、Alice或Bob却无法证明是对方计算了MAC值,而不是自己。

使用数字签名可以实现对第三方的证明。

5.2. 防止否认

假设Bob收到了包含MAC值的消息,这个MAC值是用Alice和Bob共享的密钥计算出来的,因此Bob能够判断这条消 息的确来自Alice。

但是,上面我们讲过,Bob无法向验证者Victor证明这一点,也就是说,发送者Alice可以向Victor声称:“我没有 向Bob发送过这条消息。”这样的行为就称为否认(repudiation)。

Alice可以说“这条消息是Bob自己编的吧",“说不定Bob的密钥被主动攻击者Mallory给盗取了,我的密钥可是妥善 保管着呢" 等。说白了,就是Alice和Bob吵起来了。

即便Bob拿MAC值来举证,Victor也无法判断Alice和Bob谁的主张才是正确的,也就是说, 用消息认证码无法防止否认(nonrepudiatlon)

6. 总结

消息认证码是对消息进行认证并确认其完整性的技术。通过使用发送者和接收者之间共享的密钥,就可以识别出是否存在伪装和篡改行为。

消息认证码可以使用单向散列函数HMAC, 对称加密也可以实现, 这里不再进行介绍。

消息认证码中,由于发送者和接收者共享相同的密钥,因此会产生无法对第三方证明以及无法防止否认等问
题。在下一章中,我们将介绍能够解决这些问题的数字签名。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,873评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,483评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,525评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,595评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,018评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,958评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,118评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,873评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,643评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,813评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,293评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,615评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,306评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,170评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,968评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,107评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,894评论 2 278

推荐阅读更多精彩内容