增加了DRBG销毁内部状态的方法 (#378)

* 增加了DRBG销毁内部状态的方法

* 统一前缀

* 修改随机数长度

* 分组和注释

* 错误函数描述
This commit is contained in:
Guanyu Quan 2025-09-29 15:42:30 +08:00 committed by GitHub
parent c234076521
commit 62ee2eb20e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 143 additions and 2 deletions

View File

@ -7,6 +7,8 @@ import (
"errors" "errors"
"hash" "hash"
"io" "io"
"runtime"
"sync/atomic"
"time" "time"
"github.com/emmansun/gmsm/sm3" "github.com/emmansun/gmsm/sm3"
@ -226,6 +228,8 @@ type DRBG interface {
Generate(b, additional []byte) error Generate(b, additional []byte) error
// MaxBytesPerRequest return max bytes per request // MaxBytesPerRequest return max bytes per request
MaxBytesPerRequest() int MaxBytesPerRequest() int
// Destroy internal state
Destroy()
} }
type BaseDrbg struct { type BaseDrbg struct {
@ -258,6 +262,26 @@ func (hd *BaseDrbg) setSecurityLevel(securityLevel SecurityLevel) {
} }
} }
// Destroy 对 GM/T 0105-2021 B.2、E.2 对内部状态进行清零处理
// HASH RNG 内部状态组成为 {V,C, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
// HMAC/对称加密 RNG 内部状态组成为 {V,Key, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
func (hd *BaseDrbg) Destroy() {
setZero(hd.v)
hd.seedLength = 0
for i := 0; i < 3; i++ {
// 使用原子操作防止编译器优化
atomic.StoreUint64(&hd.reseedCounter, 0xFFFFFFFFFFFFFFFF)
atomic.StoreUint64(&hd.reseedCounter, 0x00)
atomic.StoreUint64(&hd.reseedIntervalInCounter, 0xFFFFFFFFFFFFFFFF)
atomic.StoreUint64(&hd.reseedIntervalInCounter, 0x00)
// 将 reseedIntervalInTime 设置内存屏障,防止编译器优化
hd.reseedIntervalInTime = time.Duration(1<<63 - 1)
runtime.KeepAlive(&hd.reseedIntervalInTime)
hd.reseedIntervalInTime = time.Duration(0)
hd.reseedTime = time.Now()
}
}
// Set security_strength to the lowest security strength greater than or equal to // Set security_strength to the lowest security strength greater than or equal to
// requested_instantiation_security_strength from the set {112, 128, 192, 256}. // requested_instantiation_security_strength from the set {112, 128, 192, 256}.
func selectSecurityStrength(requested int) int { func selectSecurityStrength(requested int) int {
@ -292,3 +316,26 @@ func addOne(data []byte, len int) {
temp >>= 8 temp >>= 8
} }
} }
// setZero tries best to clear the sensitive data in memory by overwriting it with 0xFF and 0 for 3 times.
// - data: the byte slice to be cleared.
func setZero(data []byte) {
if data == nil {
return
}
for j := 0; j < 3; j++ {
// 先写入0xFF
for i := range data {
data[i] = 0xFF
}
// 内存屏障确保写入0xFF完成
runtime.KeepAlive(data)
// 再写入0
for i := range data {
data[i] = 0
}
// 再次内存屏障确保写入0完成
runtime.KeepAlive(data)
}
}

View File

@ -95,7 +95,6 @@ func TestNistHashDrbgPrng(t *testing.T) {
} }
} }
func TestNistHmacDrbgPrng(t *testing.T) { func TestNistHmacDrbgPrng(t *testing.T) {
prng, err := NewNistHmacDrbgPrng(sha256.New, nil, 32, SECURITY_LEVEL_TEST, nil) prng, err := NewNistHmacDrbgPrng(sha256.New, nil, 32, SECURITY_LEVEL_TEST, nil)
if err != nil { if err != nil {
@ -121,3 +120,24 @@ func TestGMSecurityStrengthValidation(t *testing.T) {
t.Fatalf("expected error here") t.Fatalf("expected error here")
} }
} }
func Test_setZero(t *testing.T) {
cases := []struct {
name string
args []byte
}{
{"nil", nil},
{"empty", []byte{}},
{"normal", []byte{1, 2, 3, 4, 5}},
{"large", bytes.Repeat([]byte{1, 2, 3, 4, 5}, 100)},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
setZero(tt.args)
if !bytes.Equal(tt.args, make([]byte, len(tt.args))) {
t.Errorf("setZero() = %v, want %v", tt.args, make([]byte, len(tt.args)))
}
})
}
}

