mirror of
https://github.com/skyle1995/NetworkAuth.git
synced 2026-05-25 02:24:05 +08:00
Add the encrypt toolkit
This commit is contained in:
@@ -10,10 +10,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@@ -310,28 +307,51 @@ func APIGenerateKeysHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
result["private_key"] = ""
|
result["private_key"] = ""
|
||||||
case models.AlgorithmRC4:
|
case models.AlgorithmRC4:
|
||||||
// 生成16字节随机密钥并返回16位十六进制(大写)
|
// 生成16字节随机密钥并返回16位十六进制(大写)
|
||||||
bytes := make([]byte, 8)
|
key, err := encrypt.GenerateRC4Key(8) // 生成8字节密钥
|
||||||
if _, err := rand.Read(bytes); err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Error("Failed to generate RC4 key")
|
logrus.WithError(err).Error("Failed to generate RC4 key")
|
||||||
http.Error(w, "生成RC4密钥失败", http.StatusInternalServerError)
|
http.Error(w, "生成RC4密钥失败", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result["public_key"] = ""
|
result["public_key"] = ""
|
||||||
result["private_key"] = strings.ToUpper(hex.EncodeToString(bytes))
|
result["private_key"] = strings.ToUpper(hex.EncodeToString(key))
|
||||||
case models.AlgorithmRSA, models.AlgorithmRSADynamic:
|
case models.AlgorithmRSA:
|
||||||
// 生成RSA 2048密钥对,返回PEM明文字符串
|
// 生成标准RSA 2048密钥对,返回PEM明文字符串
|
||||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
publicKey, privateKey, err := encrypt.GenerateRSAKeyPair(2048)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Error("Failed to generate RSA key pair")
|
logrus.WithError(err).Error("Failed to generate RSA key pair")
|
||||||
http.Error(w, "生成RSA密钥失败", http.StatusInternalServerError)
|
http.Error(w, "生成RSA密钥失败", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
privBytes := x509.MarshalPKCS1PrivateKey(key)
|
|
||||||
pubBytes := x509.MarshalPKCS1PublicKey(&key.PublicKey)
|
// 转换为PEM格式
|
||||||
privPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes})
|
publicKeyPEM, err := encrypt.PublicKeyToPEM(publicKey)
|
||||||
pubPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: pubBytes})
|
if err != nil {
|
||||||
result["private_key"] = string(privPEM)
|
logrus.WithError(err).Error("Failed to convert public key to PEM")
|
||||||
result["public_key"] = string(pubPEM)
|
http.Error(w, "转换公钥格式失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKeyPEM, err := encrypt.PrivateKeyToPEM(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to convert private key to PEM")
|
||||||
|
http.Error(w, "转换私钥格式失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result["public_key"] = publicKeyPEM
|
||||||
|
result["private_key"] = privateKeyPEM
|
||||||
|
case models.AlgorithmRSADynamic:
|
||||||
|
// 生成RSA动态加密密钥对,返回PEM明文字符串
|
||||||
|
publicKeyPEM, privateKeyPEM, err := encrypt.GenerateRSADynamicKeyPair(2048)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to generate RSA dynamic key pair")
|
||||||
|
http.Error(w, "生成RSA动态密钥失败", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result["public_key"] = publicKeyPEM
|
||||||
|
result["private_key"] = privateKeyPEM
|
||||||
case models.AlgorithmEasy:
|
case models.AlgorithmEasy:
|
||||||
// 生成易加密密钥对,返回逗号分隔的整数数组字符串
|
// 生成易加密密钥对,返回逗号分隔的整数数组字符串
|
||||||
encryptKey, _, err := encrypt.GenerateEasyKey()
|
encryptKey, _, err := encrypt.GenerateEasyKey()
|
||||||
|
|||||||
112
utils/encrypt/rc4.go
Normal file
112
utils/encrypt/rc4.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package encrypt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RC4Encrypt RC4加密算法结构体
|
||||||
|
type RC4Encrypt struct {
|
||||||
|
key []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRC4Encrypt 创建新的RC4加密实例
|
||||||
|
func NewRC4Encrypt(key []byte) *RC4Encrypt {
|
||||||
|
return &RC4Encrypt{
|
||||||
|
key: key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRC4Key 生成RC4密钥
|
||||||
|
func GenerateRC4Key(length int) ([]byte, error) {
|
||||||
|
if length <= 0 || length > 256 {
|
||||||
|
length = 16 // 默认16字节密钥
|
||||||
|
}
|
||||||
|
|
||||||
|
key := make([]byte, length)
|
||||||
|
_, err := rand.Read(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("生成RC4密钥失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// rc4KeyScheduling RC4密钥调度算法(KSA)
|
||||||
|
func (r *RC4Encrypt) rc4KeyScheduling() []int {
|
||||||
|
s := make([]int, 256)
|
||||||
|
|
||||||
|
// 初始化S盒
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
s[i] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// 密钥调度
|
||||||
|
j := 0
|
||||||
|
keyLen := len(r.key)
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
j = (j + s[i] + int(r.key[i%keyLen])) % 256
|
||||||
|
s[i], s[j] = s[j], s[i] // 交换
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// rc4PseudoRandomGeneration RC4伪随机生成算法(PRGA)
|
||||||
|
func (r *RC4Encrypt) rc4PseudoRandomGeneration(s []int, data []byte) []byte {
|
||||||
|
result := make([]byte, len(data))
|
||||||
|
i, j := 0, 0
|
||||||
|
|
||||||
|
for k, b := range data {
|
||||||
|
i = (i + 1) % 256
|
||||||
|
j = (j + s[i]) % 256
|
||||||
|
s[i], s[j] = s[j], s[i] // 交换
|
||||||
|
|
||||||
|
keystream := s[(s[i]+s[j])%256]
|
||||||
|
result[k] = b ^ byte(keystream)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt RC4加密
|
||||||
|
func (r *RC4Encrypt) Encrypt(plaintext string) (string, error) {
|
||||||
|
if len(r.key) == 0 {
|
||||||
|
return "", fmt.Errorf("RC4密钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
data := []byte(plaintext)
|
||||||
|
s := r.rc4KeyScheduling()
|
||||||
|
encrypted := r.rc4PseudoRandomGeneration(s, data)
|
||||||
|
|
||||||
|
// Base64编码
|
||||||
|
return base64.StdEncoding.EncodeToString(encrypted), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt RC4解密
|
||||||
|
func (r *RC4Encrypt) Decrypt(ciphertext string) (string, error) {
|
||||||
|
if len(r.key) == 0 {
|
||||||
|
return "", fmt.Errorf("RC4密钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base64解码
|
||||||
|
data, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Base64解码失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := r.rc4KeyScheduling()
|
||||||
|
decrypted := r.rc4PseudoRandomGeneration(s, data)
|
||||||
|
|
||||||
|
return string(decrypted), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseRC4KeyFromString 从字符串解析RC4密钥
|
||||||
|
func ParseRC4KeyFromString(keyStr string) ([]byte, error) {
|
||||||
|
key, err := base64.StdEncoding.DecodeString(keyStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("解析RC4密钥失败: %v", err)
|
||||||
|
}
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
105
utils/encrypt/rsa.go
Normal file
105
utils/encrypt/rsa.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package encrypt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateRSAKeyPair 生成RSA密钥对(公共函数)
|
||||||
|
func GenerateRSAKeyPair(bits int) (*rsa.PublicKey, *rsa.PrivateKey, error) {
|
||||||
|
if bits < 1024 {
|
||||||
|
bits = 2048 // 默认2048位
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("生成RSA密钥对失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &privateKey.PublicKey, privateKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKeyToPEM 将RSA公钥转换为PEM格式字符串(公共函数)
|
||||||
|
func PublicKeyToPEM(publicKey *rsa.PublicKey) (string, error) {
|
||||||
|
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("序列化公钥失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "PUBLIC KEY",
|
||||||
|
Bytes: publicKeyBytes,
|
||||||
|
})
|
||||||
|
|
||||||
|
return string(publicKeyPEM), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrivateKeyToPEM 将RSA私钥转换为PEM格式字符串(公共函数)
|
||||||
|
func PrivateKeyToPEM(privateKey *rsa.PrivateKey) (string, error) {
|
||||||
|
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||||
|
|
||||||
|
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "RSA PRIVATE KEY",
|
||||||
|
Bytes: privateKeyBytes,
|
||||||
|
})
|
||||||
|
|
||||||
|
return string(privateKeyPEM), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKeyFromPEM 从PEM格式字符串解析RSA公钥(公共函数)
|
||||||
|
func PublicKeyFromPEM(publicKeyPEM string) (*rsa.PublicKey, error) {
|
||||||
|
block, _ := pem.Decode([]byte(publicKeyPEM))
|
||||||
|
if block == nil {
|
||||||
|
return nil, fmt.Errorf("无效的PEM格式公钥")
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("解析公钥失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rsaPublicKey, ok := publicKey.(*rsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("不是RSA公钥")
|
||||||
|
}
|
||||||
|
|
||||||
|
return rsaPublicKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrivateKeyFromPEM 从PEM格式字符串解析RSA私钥(公共函数)
|
||||||
|
func PrivateKeyFromPEM(privateKeyPEM string) (*rsa.PrivateKey, error) {
|
||||||
|
block, _ := pem.Decode([]byte(privateKeyPEM))
|
||||||
|
if block == nil {
|
||||||
|
return nil, fmt.Errorf("无效的PEM格式私钥")
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("解析私钥失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return privateKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRSAKeyPairPEM 生成RSA密钥对并返回PEM格式字符串(公共函数)
|
||||||
|
func GenerateRSAKeyPairPEM(bits int) (string, string, error) {
|
||||||
|
publicKey, privateKey, err := GenerateRSAKeyPair(bits)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKeyPEM, err := PublicKeyToPEM(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKeyPEM, err := PrivateKeyToPEM(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return publicKeyPEM, privateKeyPEM, nil
|
||||||
|
}
|
||||||
190
utils/encrypt/rsa_dynamic.go
Normal file
190
utils/encrypt/rsa_dynamic.go
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
package encrypt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RSADynamicEncrypt RAS动态加密算法结构体
|
||||||
|
type RSADynamicEncrypt struct {
|
||||||
|
publicKey *rsa.PublicKey
|
||||||
|
privateKey *rsa.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRSADynamicEncrypt 创建新的RAS动态加密实例
|
||||||
|
func NewRSADynamicEncrypt(publicKeyPEM, privateKeyPEM string) (*RSADynamicEncrypt, error) {
|
||||||
|
var pubKey *rsa.PublicKey
|
||||||
|
var privKey *rsa.PrivateKey
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// 解析公钥
|
||||||
|
if publicKeyPEM != "" {
|
||||||
|
pubKey, err = PublicKeyFromPEM(publicKeyPEM) // 使用公共函数
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse public key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析私钥
|
||||||
|
if privateKeyPEM != "" {
|
||||||
|
privKey, err = PrivateKeyFromPEM(privateKeyPEM) // 使用公共函数
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse private key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &RSADynamicEncrypt{
|
||||||
|
publicKey: pubKey,
|
||||||
|
privateKey: privKey,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRSADynamicKeyPair 生成RSA动态加密密钥对
|
||||||
|
func GenerateRSADynamicKeyPair(bits int) (string, string, error) {
|
||||||
|
return GenerateRSAKeyPairPEM(bits) // 使用公共函数
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateDynamicKeys 生成动态密钥
|
||||||
|
func generateDynamicKeys() ([]byte, error) {
|
||||||
|
// 生成3-6个随机密钥长度
|
||||||
|
var lengthByte [1]byte
|
||||||
|
if _, err := rand.Read(lengthByte[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
keyLen := 3 + int(lengthByte[0])%4 // 3-6个密钥
|
||||||
|
|
||||||
|
keys := make([]byte, keyLen)
|
||||||
|
for i := 0; i < keyLen; i++ {
|
||||||
|
var keyByte [1]byte
|
||||||
|
if _, err := rand.Read(keyByte[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 确保密钥在1-255范围内
|
||||||
|
keys[i] = keyByte[0]
|
||||||
|
if keys[i] == 0 {
|
||||||
|
keys[i] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// xorEncrypt 使用动态密钥进行XOR加密
|
||||||
|
func xorEncrypt(data []byte, keys []byte) []byte {
|
||||||
|
result := make([]byte, len(data))
|
||||||
|
copy(result, data)
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
for i := range result {
|
||||||
|
result[i] ^= key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// xorDecrypt 使用动态密钥进行XOR解密(与加密相同)
|
||||||
|
func xorDecrypt(data []byte, keys []byte) []byte {
|
||||||
|
return xorEncrypt(data, keys) // XOR解密与加密相同
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt RAS动态加密
|
||||||
|
func (r *RSADynamicEncrypt) Encrypt(plaintext string) (string, error) {
|
||||||
|
if r.publicKey == nil {
|
||||||
|
return "", errors.New("public key not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 生成动态密钥
|
||||||
|
dynamicKeys, err := generateDynamicKeys()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to generate dynamic keys: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 使用动态密钥对明文进行XOR加密
|
||||||
|
plaintextBytes := []byte(plaintext)
|
||||||
|
xorEncrypted := xorEncrypt(plaintextBytes, dynamicKeys)
|
||||||
|
|
||||||
|
// 3. 构造最终数据:密钥长度 + 密钥 + 加密数据
|
||||||
|
finalData := make([]byte, 0, 1+len(dynamicKeys)+len(xorEncrypted))
|
||||||
|
finalData = append(finalData, byte(len(dynamicKeys))) // 密钥长度
|
||||||
|
|
||||||
|
// 按逆序插入密钥(与C++代码保持一致)
|
||||||
|
for i := len(dynamicKeys) - 1; i >= 0; i-- {
|
||||||
|
finalData = append(finalData, dynamicKeys[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
finalData = append(finalData, xorEncrypted...) // 加密数据
|
||||||
|
|
||||||
|
// 4. 使用RSA公钥加密
|
||||||
|
rsaEncrypted, err := rsa.EncryptPKCS1v15(rand.Reader, r.publicKey, finalData)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("RSA encryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Base64编码
|
||||||
|
return base64.StdEncoding.EncodeToString(rsaEncrypted), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt RAS动态解密
|
||||||
|
func (r *RSADynamicEncrypt) Decrypt(ciphertext string) (string, error) {
|
||||||
|
if r.privateKey == nil {
|
||||||
|
return "", errors.New("private key not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Base64解码
|
||||||
|
rsaEncrypted, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("base64 decode failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 使用RSA私钥解密
|
||||||
|
decryptedData, err := rsa.DecryptPKCS1v15(rand.Reader, r.privateKey, rsaEncrypted)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("RSA decryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(decryptedData) < 1 {
|
||||||
|
return "", errors.New("decrypted data too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 提取密钥长度
|
||||||
|
keyLen := int(decryptedData[0])
|
||||||
|
if len(decryptedData) < 1+keyLen {
|
||||||
|
return "", errors.New("invalid decrypted data format")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 提取动态密钥(按逆序存储的)
|
||||||
|
dynamicKeys := make([]byte, keyLen)
|
||||||
|
for i := 0; i < keyLen; i++ {
|
||||||
|
dynamicKeys[keyLen-1-i] = decryptedData[1+i] // 恢复原始顺序
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 提取XOR加密的数据
|
||||||
|
xorEncryptedData := decryptedData[1+keyLen:]
|
||||||
|
|
||||||
|
// 6. 使用动态密钥进行XOR解密
|
||||||
|
plaintext := xorDecrypt(xorEncryptedData, dynamicKeys)
|
||||||
|
|
||||||
|
return string(plaintext), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptWithKeys 使用指定的公钥进行RAS动态加密
|
||||||
|
func EncryptWithKeys(plaintext, publicKeyPEM string) (string, error) {
|
||||||
|
rsaEncrypt, err := NewRSADynamicEncrypt(publicKeyPEM, "")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return rsaEncrypt.Encrypt(plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptWithKeys 使用指定的私钥进行RAS动态解密
|
||||||
|
func DecryptWithKeys(ciphertext, privateKeyPEM string) (string, error) {
|
||||||
|
rsaEncrypt, err := NewRSADynamicEncrypt("", privateKeyPEM)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return rsaEncrypt.Decrypt(ciphertext)
|
||||||
|
}
|
||||||
124
utils/encrypt/rsa_standard.go
Normal file
124
utils/encrypt/rsa_standard.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package encrypt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RSAEncrypt 普通RSA加密算法结构体
|
||||||
|
type RSAEncrypt struct {
|
||||||
|
publicKey *rsa.PublicKey
|
||||||
|
privateKey *rsa.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRSAEncrypt 创建新的RSA加密实例
|
||||||
|
func NewRSAEncrypt(publicKey *rsa.PublicKey, privateKey *rsa.PrivateKey) *RSAEncrypt {
|
||||||
|
return &RSAEncrypt{
|
||||||
|
publicKey: publicKey,
|
||||||
|
privateKey: privateKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt RSA公钥加密
|
||||||
|
func (r *RSAEncrypt) Encrypt(plaintext string) (string, error) {
|
||||||
|
if r.publicKey == nil {
|
||||||
|
return "", fmt.Errorf("RSA公钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
data := []byte(plaintext)
|
||||||
|
|
||||||
|
// 使用OAEP填充进行加密
|
||||||
|
encrypted, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, r.publicKey, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("RSA加密失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base64编码
|
||||||
|
return base64.StdEncoding.EncodeToString(encrypted), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt RSA私钥解密
|
||||||
|
func (r *RSAEncrypt) Decrypt(ciphertext string) (string, error) {
|
||||||
|
if r.privateKey == nil {
|
||||||
|
return "", fmt.Errorf("RSA私钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base64解码
|
||||||
|
data, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Base64解码失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用OAEP填充进行解密
|
||||||
|
decrypted, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, r.privateKey, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("RSA解密失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(decrypted), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptLargeData RSA分块加密大数据
|
||||||
|
func (r *RSAEncrypt) EncryptLargeData(plaintext string) (string, error) {
|
||||||
|
if r.publicKey == nil {
|
||||||
|
return "", fmt.Errorf("RSA公钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
data := []byte(plaintext)
|
||||||
|
keySize := r.publicKey.Size()
|
||||||
|
blockSize := keySize - 2*sha256.Size - 2 // OAEP填充的最大明文长度
|
||||||
|
|
||||||
|
var encrypted []byte
|
||||||
|
|
||||||
|
for i := 0; i < len(data); i += blockSize {
|
||||||
|
end := i + blockSize
|
||||||
|
if end > len(data) {
|
||||||
|
end = len(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
block := data[i:end]
|
||||||
|
encryptedBlock, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, r.publicKey, block, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("RSA分块加密失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted = append(encrypted, encryptedBlock...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(encrypted), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptLargeData RSA分块解密大数据
|
||||||
|
func (r *RSAEncrypt) DecryptLargeData(ciphertext string) (string, error) {
|
||||||
|
if r.privateKey == nil {
|
||||||
|
return "", fmt.Errorf("RSA私钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Base64解码失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keySize := r.privateKey.Size()
|
||||||
|
var decrypted []byte
|
||||||
|
|
||||||
|
for i := 0; i < len(data); i += keySize {
|
||||||
|
end := i + keySize
|
||||||
|
if end > len(data) {
|
||||||
|
end = len(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
block := data[i:end]
|
||||||
|
decryptedBlock, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, r.privateKey, block, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("RSA分块解密失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted = append(decrypted, decryptedBlock...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(decrypted), nil
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
<label class="layui-form-label">搜索</label>
|
<label class="layui-form-label">搜索</label>
|
||||||
<div class="layui-input-inline">
|
<div class="layui-input-inline">
|
||||||
<input type="text" name="search" placeholder="API密钥/应用UUID" autocomplete="off" class="layui-input" />
|
<input type="text" name="search" placeholder="API接口/应用UUID" autocomplete="off" class="layui-input" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<script type="text/html" id="tpl-apis-ops">
|
<script type="text/html" id="tpl-apis-ops">
|
||||||
<div style="white-space: nowrap;">
|
<div style="white-space: nowrap;">
|
||||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="reset">重置密钥</a>
|
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="reset">重置接口</a>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
<script type="text/html" id="tpl-apis-status">
|
<script type="text/html" id="tpl-apis-status">
|
||||||
@@ -149,6 +149,46 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
// 当前选中的应用UUID
|
// 当前选中的应用UUID
|
||||||
var currentAppUUID = '';
|
var currentAppUUID = '';
|
||||||
|
|
||||||
|
// 复制到剪贴板函数
|
||||||
|
window.copyToClipboard = function(text) {
|
||||||
|
if (navigator.clipboard && window.isSecureContext) {
|
||||||
|
// 使用现代 Clipboard API
|
||||||
|
navigator.clipboard.writeText(text).then(function() {
|
||||||
|
layer.msg('接口地址已复制到剪贴板', {icon: 1, time: 2000});
|
||||||
|
}).catch(function(err) {
|
||||||
|
console.error('复制失败:', err);
|
||||||
|
fallbackCopyTextToClipboard(text);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 降级方案
|
||||||
|
fallbackCopyTextToClipboard(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 降级复制方案
|
||||||
|
function fallbackCopyTextToClipboard(text) {
|
||||||
|
var textArea = document.createElement("textarea");
|
||||||
|
textArea.value = text;
|
||||||
|
textArea.style.top = "0";
|
||||||
|
textArea.style.left = "0";
|
||||||
|
textArea.style.position = "fixed";
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
try {
|
||||||
|
var successful = document.execCommand('copy');
|
||||||
|
if (successful) {
|
||||||
|
layer.msg('接口地址已复制到剪贴板', {icon: 1, time: 2000});
|
||||||
|
} else {
|
||||||
|
layer.msg('复制失败,请手动复制', {icon: 2, time: 3000});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('复制失败:', err);
|
||||||
|
layer.msg('复制失败,请手动复制', {icon: 2, time: 3000});
|
||||||
|
}
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化接口表格
|
// 初始化接口表格
|
||||||
var apisTable = table.render({
|
var apisTable = table.render({
|
||||||
elem: '#apisTable',
|
elem: '#apisTable',
|
||||||
@@ -171,15 +211,21 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
limits: [10, 20, 50, 100],
|
limits: [10, 20, 50, 100],
|
||||||
loading: true,
|
loading: true,
|
||||||
cols: [[
|
cols: [[
|
||||||
{ type: 'checkbox', width: 50 },
|
|
||||||
{ field: 'id', title: 'ID', width: 80, sort: true },
|
{ field: 'id', title: 'ID', width: 80, sort: true },
|
||||||
{ field: 'app_name', title: '应用名称', minWidth: 150 },
|
{ field: 'app_name', title: '应用名称', width: 180 },
|
||||||
{ field: 'api_type_name', title: '接口类型', minWidth: 120 },
|
{ field: 'api_type_name', title: '接口类型', width: 120 },
|
||||||
{
|
{
|
||||||
field: 'api_key',
|
field: 'api_key',
|
||||||
title: 'API密钥',
|
title: 'API接口',
|
||||||
minWidth: 280,
|
minWidth: 350,
|
||||||
templet: (d) => '<span style="font-family: monospace; font-size: 12px;">' + d.api_key + '</span>'
|
templet: (d) => {
|
||||||
|
const baseUrl = window.location.protocol + '//' + window.location.host;
|
||||||
|
const fullUrl = baseUrl + '/api/v1/' + d.api_key;
|
||||||
|
return '<span style="font-family: monospace; font-size: 12px; word-break: break-all; cursor: pointer; color: #1E9FFF; text-decoration: underline;" ' +
|
||||||
|
'onclick="copyToClipboard(\'' + fullUrl + '\')" title="点击复制接口地址">' +
|
||||||
|
fullUrl +
|
||||||
|
'</span>';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'status_name',
|
field: 'status_name',
|
||||||
@@ -487,7 +533,7 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
shadeClose: false
|
shadeClose: false
|
||||||
});
|
});
|
||||||
} else if (obj.event === 'reset') {
|
} else if (obj.event === 'reset') {
|
||||||
layer.confirm('确定重置该接口密钥吗?', {icon: 3, title: '提示'}, function(index) {
|
layer.confirm('确定重置该接口吗?', {icon: 3, title: '提示'}, function(index) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/admin/api/apis/reset_key',
|
url: '/admin/api/apis/reset_key',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
@@ -495,7 +541,7 @@ layui.use(['table', 'form', 'layer', 'dropdown'], function() {
|
|||||||
data: JSON.stringify({ id: data.id }),
|
data: JSON.stringify({ id: data.id }),
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
layer.msg('密钥重置成功', {icon: 1});
|
layer.msg('接口重置成功', {icon: 1});
|
||||||
// 更新当前行的密钥显示
|
// 更新当前行的密钥显示
|
||||||
if (res.data && res.data.api_key) {
|
if (res.data && res.data.api_key) {
|
||||||
obj.update({ api_key: res.data.api_key });
|
obj.update({ api_key: res.data.api_key });
|
||||||
|
|||||||
Reference in New Issue
Block a user