77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
package immessagecrypto
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/binary"
|
|
"hotgo/internal/consts"
|
|
"hotgo/internal/dao"
|
|
"hotgo/utility/encrypt"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
)
|
|
|
|
func GenerateDEK() ([]byte, error) {
|
|
key := make([]byte, encrypt.AESGCMKeySize)
|
|
if _, err := rand.Read(key); err != nil {
|
|
return nil, gerror.Wrap(err, "生成商户消息密钥失败")
|
|
}
|
|
return key, nil
|
|
}
|
|
|
|
func WrapDEK(ctx context.Context, tenantID int64, version uint, dek []byte) (ciphertext, nonce []byte, err error) {
|
|
kek, err := loadRootKEK(ctx)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return encrypt.AESGCMEncrypt(dek, kek, keyAAD(tenantID, version))
|
|
}
|
|
|
|
func UnwrapDEK(ctx context.Context, tenantID int64, version uint, ciphertext, nonce []byte) ([]byte, error) {
|
|
kek, err := loadRootKEK(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dek, err := encrypt.AESGCMDecrypt(ciphertext, nonce, kek, keyAAD(tenantID, version))
|
|
if err != nil {
|
|
return nil, gerror.Wrap(err, "解包商户消息密钥失败")
|
|
}
|
|
if len(dek) != encrypt.AESGCMKeySize {
|
|
return nil, gerror.New("商户消息密钥长度不正确")
|
|
}
|
|
return dek, nil
|
|
}
|
|
|
|
func EncodeDEK(dek []byte) string {
|
|
return base64.StdEncoding.EncodeToString(dek)
|
|
}
|
|
|
|
func loadRootKEK(ctx context.Context) ([]byte, error) {
|
|
columns := dao.SysDictData.Columns()
|
|
value, err := dao.SysDictData.Ctx(ctx).
|
|
Fields(columns.Value).
|
|
Where(columns.Type, consts.ImInternalSecretDictType).
|
|
Where(columns.Label, consts.ImMessageRootKEKLabel).
|
|
Where(columns.Status, consts.StatusEnabled).
|
|
Value()
|
|
if err != nil {
|
|
return nil, gerror.Wrap(err, "读取消息根密钥失败")
|
|
}
|
|
if value.IsEmpty() {
|
|
return nil, gerror.New("消息根密钥未初始化")
|
|
}
|
|
kek, err := base64.StdEncoding.DecodeString(value.String())
|
|
if err != nil || len(kek) != encrypt.AESGCMKeySize {
|
|
return nil, gerror.New("消息根密钥格式不正确")
|
|
}
|
|
return kek, nil
|
|
}
|
|
|
|
func keyAAD(tenantID int64, version uint) []byte {
|
|
aad := make([]byte, 16)
|
|
binary.BigEndian.PutUint64(aad[:8], uint64(tenantID))
|
|
binary.BigEndian.PutUint64(aad[8:], uint64(version))
|
|
return aad
|
|
}
|