// 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 }