Files
xgcl/grand/drng/drng.go
T
2026-05-27 23:03:00 +08:00

101 lines
2.7 KiB
Go

// package drng implements the SM3Rng and SM4Rng which specified in GM/T 0115.
//
// ctrrng and hashrng implements the low-level Drng interface.
// Combine entropy(pool) and xxxrng we got the Drng as a ReadWriter.
// The Read method generates random bits, and the Write method
// add outter entropy into the Drng.
//
// Use drng.SM3Rng as an ordinary io.Reader to generate random bits.
// If necessary, it could add extra entropy into the Drng.
// For example, add user's scratch points on mobile, get random bits
// from the cryptography server, etc..
package drng
import (
"io"
"sync"
"xdx.jelly/xgcl/grand/drng/ctrrng"
"xdx.jelly/xgcl/grand/drng/entropy"
"xdx.jelly/xgcl/grand/drng/hashrng"
"xdx.jelly/xgcl/grand/drng/internal"
"xdx.jelly/xgcl/sm"
)
// PERSONALIZATIONSTRING = "粤信签协同签名软件Android客户端密码模块YXQXTQM-Y"
var PERSONALIZATIONSTRING = []byte("xdx")
// SM3Rng implements the io.ReadWriter interface.
//
// SM3Rng.Read reads random bytes from the DRNG.
// SM3rng.Write add extra entropy to the DRNG.
var SM3Rng io.ReadWriter
var SM4Rng io.ReadWriter
func init() {
raw, _ := hashrng.NewHashDrng(sm.SM3, hashrng.Config(internal.SecureLevel2))
rng, _ := raw.Instantiate(PERSONALIZATIONSTRING, internal.Nonce(), entropy.GetEntropyPool())
SM3Rng = &DrngUtil{
Drng: rng,
ReseedSource: entropy.GetEntropyPool(),
}
raw, _ = ctrrng.NewCtrDrng(ctrrng.SM4BlockNewer{}, ctrrng.Config(internal.SecureLevel2))
rng, _ = raw.Instantiate(PERSONALIZATIONSTRING, internal.Nonce(), entropy.GetEntropyPool())
SM4Rng = &DrngUtil{
Drng: rng,
ReseedSource: entropy.GetEntropyPool(),
}
}
// DrngUtil implements the io.Reader interface
type DrngUtil struct {
mu sync.Mutex
internal.Drng
ReseedSource io.Reader // 重播种熵源
additionalInput io.Reader // TODO: 额外输入, 可为空
}
// Write implements io.ReadWriter.
// The returns can be ignored.
func (du *DrngUtil) Write(p []byte) (n int, err error) {
du.mu.Lock()
defer du.mu.Unlock()
du.Drng.Reseed(p, nil)
return len(p), nil
}
// Read implements io.Reader
func (du *DrngUtil) Read(p []byte) (n int, err error) {
du.mu.Lock()
defer du.mu.Unlock()
outlen := du.OutLen()
for len(p) > 0 {
generateLen := len(p)
if generateLen > outlen {
generateLen = outlen
}
err := du.Generate(p[:generateLen], nil)
if err != nil {
// 需要重播种
config := du.Config()
entropyInput := make([]byte, config.MinEntropy)
n, err := du.ReseedSource.Read(entropyInput)
if err != nil {
return n, err
}
du.Drng.Reseed(entropyInput[:n], nil)
err = du.Generate(p[:generateLen], nil)
if err != nil {
return n, err
}
}
n += generateLen
p = p[generateLen:]
}
return n, nil
}