init: v1.0.0
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
package sdf
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/pbkd"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
)
|
||||
|
||||
/*
|
||||
Example of snapshot:
|
||||
{
|
||||
"keys":[
|
||||
{
|
||||
"type": "Sm2SignKey",
|
||||
"url": "sm2sign/12",
|
||||
"material": ["base64(d)", "base64(04||x||y)"]
|
||||
},
|
||||
{
|
||||
"type": "Sm2SignKey",
|
||||
"url": "sm2enc/12",
|
||||
"material": ["base64(d)", "base64(04||x||y)"]
|
||||
},
|
||||
{
|
||||
"type": "BlockKey",
|
||||
"url": "kek/0",
|
||||
"material": ["base64(key)"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
*/
|
||||
type KeyMaterial struct {
|
||||
Type string `json:"type"`
|
||||
Url string `json:"url"`
|
||||
Nonces [][]byte `json:"nonces"` // coresponding to each Material, with add Url
|
||||
Materials [][]byte `json:"materials"`
|
||||
}
|
||||
|
||||
type EncParam struct {
|
||||
Algo string `json:"algo"` // only "sm4_gcm" are supported
|
||||
Salt []byte `json:"salt"`
|
||||
Count uint32 `json:"count"`
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Time time.Time `json:"time"`
|
||||
Info string `json:"info"`
|
||||
Enc bool `json:"enc"`
|
||||
EncParam *EncParam `json:"encParam"`
|
||||
Keys []*KeyMaterial `json:"keys"`
|
||||
}
|
||||
|
||||
func (s *SdfNoLock) Snapshot(enc bool, password []byte, count int) (*Snapshot, error) {
|
||||
|
||||
snapshot := &Snapshot{
|
||||
Time: time.Now(),
|
||||
Enc: enc,
|
||||
Keys: make([]*KeyMaterial, 0),
|
||||
}
|
||||
var aead cipher.AEAD
|
||||
var nonces [][]byte
|
||||
|
||||
if enc {
|
||||
var salt []byte
|
||||
var err error
|
||||
var n uint32
|
||||
salt = make([]byte, 16)
|
||||
if n, err = s.SDF_GenerateRandom(salt); err != nil || n != uint32(len(salt)) {
|
||||
return nil, err
|
||||
}
|
||||
var encryptionKey []byte
|
||||
if encryptionKey, err = pbkd.PbkdfWithHmacSm3(password, salt, count, sm4.BlockSize); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if aead, err = sm4.NewGCM(encryptionKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonces = [][]byte{
|
||||
make([]byte, aead.NonceSize()),
|
||||
make([]byte, aead.NonceSize()),
|
||||
}
|
||||
|
||||
snapshot.EncParam = &EncParam{
|
||||
Algo: "sm4_gcm",
|
||||
Salt: salt,
|
||||
Count: uint32(count),
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range s.Sm2Key {
|
||||
if v.signKey != nil {
|
||||
sk := v.signKey.Bytes()
|
||||
pk := v.signKey.PublicKey.Bytes()
|
||||
url := fmt.Sprintf("sm2sign/%d", k)
|
||||
thisNonces := nonces
|
||||
if aead != nil {
|
||||
s.SDF_GenerateRandom(nonces[0])
|
||||
s.SDF_GenerateRandom(nonces[1])
|
||||
thisNonces = [][]byte{
|
||||
append([]byte{}, nonces[0]...),
|
||||
append([]byte{}, nonces[1]...),
|
||||
}
|
||||
sk = aead.Seal(sk[:0], nonces[0], sk, []byte(url))
|
||||
pk = aead.Seal(pk[:0], nonces[1], pk, []byte(url))
|
||||
}
|
||||
km := &KeyMaterial{
|
||||
Type: KeyTypeSm2Sign.String(),
|
||||
Url: url,
|
||||
Nonces: thisNonces,
|
||||
Materials: [][]byte{sk, pk},
|
||||
}
|
||||
snapshot.Keys = append(snapshot.Keys, km)
|
||||
}
|
||||
|
||||
if v.encKey != nil {
|
||||
sk := v.encKey.Bytes()
|
||||
pk := v.encKey.PublicKey.Bytes()
|
||||
url := fmt.Sprintf("sm2enc/%d", k)
|
||||
thisNonces := nonces
|
||||
if aead != nil {
|
||||
s.SDF_GenerateRandom(nonces[0])
|
||||
s.SDF_GenerateRandom(nonces[1])
|
||||
thisNonces = [][]byte{
|
||||
append([]byte{}, nonces[0]...),
|
||||
append([]byte{}, nonces[1]...),
|
||||
}
|
||||
sk = aead.Seal(sk[:0], nonces[0], sk, []byte(url))
|
||||
pk = aead.Seal(pk[:0], nonces[1], pk, []byte(url))
|
||||
}
|
||||
km := &KeyMaterial{
|
||||
Type: KeyTypeSm2Enc.String(),
|
||||
Url: url,
|
||||
Nonces: thisNonces,
|
||||
Materials: [][]byte{sk, pk},
|
||||
}
|
||||
snapshot.Keys = append(snapshot.Keys, km)
|
||||
}
|
||||
}
|
||||
for k, v := range s.SymKey {
|
||||
key := make([]byte, len(v.key), len(v.key)+16)
|
||||
url := fmt.Sprintf("kek/%d", k)
|
||||
thisNonces := nonces
|
||||
copy(key, v.key)
|
||||
if aead != nil {
|
||||
s.SDF_GenerateRandom(nonces[0])
|
||||
thisNonces = [][]byte{
|
||||
append([]byte{}, nonces[0]...),
|
||||
}
|
||||
key = aead.Seal(key[:0], nonces[0], key, []byte(url))
|
||||
}
|
||||
|
||||
km := &KeyMaterial{
|
||||
Type: v.keyType.String(),
|
||||
Url: url,
|
||||
Nonces: thisNonces,
|
||||
Materials: [][]byte{key},
|
||||
}
|
||||
snapshot.Keys = append(snapshot.Keys, km)
|
||||
}
|
||||
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func (s *SdfNoLock) Restore(ss *Snapshot, password []byte) error {
|
||||
var sdf = &SdfNoLock{
|
||||
RsaKey: make(map[uint32]*RsaKey),
|
||||
Sm2Key: make(map[uint32]*Sm2Key),
|
||||
SymKey: make(map[uint32]*SymKey),
|
||||
}
|
||||
var aead cipher.AEAD
|
||||
var err error
|
||||
if ss.Enc {
|
||||
var encryptionKey []byte
|
||||
if encryptionKey, err = pbkd.PbkdfWithHmacSm3([]byte(password), ss.EncParam.Salt, int(ss.EncParam.Count), sm4.BlockSize); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if aead, err = sm4.NewGCM(encryptionKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, k := range ss.Keys {
|
||||
if k == nil {
|
||||
return fmt.Errorf("nil key")
|
||||
}
|
||||
switch GetKeyType(k.Type) {
|
||||
case KeyTypeBlock:
|
||||
if len(k.Materials) != 1 || len(k.Nonces) != len(k.Materials) {
|
||||
return fmt.Errorf("key material error")
|
||||
}
|
||||
key := k.Materials[0]
|
||||
if aead != nil {
|
||||
key, err = aead.Open(nil, k.Nonces[0], key, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
urlSplits := strings.Split(k.Url, "/")
|
||||
if len(urlSplits) != 2 {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
if strings.TrimSpace(urlSplits[0]) != "kek" {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
index, err := strconv.Atoi(urlSplits[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("key url error")
|
||||
} else {
|
||||
sdf.SymKey[uint32(index)] = &SymKey{
|
||||
keyType: KeyTypeBlock,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
case KeyTypeSm2Sign:
|
||||
if len(k.Materials) != 2 || len(k.Nonces) != len(k.Materials) {
|
||||
return fmt.Errorf("key material error")
|
||||
}
|
||||
sk := k.Materials[0]
|
||||
pk := k.Materials[1]
|
||||
if aead != nil {
|
||||
sk, err = aead.Open(nil, k.Nonces[0], sk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pk, err = aead.Open(nil, k.Nonces[1], pk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
urlSplits := strings.Split(k.Url, "/")
|
||||
if len(urlSplits) != 2 {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
if strings.TrimSpace(urlSplits[0]) != "sm2sign" {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
index, err := strconv.Atoi(urlSplits[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("key url error")
|
||||
} else {
|
||||
sm2PrivateKey := &sm2.PrivateKey{
|
||||
D: new(big.Int).SetBytes(sk),
|
||||
}
|
||||
sm2PrivateKey.PublicKey.Curve = sm2.Curve()
|
||||
sm2PrivateKey.PublicKey.X = new(big.Int).SetBytes(pk[:sm2.ByteSize()])
|
||||
sm2PrivateKey.PublicKey.Y = new(big.Int).SetBytes(pk[sm2.ByteSize():])
|
||||
|
||||
if _, ok := sdf.Sm2Key[uint32(index)]; !ok {
|
||||
sdf.Sm2Key[uint32(index)] = &Sm2Key{}
|
||||
}
|
||||
sdf.Sm2Key[uint32(index)].signKey = sm2PrivateKey
|
||||
}
|
||||
|
||||
case KeyTypeSm2Enc:
|
||||
if len(k.Materials) != 2 || len(k.Nonces) != len(k.Materials) {
|
||||
return fmt.Errorf("key material error")
|
||||
}
|
||||
sk := k.Materials[0]
|
||||
pk := k.Materials[1]
|
||||
if aead != nil {
|
||||
sk, err = aead.Open(nil, k.Nonces[0], sk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pk, err = aead.Open(nil, k.Nonces[1], pk, []byte(k.Url))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
urlSplits := strings.Split(k.Url, "/")
|
||||
if len(urlSplits) != 2 {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
if strings.TrimSpace(urlSplits[0]) != "sm2enc" {
|
||||
return fmt.Errorf("key url error")
|
||||
}
|
||||
index, err := strconv.Atoi(urlSplits[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("key url error")
|
||||
} else {
|
||||
sm2PrivateKey := &sm2.PrivateKey{
|
||||
D: new(big.Int).SetBytes(sk),
|
||||
}
|
||||
sm2PrivateKey.PublicKey.Curve = sm2.Curve()
|
||||
sm2PrivateKey.PublicKey.X = new(big.Int).SetBytes(pk[:sm2.ByteSize()])
|
||||
sm2PrivateKey.PublicKey.Y = new(big.Int).SetBytes(pk[sm2.ByteSize():])
|
||||
|
||||
if _, ok := sdf.Sm2Key[uint32(index)]; !ok {
|
||||
sdf.Sm2Key[uint32(index)] = &Sm2Key{}
|
||||
}
|
||||
sdf.Sm2Key[uint32(index)].encKey = sm2PrivateKey
|
||||
}
|
||||
case KeyTypeSm1:
|
||||
fallthrough
|
||||
case KeyTypeSm4:
|
||||
fallthrough
|
||||
case KeyTypeSm9MasterSign:
|
||||
fallthrough
|
||||
case KeyTypeSm9MasterEnc:
|
||||
fallthrough
|
||||
case KeyTypeSm9UserSign:
|
||||
fallthrough
|
||||
case KeyTypeSm9UserEnc:
|
||||
fallthrough
|
||||
case KeyTypeRsa:
|
||||
fallthrough
|
||||
default:
|
||||
return fmt.Errorf("key type errror")
|
||||
}
|
||||
}
|
||||
|
||||
// now copy sdf to s
|
||||
s.Sm2Key = sdf.Sm2Key
|
||||
s.SymKey = sdf.SymKey
|
||||
s.RsaKey = sdf.RsaKey
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user