Skip to content

Commit 62ee2eb

Browse files
authored
增加了DRBG销毁内部状态的方法 (#378)
* 增加了DRBG销毁内部状态的方法 * 统一前缀 * 修改随机数长度 * 分组和注释 * 错误函数描述
1 parent c234076 commit 62ee2eb

8 files changed

Lines changed: 143 additions & 2 deletions

File tree

drbg/common.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"errors"
88
"hash"
99
"io"
10+
"runtime"
11+
"sync/atomic"
1012
"time"
1113

1214
"github.com/emmansun/gmsm/sm3"
@@ -226,6 +228,8 @@ type DRBG interface {
226228
Generate(b, additional []byte) error
227229
// MaxBytesPerRequest return max bytes per request
228230
MaxBytesPerRequest() int
231+
// Destroy internal state
232+
Destroy()
229233
}
230234

231235
type BaseDrbg struct {
@@ -258,6 +262,26 @@ func (hd *BaseDrbg) setSecurityLevel(securityLevel SecurityLevel) {
258262
}
259263
}
260264

265+
// Destroy 对 GM/T 0105-2021 B.2、E.2 对内部状态进行清零处理
266+
// HASH RNG 内部状态组成为 {V,C, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
267+
// HMAC/对称加密 RNG 内部状态组成为 {V,Key, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
268+
func (hd *BaseDrbg) Destroy() {
269+
setZero(hd.v)
270+
hd.seedLength = 0
271+
for i := 0; i < 3; i++ {
272+
// 使用原子操作防止编译器优化
273+
atomic.StoreUint64(&hd.reseedCounter, 0xFFFFFFFFFFFFFFFF)
274+
atomic.StoreUint64(&hd.reseedCounter, 0x00)
275+
atomic.StoreUint64(&hd.reseedIntervalInCounter, 0xFFFFFFFFFFFFFFFF)
276+
atomic.StoreUint64(&hd.reseedIntervalInCounter, 0x00)
277+
// 将 reseedIntervalInTime 设置内存屏障,防止编译器优化
278+
hd.reseedIntervalInTime = time.Duration(1<<63 - 1)
279+
runtime.KeepAlive(&hd.reseedIntervalInTime)
280+
hd.reseedIntervalInTime = time.Duration(0)
281+
hd.reseedTime = time.Now()
282+
}
283+
}
284+
261285
// Set security_strength to the lowest security strength greater than or equal to
262286
// requested_instantiation_security_strength from the set {112, 128, 192, 256}.
263287
func selectSecurityStrength(requested int) int {
@@ -292,3 +316,26 @@ func addOne(data []byte, len int) {
292316
temp >>= 8
293317
}
294318
}
319+
320+
// setZero tries best to clear the sensitive data in memory by overwriting it with 0xFF and 0 for 3 times.
321+
// - data: the byte slice to be cleared.
322+
func setZero(data []byte) {
323+
if data == nil {
324+
return
325+
}
326+
for j := 0; j < 3; j++ {
327+
// 先写入0xFF
328+
for i := range data {
329+
data[i] = 0xFF
330+
}
331+
// 内存屏障,确保写入0xFF完成
332+
runtime.KeepAlive(data)
333+
334+
// 再写入0
335+
for i := range data {
336+
data[i] = 0
337+
}
338+
// 再次内存屏障,确保写入0完成
339+
runtime.KeepAlive(data)
340+
}
341+
}

drbg/common_test.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ func TestNistHashDrbgPrng(t *testing.T) {
9595
}
9696
}
9797

