init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+245
View File
@@ -0,0 +1,245 @@
package ctrrng
import (
"crypto/cipher"
"encoding/binary"
"io"
"runtime"
"time"
"xdx.jelly/xgcl/grand/drng/internal"
"xdx.jelly/xgcl/internal/xor"
"xdx.jelly/xgcl/sm/sm4"
)
type SM4BlockNewer struct{}
func (b SM4BlockNewer) BlockSize() int {
return sm4.BlockSize
}
func (b SM4BlockNewer) New(key []byte) cipher.Block {
if len(key) != sm4.BlockSize {
panic("ctrrng: invalid block key length")
}
block, _ := sm4.NewCipher(key)
return block
}
func NewCtrDrng(newBlock NewBlock, config *internal.DrngConfig) (internal.RawDrng, error) {
hd := &CtrDrng{
config: *config,
newBlock: newBlock,
df: newDF(newBlock),
}
// 析构时对内部状态置0
runtime.SetFinalizer(hd, func(hd *CtrDrng) {
hd.state.zeromize()
})
return hd, nil
}
type internalState struct {
v []byte // blockLen
k []byte // keyLen
reseedCounter uint32
lastReseedTime time.Time
}
// zeromize 对内部状态置0
func (s *internalState) zeromize() {
for i := 0; i < len(s.v); i++ {
s.v[i] = 0
}
for i := 0; i < len(s.k); i++ {
s.k[i] = 0
}
s.reseedCounter = 0
}
type CtrDrng struct {
// mu sync.Mutex
config internal.DrngConfig
newBlock NewBlock
df func(input []byte, n int) []byte
state internalState
personalizationString []byte //个性化字符串,来自应用的比特串
}
type NewBlock interface {
BlockSize() int
New(key []byte) cipher.Block
}
// newDF 返回一个使用block作为杂凑的df函数
// 例:SM3_df = newDF(sm.SM3)
func newDF(newBlock NewBlock) func(input []byte, n int) []byte {
keylen := newBlock.BlockSize()
outlen := newBlock.BlockSize()
keymatial := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31}
return func(input []byte, n int) []byte {
L := len(input)
// S = L || n || input || 0x80 || 00 such that len(S) % n = 0
S := make([]byte, ((9+L+n-1)/n)*n)
binary.BigEndian.PutUint32(S, uint32(L))
binary.BigEndian.PutUint32(S[4:], uint32(n))
copy(S[8:], input)
S[8+L] = 0x80
K := keymatial[:keylen]
temp := make([]byte, 0, keylen+n)
ivs := make([]byte, outlen+len(S)) // iv || S
copy(ivs[4:], S)
i := uint32(0)
block := newBlock.New(K)
for len(temp) < keylen+n {
binary.BigEndian.PutUint32(ivs, i)
i++
temp = append(temp, cbcMac(block, ivs)...)
}
K = temp[:keylen]
X := temp[keylen:]
block = newBlock.New(K)
temp = []byte{}
for len(temp) < n {
block.Encrypt(X, X)
temp = append(temp, X...)
}
return temp[:n]
}
}
// len(data) % block.BlockSize() == 0
func cbcMac(block cipher.Block, data []byte) []byte {
blockSize := block.BlockSize()
iv := make([]byte, blockSize)
n := 0
for n+blockSize <= len(data) {
xor.XorBytes(iv, iv, data[n:])
block.Encrypt(iv, iv)
n += blockSize
}
return iv
}
func (cd *CtrDrng) keyLen() int {
return cd.newBlock.BlockSize()
}
func (cd *CtrDrng) blockLen() int {
return cd.newBlock.BlockSize()
}
func (cd *CtrDrng) seedLen() int {
return cd.keyLen() + cd.OutLen()
}
func (cd *CtrDrng) OutLen() int {
return cd.config.Outlen
}
func (cd *CtrDrng) Config() *internal.DrngConfig {
return &cd.config
}
// Instantiate 初始化HashDrng
func (cd *CtrDrng) Instantiate(personalizationString []byte, nonce []byte, entropySource io.Reader) (internal.Drng, error) {
// cd.mu.Lock()
// defer cd.mu.Unlock()
cfg := cd.config
cd.personalizationString = personalizationString
cd.state.k = make([]byte, cd.keyLen())
cd.state.v = make([]byte, cd.blockLen())
seedMaterial := make([]byte, 2*cfg.MinEntropyInputLength, int(2*cfg.MinEntropyInputLength)+len(nonce)+len(personalizationString))
var m, n int
var err error
var errCount int
for n < int(cfg.MinEntropyInputLength) {
m, err = entropySource.Read(seedMaterial[n:])
n += m
if err != nil {
errCount++
}
if errCount > 3 {
return cd, err
}
}
seedMaterial = append(seedMaterial, nonce...)
seedMaterial = append(seedMaterial, personalizationString...)
seedMaterial = cd.df(seedMaterial, cd.seedLen())
cd.update(seedMaterial)
return cd, nil
}
func (cd *CtrDrng) update(seedMaterial []byte) {
seedlen := cd.seedLen()
temp := make([]byte, seedlen)
n := 0
block := cd.newBlock.New(cd.state.k)
for n+cd.blockLen() < seedlen {
internal.IncBytes(cd.state.v)
block.Encrypt(temp[n:n+cd.blockLen()], cd.state.v)
n += cd.blockLen()
}
xor.XorBytes(temp, temp, seedMaterial)
copy(cd.state.k, temp)
copy(cd.state.v, temp[cd.keyLen():])
}
func (cd *CtrDrng) Reseed(entropyInput, additionalInput []byte) {
// cd.mu.Lock()
// defer cd.mu.Unlock()
seedMaterial := make([]byte, len(entropyInput)+len(additionalInput))
copy(seedMaterial, entropyInput)
copy(seedMaterial[len(entropyInput):], additionalInput)
seedMaterial = cd.df(seedMaterial, cd.seedLen())
cd.update(seedMaterial)
cd.state.reseedCounter = 1
cd.state.lastReseedTime = time.Now()
for i := 0; i < len(seedMaterial); i++ {
seedMaterial[i] = 0
}
}
func (cd *CtrDrng) Generate(b []byte, additionalInput []byte) error {
// cd.mu.Lock()
// defer cd.mu.Unlock()
if len(b) > cd.config.Outlen {
return internal.ErrReturnedBitsTooLong
}
// 需要重播种
if cd.state.reseedCounter > uint32(cd.config.ReseedIntervalInCounter) ||
time.Since(cd.state.lastReseedTime) > cd.config.ReseedIntervalInTime {
return internal.ErrNeedReseed
}
if len(additionalInput) > 0 {
additionalInput = cd.df(additionalInput, cd.seedLen())
cd.update(additionalInput)
} else {
additionalInput = make([]byte, cd.seedLen())
}
block := cd.newBlock.New(cd.state.k)
internal.IncBytes(cd.state.v)
outputBlock := make([]byte, block.BlockSize())
block.Encrypt(outputBlock, cd.state.v)
copy(b, outputBlock)
cd.update(additionalInput)
cd.state.reseedCounter++
return nil
}