完成所有的加密和加密链接

This commit is contained in:
eson
2023-07-28 12:15:56 +08:00
parent 3be161a011
commit 66808fc735
8 changed files with 422 additions and 99 deletions

View File

@@ -4,13 +4,13 @@ import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"math/rand"
)
// 必须16字节
var key = "fusen20230405145"
var cbckey = "fusen20230405145"
// 加密(key必须16字节),前端加解密需要先把base64转字符串再取前16字节作为iv
func CBCEncrypt(data string) (string, error) {
@@ -19,11 +19,11 @@ func CBCEncrypt(data string) (string, error) {
fmt.Println("cbc decrypt err:", err)
}
}()
block, err := aes.NewCipher([]byte(key))
block, err := aes.NewCipher([]byte(cbckey))
if err != nil {
return "", err
}
blockSize := len(key)
blockSize := len(cbckey)
padding := blockSize - len(data)%blockSize // 填充字节
if padding == 0 {
padding = blockSize
@@ -47,7 +47,7 @@ func CBCDecrypt(src string) (string, error) {
fmt.Println("cbc decrypt err:", err)
}
}()
block, err := aes.NewCipher([]byte(key))
block, err := aes.NewCipher([]byte(cbckey))
if err != nil {
return "", err
}

View File

@@ -0,0 +1,102 @@
package encryption_decryption
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/gob"
"sync"
)
type ISecretEncDec interface {
EncodeToString([]byte) string
DecodeString(string) ([]byte, error)
}
type SecretCRT[T any] struct {
srcKey string
secretKey []byte
iv []byte
derivationKey func(keysting string) []byte
mu sync.Mutex
EncDec ISecretEncDec
}
func NewSecretCRT[T any](key string, iv string) *SecretCRT[T] {
s := &SecretCRT[T]{
derivationKey: DerivationKeyV1,
iv: []byte(iv),
EncDec: base64.URLEncoding,
}
s.secretKey = s.derivationKey(key)
return s
}
func (s *SecretCRT[T]) UpdateDerivationKeyFunc(kfunc func(keysting string) []byte) {
s.mu.Lock()
defer s.mu.Unlock()
s.derivationKey = kfunc
s.secretKey = s.derivationKey(s.srcKey)
}
func (s *SecretCRT[T]) Encrypt(gobj *T) (string, error) {
s.mu.Lock()
defer s.mu.Unlock()
var buf = bytes.NewBuffer(nil)
err := gob.NewEncoder(buf).Encode(gobj)
if err != nil {
return "", err
}
// 使用AES加密,返回一个Block接口
block, err := aes.NewCipher(s.secretKey)
if err != nil {
panic(err)
}
// 使用CTR模式
stream := cipher.NewCTR(block, s.iv)
// 加密明文
plaintext := buf.Bytes()
ciphertext := make([]byte, len(plaintext))
stream.XORKeyStream(ciphertext, plaintext)
// 转为hex编码打印出来
return s.EncDec.EncodeToString(ciphertext), nil
}
func (s *SecretCRT[T]) Decrypt(ciphertext string) (*T, error) {
// 将hex解码成[]byte
ciphertextbytes, err := s.EncDec.DecodeString(ciphertext)
if err != nil {
return nil, err
}
// 生成Block接口
block, err := aes.NewCipher(s.secretKey)
if err != nil {
panic(err)
}
// 生成CTR模式
stream := cipher.NewCTR(block, s.iv)
// 解密密文
plaintext := make([]byte, len(ciphertextbytes))
stream.XORKeyStream(plaintext, ciphertextbytes)
// 解出golang的结构体
var protected T
var buf = bytes.NewBuffer(plaintext)
err = gob.NewDecoder(buf).Decode(&protected)
if err != nil {
return nil, err
}
return &protected, nil
}

View File

