github.com/emmansun/gmsm@v0.29.1/kdf/kdf.go (about) 1 // Package kdf implements ShangMi(SM) used Key Derivation Function, compliances with GB/T 32918.4-2016 5.4.3. 2 package kdf 3 4 import ( 5 "encoding" 6 "encoding/binary" 7 "hash" 8 ) 9 10 // KdfInterface is the interface implemented by some specific Hash implementations. 11 type KdfInterface interface { 12 Kdf(z []byte, keyLen int) []byte 13 } 14 15 // Kdf key derivation function, compliance with GB/T 32918.4-2016 5.4.3. 16 // ANSI-X9.63-KDF 17 func Kdf(newHash func() hash.Hash, z []byte, keyLen int) []byte { 18 baseMD := newHash() 19 // If the hash implements KdfInterface, use the optimized Kdf method. 20 if kdfImpl, ok := baseMD.(KdfInterface); ok { 21 return kdfImpl.Kdf(z, keyLen) 22 } 23 limit := uint64(keyLen+baseMD.Size()-1) / uint64(baseMD.Size()) 24 if limit >= uint64(1<<32)-1 { 25 panic("kdf: key length too long") 26 } 27 var countBytes [4]byte 28 var ct uint32 = 1 29 var k []byte 30 31 if marshaler, ok := baseMD.(encoding.BinaryMarshaler); limit == 1 || len(z) < baseMD.BlockSize() || !ok { 32 for i := 0; i < int(limit); i++ { 33 binary.BigEndian.PutUint32(countBytes[:], ct) 34 baseMD.Write(z) 35 baseMD.Write(countBytes[:]) 36 k = baseMD.Sum(k) 37 ct++ 38 baseMD.Reset() 39 } 40 } else { 41 baseMD.Write(z) 42 zstate, _ := marshaler.MarshalBinary() 43 for i := 0; i < int(limit); i++ { 44 md := newHash() 45 err := md.(encoding.BinaryUnmarshaler).UnmarshalBinary(zstate) 46 if err != nil { 47 panic(err) 48 } 49 binary.BigEndian.PutUint32(countBytes[:], ct) 50 md.Write(countBytes[:]) 51 k = md.Sum(k) 52 ct++ 53 } 54 } 55 56 return k[:keyLen] 57 }