98-
9998
func TestNistHmacDrbgPrng(t *testing.T) {
10099
prng, err := NewNistHmacDrbgPrng(sha256.New, nil, 32, SECURITY_LEVEL_TEST, nil)
101100
if err != nil {
@@ -121,3 +120,24 @@ func TestGMSecurityStrengthValidation(t *testing.T) {
121120
t.Fatalf("expected error here")
122121
}
123122
}
123+
124+
func Test_setZero(t *testing.T) {
125+
126+
cases := []struct {
127+
name string
128+
args []byte
129+
}{
130+
{"nil", nil},
131+
{"empty", []byte{}},
132+
{"normal", []byte{1, 2, 3, 4, 5}},
133+
{"large", bytes.Repeat([]byte{1, 2, 3, 4, 5}, 100)},
134+
}
135+
for _, tt := range cases {
136+
t.Run(tt.name, func(t *testing.T) {
137+
setZero(tt.args)
138+
if !bytes.Equal(tt.args, make([]byte, len(tt.args))) {
139+
t.Errorf("setZero() = %v, want %v", tt.args, make([]byte, len(tt.args)))
140+
}
141+
})
142+
}
143+
}

drbg/ctr_drbg.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (cd *CtrDrbg) update(seedMaterial []byte) {
162162
v := make([]byte, outlen)
163163
output := make([]byte, outlen)
164164
copy(v, cd.v)
165-
for i := range (cd.seedLength+outlen-1)/outlen {
165+
for i := range (cd.seedLength + outlen - 1) / outlen {
166166
// V = (V + 1) mod 2^outlen
167167
addOne(v, outlen)
168168
// output_block = Encrypt(Key, V)
@@ -222,3 +222,10 @@ func (cd *CtrDrbg) bcc(block cipher.Block, data []byte) []byte {
222222
}
223223
return chainingValue
224224
}
225+
226+
// Destroy destroys the internal state of DRBG instance
227+
// 对称加密的RNG内部状态组成为 {V,Key, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
228+
func (cd *CtrDrbg) Destroy() {
229+
cd.BaseDrbg.Destroy()
230+
setZero(cd.key)
231+
}

drbg/ctr_drbg_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"crypto/aes"
66
"crypto/cipher"
7+
"crypto/rand"
78
"encoding/hex"
89
"testing"
910

@@ -303,3 +304,19 @@ func TestGmCtrDRBG_Validation(t *testing.T) {
303304
t.Fatalf("expected error here")
304305
}
305306
}
307+
308+
func TestCtrDrbg_Destroy(t *testing.T) {
309+
entropyInput := make([]byte, 64)
310+
_, _ = rand.Reader.Read(entropyInput)
311+
cd, err := NewCtrDrbg(sm4.NewCipher, 16, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:64], nil)
312+
if err != nil {
313+
t.Errorf("NewCtrDrbg failed: %v", err)
314+
}
315+
cd.Destroy()
316+
if !bytes.Equal(cd.key, make([]byte, len(cd.key))) {
317+
t.Errorf("Destroy failed: v not zeroed")
318+
}
319+
if !bytes.Equal(cd.v, make([]byte, len(cd.v))) {
320+
t.Errorf("Destroy failed: key not zeroed")
321+
}
322+
}

drbg/hash_drbg.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,10 @@ func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte {
222222
}
223223
return k
224224
}
225+
226+
// Destroy destroys the internal state of DRBG instance
227+
// HASH 内部状态组成为 {V,C, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
228+
func (hd *HashDrbg) Destroy() {
229+
hd.BaseDrbg.Destroy()
230+
setZero(hd.c)
231+
}

drbg/hash_drbg_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package drbg
22

33
import (
44
"bytes"
5+
"crypto/rand"
56
"crypto/sha1"
67
"crypto/sha256"
78
"crypto/sha512"
@@ -249,3 +250,19 @@ func TestGmHashDRBG_Validation(t *testing.T) {
249250
t.Fatalf("expected error here")
250251
}
251252
}
253+
254+
func TestHashDrbg_Destroy(t *testing.T) {
255+
entropyInput := make([]byte, 64)
256+
_, _ = rand.Reader.Read(entropyInput)
257+
hd, err := NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil)
258+
if err != nil {
259+
t.Errorf("NewHashDrbg failed: %v", err)
260+
}
261+
hd.Destroy()
262+
if !bytes.Equal(hd.c, make([]byte, len(hd.c))) {
263+
t.Errorf("Destroy failed: v not zeroed")
264+
}
265+
if !bytes.Equal(hd.v, make([]byte, len(hd.v))) {
266+
t.Errorf("Destroy failed: key not zeroed")
267+
}
268+
}

drbg/hmac_drbg.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,10 @@ func (hd *HmacDrbg) update(byteSlices ...[]byte) error {
153153
hd.v = md.Sum(hd.v[:0])
154154
return nil
155155
}
156+
157+
// Destroy destroys the internal state of DRBG instance
158+
// HMAC的RNG内部状态组成为 {V,Key, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
159+
func (hd *HmacDrbg) Destroy() {
160+
hd.BaseDrbg.Destroy()
161+
setZero(hd.key)
162+
}

drbg/hmac_drbg_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ package drbg
22

33
import (
44
"bytes"
5+
"crypto/rand"
56
"crypto/sha1"
67
"crypto/sha256"
78
"crypto/sha512"
89
"encoding/hex"
910
"hash"
1011
"testing"
12+
13+
"github.com/emmansun/gmsm/sm3"
1114
)
1215

1316
var hmactests = []struct {
@@ -802,3 +805,19 @@ func TestHmacDRBG(t *testing.T) {
802805
}
803806
}
804807
}
808+
809+
func TestHmacDrbg_Destroy(t *testing.T) {
810+
entropyInput := make([]byte, 64)
811+
_, _ = rand.Reader.Read(entropyInput)
812+
hd, err := NewHmacDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil)
813+
if err != nil {
814+
t.Errorf("NewHmacDrbg failed: %v", err)
815+
}
816+
hd.Destroy()
817+
if !bytes.Equal(hd.key, make([]byte, len(hd.key))) {
818+
t.Errorf("Destroy failed: v not zeroed")
819+
}
820+
if !bytes.Equal(hd.v, make([]byte, len(hd.v))) {
821+
t.Errorf("Destroy failed: key not zeroed")
822+
}
823+
}

0 commit comments

Comments
 (0)