guanzhi / GmSSL

支持国密SM2/SM3/SM4/SM9/SSL的密码工具箱
http://gmssl.org
Apache License 2.0
5.05k stars 1.65k forks source link

按照国密sm9官方参数文档里的值来计算加密里的hmac的C3结果是不一致的 #1707

Open hanlinbao opened 2 months ago

hanlinbao commented 2 months ago

官方文档:

计算 C2=M⊕K1: K1:58373260 F067EC48 667C21C1 44F8BC33 CD304978 
C2:1B5F5B0E 95148968 2F3E64E1 378CDD5D A9513B1C 
计算 C3=MAC(K2, C2): 
K2:8651FFD5 F738003E 51DF3117 4D0E4E40 2FD87F45 81B612F7 4259DB57 4F67ECE6 
C3:BA672387 BCD6DE50 16A158A5 2BB2E7FC 429197BC AB70B25A FEE37A2B 9DB9F367

用目前sm9_do_decrypt函数,debug进去查看到值为:

A9 CF 7B 5A 85 18 2A 3D 50 0B 46 C1 83 32 39 2C 06 AF 26 55 09 24 34 45 2E 4B 8D 93 6D B1 3D 81

结果和文档的不一致

hanlinbao commented 2 months ago

之前您解答了asn头问题,当时以为和手头的硬件不能加解密互通是因为这个asn导致的。 现在逐步排查发现封装解封装都正常,应该计算出k1和k2的过程没问题。 通过直接赋值文档里的数据,发现这个hmac计算出的C3结果不正确,可以关注一下

emmansun commented 2 months ago

标准应该没变化,不知道为什么V3改变了C3的MAC算法。

emmansun commented 2 months ago

cc @guanzhi

hanlinbao commented 2 months ago

HMAC(EVP_sm3(), key, strlen(key), (unsigned char *)data, strlen(data), digest, &digest_len); 发现替换为openssl也是一样的值

emmansun commented 2 months ago

HMAC(EVP_sm3(), key, strlen(key), (unsigned char *)data, strlen(data), digest, &digest_len); 发现替换为openssl也是一样的值

HMAC当然是一样的。但是SM9的MAC不是HMAC。 image

你测试gmssl SM9的目的是什么?和你的硬件作比对?

emmansun commented 2 months ago

这个MAC的问题去年也在这里问过:https://github.com/emmansun/gmsm/issues/193

hanlinbao commented 2 months ago

HMAC(EVP_sm3(), key, strlen(key), (unsigned char *)data, strlen(data), digest, &digest_len); 发现替换为openssl也是一样的值

HMAC当然是一样的。但是SM9的MAC不是HMAC。 image

你测试gmssl SM9的目的是什么?和你的硬件作比对?

是为了软仿硬件操作,需要和硬件一致。 您说的SM9的MAC不是HMAC,gmssl里用的hmac是不是就是用错了? 如果单纯的使用sm3hash,也没有传递key2的地方了,这是啥情况搞不明白了

emmansun commented 2 months ago

https://github.com/emmansun/gmsm/blob/8b0ad542386dad9621a22f12e8b9c2dbd0f9501c/sm9/sm9.go#L438C1-L461C2

func encrypt(rand io.Reader, pub *EncryptMasterPublicKey, uid []byte, hid byte, plaintext []byte, opts EncrypterOpts) (c1 *bn256.G1, c2, c3 []byte, err error) {
    if opts == nil {
        opts = DefaultEncrypterOpts
    }
    if len(plaintext) == 0 {
        return nil, nil, nil, ErrEmptyPlaintext
    }
    key1Len := opts.GetKeySize(plaintext)
    key, c1, err := WrapKey(rand, pub, uid, hid, key1Len+sm3.Size)
    if err != nil {
        return nil, nil, nil, err
    }
    c2, err = opts.Encrypt(rand, key[:key1Len], plaintext)
    if err != nil {
        return nil, nil, nil, err
    }

    hash := sm3.New()
    hash.Write(c2)
    hash.Write(key[key1Len:])
    c3 = hash.Sum(nil)

    return
}
  1. WrapKey的时候,同时derive了K1和K2
  2. C3 = SM3HASH(C2 || K2)
hanlinbao commented 2 months ago

标准应该没变化,不知道为什么V3改变了C3的MAC算法。

