gmsm/kdf/kdf.go

58 lines
1.5 KiB
Go
Raw Normal View History

2023-01-31 13:50:14 +08:00
// Package kdf implements ShangMi(SM) used Key Derivation Function, compliances with GB/T 32918.4-2016 5.4.3.
2022-08-25 11:48:41 +08:00
package kdf
import (
2024-05-15 08:28:47 +08:00
"encoding"
2022-08-25 11:48:41 +08:00
"encoding/binary"
"hash"
)
2024-05-17 08:40:27 +08:00
// KdfInterface is the interface implemented by some specific Hash implementations.
type KdfInterface interface {
Kdf(z []byte, keyLen int) []byte
}
2022-08-25 11:48:41 +08:00
// Kdf key derivation function, compliance with GB/T 32918.4-2016 5.4.3.
// ANSI-X9.63-KDF
2024-05-15 08:28:47 +08:00
func Kdf(newHash func() hash.Hash, z []byte, keyLen int) []byte {
baseMD := newHash()
2024-05-17 08:40:27 +08:00
// If the hash implements KdfInterface, use the optimized Kdf method.
if kdfImpl, ok := baseMD.(KdfInterface); ok {
return kdfImpl.Kdf(z, keyLen)
}
2024-05-15 08:28:47 +08:00
limit := uint64(keyLen+baseMD.Size()-1) / uint64(baseMD.Size())
2022-08-25 11:48:41 +08:00
if limit >= uint64(1<<32)-1 {
panic("kdf: key length too long")
}
var countBytes [4]byte
var ct uint32 = 1
2023-09-21 13:48:51 +08:00
var k []byte
2024-05-15 08:28:47 +08:00
2024-05-17 08:40:27 +08:00
if marshaler, ok := baseMD.(encoding.BinaryMarshaler); limit == 1 || len(z) < baseMD.BlockSize() || !ok {
2024-05-15 08:28:47 +08:00
for i := 0; i < int(limit); i++ {
binary.BigEndian.PutUint32(countBytes[:], ct)
baseMD.Write(z)
baseMD.Write(countBytes[:])
k = baseMD.Sum(k)
ct++
baseMD.Reset()
}
} else {
baseMD.Write(z)
zstate, _ := marshaler.MarshalBinary()
for i := 0; i < int(limit); i++ {
md := newHash()
err := md.(encoding.BinaryUnmarshaler).UnmarshalBinary(zstate)
if err != nil {
panic(err)
}
binary.BigEndian.PutUint32(countBytes[:], ct)
md.Write(countBytes[:])
k = md.Sum(k)
ct++
}
2022-08-25 11:48:41 +08:00
}
2024-05-15 08:28:47 +08:00
return k[:keyLen]
2022-08-25 11:48:41 +08:00
}