mirror of
https://github.com/emmansun/gmsm.git
synced 2025-10-14 15:20:45 +08:00
增加了DRBG销毁内部状态的方法
This commit is contained in:
parent
5b12daceea
commit
a83ad6b5ae
@ -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 对内部状态进行清零处理
|
||||||
|
// 内部状态组成为 {V,C, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
|
||||||
|
// 内部状态组成为 {V,Key, reseed_counter, last_reseed_time,reseed_interval_in_counter, reseed_interval_in_time}
|
||||||
|
func (cd *BaseDrbg) Destroy() {
|
||||||
|
setZero(cd.v)
|
||||||
|
cd.seedLength = 0
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
// 使用原子操作防止编译器优化
|
||||||
|
atomic.StoreUint64(&cd.reseedCounter, 0xFFFFFFFFFFFFFFFF)
|
||||||
|
atomic.StoreUint64(&cd.reseedCounter, 0x00)
|
||||||
|
atomic.StoreUint64(&cd.reseedIntervalInCounter, 0xFFFFFFFFFFFFFFFF)
|
||||||
|
atomic.StoreUint64(&cd.reseedIntervalInCounter, 0x00)
|
||||||
|
// 将 reseedIntervalInTime 设置内存屏障,防止编译器优化
|
||||||
|
cd.reseedIntervalInTime = time.Duration(1<<63 - 1)
|
||||||
|
runtime.KeepAlive(&cd.reseedIntervalInTime)
|
||||||
|
cd.reseedIntervalInTime = time.Duration(0)
|
||||||
|
cd.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -162,7 +162,7 @@ func (cd *CtrDrbg) update(seedMaterial []byte) {
|
|||||||
v := make([]byte, outlen)
|
v := make([]byte, outlen)
|
||||||
output := make([]byte, outlen)
|
output := make([]byte, outlen)
|
||||||
copy(v, cd.v)
|
copy(v, cd.v)
|
||||||
for i := range (cd.seedLength+outlen-1)/outlen {
|
for i := range (cd.seedLength + outlen - 1) / outlen {
|
||||||
// V = (V + 1) mod 2^outlen
|
// V = (V + 1) mod 2^outlen
|
||||||
addOne(v, outlen)
|
addOne(v, outlen)
|
||||||
// output_block = Encrypt(Key, V)
|
// output_block = Encrypt(Key, V)
|
||||||
@ -222,3 +222,8 @@ func (cd *CtrDrbg) bcc(block cipher.Block, data []byte) []byte {
|
|||||||
}
|
}
|
||||||
return chainingValue
|
return chainingValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cd *CtrDrbg) Destroy() {
|
||||||
|
cd.BaseDrbg.Destroy()
|
||||||
|
setZero(cd.key)
|
||||||
|
}
|
||||||
|
@ -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[:16], entropyInput[16:24], 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -222,3 +222,10 @@ func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte {
|
|||||||
}
|
}
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destroy 根据 GM/T 0105-2021 B.2 对内部状态进行清零处理
|
||||||
|
// 内部状态组成为 {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)
|
||||||
|
}
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 根据 GM/T 0105-2021 E.2 对内部状态进行清零处理
|
||||||
|
// 内部状态组成为 {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)
|
||||||
|
}
|
||||||
|
@ -2,10 +2,12 @@ package drbg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"github.com/emmansun/gmsm/sm3"
|
||||||
"hash"
|
"hash"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -802,3 +804,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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user