感谢您的提示,回退到最初版本查看使用的是这个: EVP_Digest( k, c2len + SM3_HMAC_SIZE, mac, &digest_len, EVP_sm3(), NULL ); 现在替换成这个成功了,gmssl现在应该是用错了

deatil commented 2 months ago

mac 摘要和 digest 摘要是有些区别的,文档写的是做 mac 处理,按正常的逻辑就是做 hmac 处理,而测试数据用的是 digest 摘要处理,除非是写文档时候还没有 hmac 实现,所以只能先用 digest 代替。或者是文档作者对 mac 的理解有些出入,认为 mac 摘要就是 digest 摘要

emmansun commented 2 months ago

mac 摘要和 digest 摘要是有些区别的,文档写的是做 mac 处理,按正常的逻辑就是做 hmac 处理,而测试数据用的是 digest 摘要处理,除非是写文档时候还没有 hmac 实现,所以只能先用 digest 代替。或者是文档作者对 mac 的理解有些出入,认为 mac 摘要就是 digest 摘要

HMAC (Hash-based Message Authentication Code) or Keyed-Hashing for Message Authentication Code. 它通过一个标准算法,在计算哈希的过程中,把KEY混入计算过程中。 SM9中使用的SM3-MAC也是类似功效:计算一段message的哈希时,根据不同KEY计算出不同的哈希;要验证哈希值,必须同时提供正确的KEY。至于为什么SM9中使用的MAC不使用HMAC标准算法,就不得而知了。

hanlinbao commented 2 months ago

mac 摘要和 digest 摘要是有些区别的,文档写的是做 mac 处理,按正常的逻辑就是做 hmac 处理,而测试数据用的是 digest 摘要处理,除非是写文档时候还没有 hmac 实现,所以只能先用 digest 代替。或者是文档作者对 mac 的理解有些出入,认为 mac 摘要就是 digest 摘要

HMAC (Hash-based Message Authentication Code) or Keyed-Hashing for Message Authentication Code. 它通过一个标准算法,在计算哈希的过程中,把KEY混入计算过程中。 SM9中使用的SM3-MAC也是类似功效:计算一段message的哈希时,根据不同KEY计算出不同的哈希;要验证哈希值,必须同时提供正确的KEY。至于为什么SM9中使用的MAC不使用HMAC标准算法,就不得而知了。

这是真的坑,文档里并没有对这一步进行详尽描述。 c2||k2后算sm3如果不是您来告诉我,纯看文档完全不知道。。。 现在行业里各种硬件厂商和应用厂商都按照非hmac来计算了,后续的厂商也只能按照这个来走,就算是错的也只能将错就错的走下去了

emmansun commented 2 months ago

你这有点冤枉标准文档了,你结合5.3.25.3.5再仔细看看:

image

《GB/T 32905-2016 信息安全技术 SM3密码杂凑算法》。

只是HMAC: Keyed-Hashing for Message Authentication, The Keyed-Hash Message Authentication Code (HMAC) 更为人所知而已。

guanzhi commented 2 months ago

https://github.com/guanzhi/GM-Standards/blob/master/GMT密码行标/GMT%200044.4-2016%20SM9标识密码算法%20第四部分:密钥封装机制和公钥加密算法.pdf

早期流传出的SM9规范文本中将哈希函数 Hv(Z||K2) 作为MAC算法,在2016年正式发布的GM/T 0044.4-2016标准中删除了早期草案中对MAC算法的这个(不准确的)定义。为遵守正式标准,GmSSL v3采用HMAC-SM3作为其中的MAC算法。

emmansun commented 2 months ago

https://github.com/guanzhi/GM-Standards/blob/master/GMT密码行标/GMT%200044.4-2016%20SM9标识密码算法%20第四部分:密钥封装机制和公钥加密算法.pdf

早期流传出的SM9规范文本中将哈希函数 Hv(Z||K2) 作为MAC算法,在2016年正式发布的GM/T 0044.4-2016标准中删除了早期草案中对MAC算法的这个(不准确的)定义。为遵守正式标准,GmSSL v3采用HMAC-SM3作为其中的MAC算法。

《GM/T 0044.4-2016 SM9标识密码算法 第4部分:密钥封装机制和公钥加密算法》中的5.4.2.15.4.5节。 《GB/T 38635.2-2020 信息安全技术 SM9标识密码算法 第2部分:算法》中针对这个MAC算法(Hv(Z||K2))是明确的,参考标准中的5.3.2和5.3.5节。

