mirror of https://gitee.com/godoos/godoos.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
420 lines
11 KiB
420 lines
11 KiB
package libs
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/md5"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
func IsEncryptedFile(data string) bool {
|
|
if len(data) < 2 {
|
|
return false
|
|
}
|
|
// 检查是否以 @ 开头
|
|
if !strings.HasPrefix(data, "@") {
|
|
return false
|
|
}
|
|
// 去掉开头的 @
|
|
data = data[1:]
|
|
// 分割加密的私钥、二级密码和加密的文本
|
|
parts := strings.SplitN(data, "@", 3)
|
|
if len(parts) != 3 {
|
|
return false
|
|
}
|
|
|
|
hexEncodedPrivateKey := parts[0]
|
|
encryptedSecondaryPassword := parts[1]
|
|
encryptedText := parts[2]
|
|
|
|
// 检查各个部分是否都不为空
|
|
if hexEncodedPrivateKey == "" || encryptedSecondaryPassword == "" || encryptedText == "" {
|
|
return false
|
|
}
|
|
|
|
// 检查十六进制字符串是否有效
|
|
base64Str, err := hex.DecodeString(hexEncodedPrivateKey)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
// 尝试将 Base64 字符串解码为字节切片
|
|
_, err = base64.URLEncoding.DecodeString(string(base64Str))
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
// 检查二级密码和加密文本是否能被正确解码
|
|
_, err = base64.URLEncoding.DecodeString(encryptedSecondaryPassword)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
_, err = base64.URLEncoding.DecodeString(encryptedText)
|
|
return err == nil
|
|
}
|
|
|
|
// EncodeFile 加密文件
|
|
func EncodeFile(password string, longText string) (string, error) {
|
|
privateKey, publicKey, err := GenerateRSAKeyPair(2048) // 使用2048位密钥更安全
|
|
if err != nil {
|
|
fmt.Println("生成RSA密钥对失败:", err)
|
|
return "", err
|
|
}
|
|
|
|
// 使用密码加密私钥
|
|
pwd, err := hashAndMD5(password)
|
|
if err != nil {
|
|
return "", fmt.Errorf("加密密码失败:%v", err)
|
|
}
|
|
encryptedPrivateKey, err := EncryptPrivateKey(privateKey, pwd)
|
|
if err != nil {
|
|
fmt.Println("加密私钥失败:", err)
|
|
return "", fmt.Errorf("加密私钥失败")
|
|
}
|
|
|
|
// 对 encryptedPrivateKey 进行 Base64 编码
|
|
base64EncryptedPrivateKey := base64.URLEncoding.EncodeToString([]byte(encryptedPrivateKey))
|
|
|
|
// 将 Base64 编码后的字符串转换为十六进制字符串
|
|
hexEncodedPrivateKey := hex.EncodeToString([]byte(base64EncryptedPrivateKey))
|
|
|
|
// 生成二级密码
|
|
secondaryPassword, err := GenerateSecondaryPassword(32) // 32字节的二级密码
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// 使用公钥加密二级密码
|
|
encryptedSecondaryPassword, err := EncryptSecondaryPassword(secondaryPassword, publicKey)
|
|
if err != nil {
|
|
return "", fmt.Errorf("加密二级密码失败:%v", err)
|
|
}
|
|
|
|
// 使用二级密码加密数据
|
|
encryptedText, err := EncryptDataWithGCM(longText, secondaryPassword)
|
|
if err != nil {
|
|
return "", fmt.Errorf("加密数据失败:%v", err)
|
|
}
|
|
|
|
return "@" + hexEncodedPrivateKey + "@" + encryptedSecondaryPassword + "@" + encryptedText, nil
|
|
}
|
|
|
|
// DecodeFile 解密文件
|
|
func DecodeFile(password string, encryptedData string) (string, error) {
|
|
// 去掉开头的@
|
|
if !strings.HasPrefix(encryptedData, "@") {
|
|
return "", fmt.Errorf("无效的加密数据格式")
|
|
}
|
|
encryptedData = encryptedData[1:]
|
|
|
|
// 分割加密的私钥、加密的二级密码和加密的文本
|
|
parts := strings.SplitN(encryptedData, "@", 3)
|
|
if len(parts) != 3 {
|
|
return "", fmt.Errorf("无效的加密数据格式")
|
|
}
|
|
|
|
hexEncodedPrivateKey := parts[0]
|
|
encryptedSecondaryPassword := parts[1]
|
|
encryptedText := parts[2]
|
|
|
|
// 将十六进制字符串转换回 Base64 编码字符串
|
|
base64DecodedPrivateKey, err := hex.DecodeString(hexEncodedPrivateKey)
|
|
if err != nil {
|
|
return "", fmt.Errorf("十六进制字符串解码失败:%v", err)
|
|
}
|
|
|
|
// 将 Base64 编码字符串解码回原始的 encryptedPrivateKey
|
|
encryptedPrivateKey, err := base64.URLEncoding.DecodeString(string(base64DecodedPrivateKey))
|
|
if err != nil {
|
|
return "", fmt.Errorf("Base64字符串解码失败:%v", err)
|
|
}
|
|
|
|
pwd, err := hashAndMD5(password)
|
|
if err != nil {
|
|
return "", fmt.Errorf("加密密码失败:%v", err)
|
|
}
|
|
|
|
// 解密私钥
|
|
privateKey, err := DecryptPrivateKey(string(encryptedPrivateKey), pwd)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解密私钥失败:%v", err)
|
|
}
|
|
|
|
// 解密二级密码
|
|
secondaryPassword, err := DecryptSecondaryPassword(encryptedSecondaryPassword, privateKey)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解密二级密码失败:%v", err)
|
|
}
|
|
|
|
// 使用二级密码解密数据
|
|
decryptedText, err := DecryptDataWithGCM(encryptedText, secondaryPassword)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解密文本失败:%v", err)
|
|
}
|
|
|
|
return decryptedText, nil
|
|
}
|
|
|
|
// GenerateRSAKeyPair 生成RSA密钥对
|
|
func GenerateRSAKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
publicKey := &privateKey.PublicKey
|
|
|
|
return privateKey, publicKey, nil
|
|
}
|
|
func GenertePrivateKey(password string, privateKey *rsa.PrivateKey) (*rsa.PrivateKey, error) {
|
|
encryptedPrivateKey, err := EncryptPrivateKey(privateKey, password)
|
|
if err != nil {
|
|
fmt.Println("加密私钥失败:", err)
|
|
return nil, fmt.Errorf("加密私钥失败")
|
|
}
|
|
decryptedPrivateKey, err := DecryptPrivateKey(encryptedPrivateKey, password)
|
|
if err != nil {
|
|
fmt.Println("解密私钥失败:", err)
|
|
return nil, fmt.Errorf("加密私钥失败")
|
|
}
|
|
return decryptedPrivateKey, nil
|
|
}
|
|
|
|
// EncryptWithPublicKey 使用公钥加密数据
|
|
func EncryptWithPublicKey(data []byte, publicKey *rsa.PublicKey) (string, error) {
|
|
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, data, nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return base64.URLEncoding.EncodeToString(ciphertext), nil
|
|
}
|
|
|
|
// DecryptWithPrivateKey 使用私钥解密数据
|
|
func DecryptWithPrivateKey(encryptedData string, privateKey *rsa.PrivateKey) ([]byte, error) {
|
|
ciphertext, err := base64.URLEncoding.DecodeString(encryptedData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return plaintext, nil
|
|
}
|
|
|
|
// hashAndMD5 使用 MD5 哈希密码
|
|
func hashAndMD5(password string) (string, error) {
|
|
hasher := md5.New()
|
|
_, err := hasher.Write([]byte(password))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(hasher.Sum(nil)), nil
|
|
}
|
|
|
|
// EncryptPrivateKey 使用AES加密RSA私钥
|
|
func EncryptPrivateKey(privateKey *rsa.PrivateKey, password string) (string, error) {
|
|
privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
|
|
key := []byte(password)
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
nonce := make([]byte, gcm.NonceSize())
|
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ciphertext := gcm.Seal(nonce, nonce, privateKeyBytes, nil)
|
|
return base64.URLEncoding.EncodeToString(ciphertext), nil
|
|
}
|
|
|
|
// DecryptPrivateKey 使用AES解密RSA私钥
|
|
func DecryptPrivateKey(encryptedPrivateKey string, password string) (*rsa.PrivateKey, error) {
|
|
ciphertext, err := base64.URLEncoding.DecodeString(encryptedPrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key := []byte(password)
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nonceSize := gcm.NonceSize()
|
|
if len(ciphertext) < nonceSize {
|
|
return nil, fmt.Errorf("ciphertext too short")
|
|
}
|
|
|
|
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
|
privateKeyBytes, err := gcm.Open(nil, nonce, ciphertext, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return privateKey, nil
|
|
}
|
|
|
|
// DecryptSecondaryPassword 使用私钥解密二级密码
|
|
func DecryptSecondaryPassword(encryptedSecondaryPassword string, privateKey *rsa.PrivateKey) (string, error) {
|
|
ciphertext, err := base64.URLEncoding.DecodeString(encryptedSecondaryPassword)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(plaintext), nil
|
|
}
|
|
|
|
// DecodeFileWithSecondaryPassword 解密文件
|
|
func DecodeFileWithSecondaryPassword(password string, encryptedData string) (string, error) {
|
|
// 去掉开头的@
|
|
if !strings.HasPrefix(encryptedData, "@") {
|
|
return "", fmt.Errorf("无效的加密数据格式")
|
|
}
|
|
encryptedData = encryptedData[1:]
|
|
|
|
// 分割加密的二级密码和加密的文本
|
|
parts := strings.SplitN(encryptedData, "@", 2)
|
|
if len(parts) != 2 {
|
|
return "", fmt.Errorf("无效的加密数据格式")
|
|
}
|
|
|
|
encryptedSecondaryPassword := parts[0]
|
|
encryptedText := parts[1]
|
|
|
|
// 使用私钥解密二级密码
|
|
privateKey, err := DecryptPrivateKey(password, password)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解密私钥失败:%v", err)
|
|
}
|
|
|
|
// 使用私钥解密二级密码
|
|
secondaryPassword, err := DecryptSecondaryPassword(encryptedSecondaryPassword, privateKey)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解密二级密码失败:%v", err)
|
|
}
|
|
|
|
// 使用二级密码解密文本
|
|
decryptedText, err := DecryptDataWithGCM(encryptedText, secondaryPassword)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解密文本失败:%v", err)
|
|
}
|
|
|
|
return decryptedText, nil
|
|
}
|
|
|
|
// GenerateSecondaryPassword 生成一个随机的二级密码
|
|
func GenerateSecondaryPassword(length int) (string, error) {
|
|
b := make([]byte, length)
|
|
_, err := rand.Read(b)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return base64.URLEncoding.EncodeToString(b), nil
|
|
}
|
|
|
|
// EncryptWithPublicKey 使用公钥加密二级密码
|
|
func EncryptSecondaryPassword(secondaryPassword string, publicKey *rsa.PublicKey) (string, error) {
|
|
data := []byte(secondaryPassword)
|
|
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, data, nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return base64.URLEncoding.EncodeToString(ciphertext), nil
|
|
}
|
|
|
|
// EncryptDataWithGCM 使用二级密码和GCM模式加密数据
|
|
func EncryptDataWithGCM(data, secondaryPassword string) (string, error) {
|
|
// 确保 secondaryPassword 长度为 32 字节
|
|
if len(secondaryPassword) < 32 {
|
|
return "", fmt.Errorf("secondary password too short")
|
|
}
|
|
key := []byte(secondaryPassword[:32])
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
nonce := make([]byte, gcm.NonceSize())
|
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ciphertext := gcm.Seal(nonce, nonce, []byte(data), nil)
|
|
return base64.URLEncoding.EncodeToString(ciphertext), nil
|
|
}
|
|
|
|
// DecryptDataWithGCM 使用二级密码和GCM模式解密数据
|
|
func DecryptDataWithGCM(encryptedData, secondaryPassword string) (string, error) {
|
|
// 确保 secondaryPassword 长度为 32 字节
|
|
if len(secondaryPassword) < 32 {
|
|
return "", fmt.Errorf("secondary password too short")
|
|
}
|
|
key := []byte(secondaryPassword[:32])
|
|
|
|
ciphertext, err := base64.URLEncoding.DecodeString(encryptedData)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
nonceSize := gcm.NonceSize()
|
|
if len(ciphertext) < nonceSize {
|
|
return "", fmt.Errorf("ciphertext too short")
|
|
}
|
|
|
|
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
|
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(plaintext), nil
|
|
}
|
|
|