View File

@ -222,3 +222,10 @@ func (cd *CtrDrbg) bcc(block cipher.Block, data []byte) []byte {
} }
return chainingValue return chainingValue
} }
// Destroy destroys the internal state of DRBG instance
// 对称加密的RNG内部状态组成为 {V,Key, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
func (cd *CtrDrbg) Destroy() {
cd.BaseDrbg.Destroy()
setZero(cd.key)
}

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/rand"
"encoding/hex" "encoding/hex"
"testing" "testing"
@ -303,3 +304,19 @@ func TestGmCtrDRBG_Validation(t *testing.T) {
t.Fatalf("expected error here") t.Fatalf("expected error here")
} }
} }
func TestCtrDrbg_Destroy(t *testing.T) {
entropyInput := make([]byte, 64)
_, _ = rand.Reader.Read(entropyInput)
cd, err := NewCtrDrbg(sm4.NewCipher, 16, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:64], nil)
if err != nil {
t.Errorf("NewCtrDrbg failed: %v", err)
}
cd.Destroy()
if !bytes.Equal(cd.key, make([]byte, len(cd.key))) {
t.Errorf("Destroy failed: v not zeroed")
}
if !bytes.Equal(cd.v, make([]byte, len(cd.v))) {
t.Errorf("Destroy failed: key not zeroed")
}
}

View File

@ -222,3 +222,10 @@ func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte {
} }
return k return k
} }
// Destroy destroys the internal state of DRBG instance
// HASH 内部状态组成为 {V,C, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
func (hd *HashDrbg) Destroy() {
hd.BaseDrbg.Destroy()
setZero(hd.c)
}

View File

@ -2,6 +2,7 @@ package drbg
import ( import (
"bytes" "bytes"
"crypto/rand"
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
@ -249,3 +250,19 @@ func TestGmHashDRBG_Validation(t *testing.T) {
t.Fatalf("expected error here") t.Fatalf("expected error here")
} }
} }
func TestHashDrbg_Destroy(t *testing.T) {
entropyInput := make([]byte, 64)
_, _ = rand.Reader.Read(entropyInput)
hd, err := NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil)
if err != nil {
t.Errorf("NewHashDrbg failed: %v", err)
}
hd.Destroy()
if !bytes.Equal(hd.c, make([]byte, len(hd.c))) {
t.Errorf("Destroy failed: v not zeroed")
}
if !bytes.Equal(hd.v, make([]byte, len(hd.v))) {
t.Errorf("Destroy failed: key not zeroed")
}
}

View File

@ -153,3 +153,10 @@ func (hd *HmacDrbg) update(byteSlices ...[]byte) error {
hd.v = md.Sum(hd.v[:0]) hd.v = md.Sum(hd.v[:0])
return nil return nil
} }
// Destroy destroys the internal state of DRBG instance
// HMAC的RNG内部状态组成为 {V,Key, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
func (hd *HmacDrbg) Destroy() {
hd.BaseDrbg.Destroy()
setZero(hd.key)
}

View File

@ -2,12 +2,15 @@ package drbg
import ( import (
"bytes" "bytes"
"crypto/rand"
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"encoding/hex" "encoding/hex"
"hash" "hash"
"testing" "testing"
"github.com/emmansun/gmsm/sm3"
) )
var hmactests = []struct { var hmactests = []struct {
@ -802,3 +805,19 @@ func TestHmacDRBG(t *testing.T) {
} }
} }
} }
func TestHmacDrbg_Destroy(t *testing.T) {
entropyInput := make([]byte, 64)
_, _ = rand.Reader.Read(entropyInput)
hd, err := NewHmacDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil)
if err != nil {
t.Errorf("NewHmacDrbg failed: %v", err)
}
hd.Destroy()
if !bytes.Equal(hd.key, make([]byte, len(hd.key))) {
t.Errorf("Destroy failed: v not zeroed")
}
if !bytes.Equal(hd.v, make([]byte, len(hd.v))) {
t.Errorf("Destroy failed: key not zeroed")
}
}