hanlinbao commented 2 months ago

https://github.com/guanzhi/GM-Standards/blob/master/GMT密码行标/GMT%200044.4-2016%20SM9标识密码算法%20第四部分:密钥封装机制和公钥加密算法.pdf

早期流传出的SM9规范文本中将哈希函数 Hv(Z||K2) 作为MAC算法,在2016年正式发布的GM/T 0044.4-2016标准中删除了早期草案中对MAC算法的这个(不准确的)定义。为遵守正式标准,GmSSL v3采用HMAC-SM3作为其中的MAC算法。

确实应该按最新国标吧,这里写了 GB/T 38635.2-2020 信息安全技术 SM9标识密码算法 第2部分:算法 1720140568500

hanlinbao commented 2 months ago

mac 摘要和 digest 摘要是有些区别的,文档写的是做 mac 处理,按正常的逻辑就是做 hmac 处理,而测试数据用的是 digest 摘要处理,除非是写文档时候还没有 hmac 实现,所以只能先用 digest 代替。或者是文档作者对 mac 的理解有些出入,认为 mac 摘要就是 digest 摘要

国标确实写了 GB/T 38635.2-2020 信息安全技术 SM9标识密码算法 第2部分:算法 1720140568500

deatil commented 2 months ago

mac 摘要和 digest 摘要是有些区别的,文档写的是做 mac 处理,按正常的逻辑就是做 hmac 处理,而测试数据用的是 digest 摘要处理,除非是写文档时候还没有 hmac 实现,所以只能先用 digest 代替。或者是文档作者对 mac 的理解有些出入,认为 mac 摘要就是 digest 摘要

国标确实写了 GB/T 38635.2-2020 信息安全技术 SM9标识密码算法 第2部分:算法 1720140568500

这个,认真的看的话,文档里说的是设H为密码杂凑算法。这里最主要的是要知道密码杂凑算法。 杂凑算法和密码杂凑算法看起来是有些区别的吧。 杂凑算法通常是digest,如果加key,按常规的标准那就是hmac吧 但是按文档说法,GB/T 32905-2016 的digest 就是[信息安全技术 SM3密码杂凑算法]。那基本就是直接调用sm3计算了,没有做 hmac 调用

hanlinbao commented 2 months ago

mac 摘要和 digest 摘要是有些区别的,文档写的是做 mac 处理,按正常的逻辑就是做 hmac 处理,而测试数据用的是 digest 摘要处理,除非是写文档时候还没有 hmac 实现,所以只能先用 digest 代替。或者是文档作者对 mac 的理解有些出入,认为 mac 摘要就是 digest 摘要

国标确实写了 GB/T 38635.2-2020 信息安全技术 SM9标识密码算法 第2部分:算法 1720140568500

这个,认真的看的话,文档里说的是设H为密码杂凑算法。这里最主要的是要知道密码杂凑算法。 杂凑算法和密码杂凑算法看起来是有些区别的吧。 杂凑算法通常是digest,如果加key,按常规的标准那就是hmac吧

那怎么解释后面写的Z||K2,这种组装方式,而不是用K2对Z计算,这同一个文档的后面就带着参数结果,可以映证是非hmac

deatil commented 2 months ago

mac 摘要和 digest 摘要是有些区别的,文档写的是做 mac 处理,按正常的逻辑就是做 hmac 处理,而测试数据用的是 digest 摘要处理,除非是写文档时候还没有 hmac 实现,所以只能先用 digest 代替。或者是文档作者对 mac 的理解有些出入,认为 mac 摘要就是 digest 摘要

国标确实写了 GB/T 38635.2-2020 信息安全技术 SM9标识密码算法 第2部分:算法 1720140568500

这个,认真的看的话,文档里说的是设H为密码杂凑算法。这里最主要的是要知道密码杂凑算法。 杂凑算法和密码杂凑算法看起来是有些区别的吧。 杂凑算法通常是digest,如果加key,按常规的标准那就是hmac吧

那怎么解释后面写的Z||K2,这种组装方式,而不是用K2对Z计算,这同一个文档的后面就带着参数结果,可以映证是非hmac

按文档来,该说就不是hmac了,没走国际标准的 hmac