101 lines
2.7 KiB
Go
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
|
|
}
|