@@ -0,0 +1,129 @@
package encryption_decryption
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/gob"
"fmt"
"io"
"sync"
)
func DerivationKeyV1(keysting string) []byte {
key := []byte(keysting)
var result [16]byte
// If key length is more than 32, truncate it
if len(key) > 16 {
key = key[:16]
}
// If key length is less than 32, replicate it until it reaches 32
for len(key) < 16 {
key = append(key, key...)
}
// Only take the first 32 bytes
key = key[:16]
// Swap the first 16 bytes with the last 16 bytes
copy(result[:], key[8:])
copy(result[8:], key[:8])
return result[:]
}
type SecretGCM[T any] struct {
srcKey string
secretKey []byte
derivationKey func(keysting string) []byte
mu sync.Mutex
EncDec ISecretEncDec
}
func NewSecretGCM[T any](key string) *SecretGCM[T] {
s := &SecretGCM[T]{
srcKey: key,
derivationKey: DerivationKeyV1,
EncDec: base64.URLEncoding,
}
s.secretKey = s.derivationKey(s.srcKey)
return s
}
func (s *SecretGCM[T]) UpdateDerivationKeyFunc(kfunc func(keysting string) []byte) {
s.mu.Lock()
defer s.mu.Unlock()
s.derivationKey = kfunc
s.secretKey = s.derivationKey(s.srcKey)
}
func (s *SecretGCM[T]) Encrypt(gobj *T) (string, error) {
s.mu.Lock()
defer s.mu.Unlock()
var buf = bytes.NewBuffer(nil)
err := gob.NewEncoder(buf).Encode(gobj)
if err != nil {
return "", err
}
block, err := aes.NewCipher(s.secretKey)
if err != nil {
return "", err
}
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
ciphertext := aesgcm.Seal(nonce, nonce, buf.Bytes(), nil)
return s.EncDec.EncodeToString(ciphertext), nil
}
func (s *SecretGCM[T]) Decrypt(ciphertext string) (*T, error) {
block, err := aes.NewCipher(s.secretKey)
if err != nil {
return nil, err
}
ct, err := s.EncDec.DecodeString(ciphertext)
if err != nil {
return nil, err
}
if len(ct) < 12 {
return nil, fmt.Errorf("ciphertext too short")
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
plaintext, err := aesgcm.Open(nil, ct[:12], ct[12:], nil)
if err != nil {
return nil, err
}
// 解出golang的结构体
var protected T
var buf = bytes.NewBuffer(plaintext)
err = gob.NewDecoder(buf).Decode(&protected)
if err != nil {
return nil, err
}
return &protected, nil
}

View File

@@ -0,0 +1,90 @@
package encryption_decryption_test
import (
"fusenapi/utils/auth"
"fusenapi/utils/encryption_decryption"
"log"
"testing"
)
func TestGCM(t *testing.T) {
token := &auth.RegisterToken{
OperateType: auth.OpTypeRegister,
Password: "fusen_password",
WCId: 123,
}
key := "fusen123321"
gcm := encryption_decryption.NewSecretGCM[auth.RegisterToken](key)
tstr, err := gcm.Encrypt(token)
if err != nil {
t.Error(err)
}
log.Println(tstr)
log.Println(gcm.Decrypt(tstr))
}
func BenchmarkCRT(b *testing.B) {
token := &auth.RegisterToken{
OperateType: auth.OpTypeRegister,
Password: "fusen_password",
WCId: 123,
}
key := "fusen123321"
iv := "1234567890123456"
for i := 0; i < b.N; i++ {
crt := encryption_decryption.NewSecretCRT[auth.RegisterToken](key, iv)
tstr, err := crt.Encrypt(token)
if err != nil {
b.Error(err)
}
crt.Decrypt(tstr)
}
}
func BenchmarkGCM(b *testing.B) {
token := &auth.RegisterToken{
OperateType: auth.OpTypeRegister,
Password: "fusen_password",
WCId: 123,
}
key := "fusen123321"
for i := 0; i < b.N; i++ {
crt := encryption_decryption.NewSecretGCM[auth.RegisterToken](key)
tstr, err := crt.Encrypt(token)
if err != nil {
b.Error(err)
}
crt.Decrypt(tstr)
}
}
func TestCRT(t *testing.T) {
token := &auth.RegisterToken{
OperateType: auth.OpTypeRegister,
Password: "fusen_password",
WCId: 123,
}
key := "fusen123321"
iv := "1234567890123456"
crt := encryption_decryption.NewSecretCRT[auth.RegisterToken](key, iv)
tstr, err := crt.Encrypt(token)
if err != nil {
t.Error(err)
}
log.Println(tstr)
log.Println(crt.Decrypt(tstr))
}