golang实现的Rsa加密解密算法(go和java交互时双向加解密方案)

加粗样式golang实现的Rsa加密解密算法(go和java交互时双向加解密方案)

使用说明:

  1. public_java.key 是java生成的公钥,需要java方生成并发给go方保存。
  2. go_private.key和go_public.key 是go生成的公私钥。其中go_public.key文件需发给java方保存,java方用来验证go给的签名,同时java方加密内容时也会用到go_public.key。反之java方也是同样的道理
  3. 支持分段加密, 可以 解决消息过长问题
go 复制代码
package utils

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"go-admin/common/client"
	"go-admin/common/file_store"
	"io"
	"math"
	mrand "math/rand"
	"os"
	"strconv"
	"strings"
	"time"
)

// 包级别初始化随机数生成器

func readKeyFromFile(filename string) (string, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return "", fmt.Errorf("读取文件失败: %v", err)
	}
	return string(data), nil
}

// 修复:增强私钥加载函数,自动补全PEM标签并清理格式
func loadPrivateKey(privKeyStr string) (*rsa.PrivateKey, error) {
	// 1. 清理空格和换行
	privKeyStr = strings.TrimSpace(privKeyStr)

	// 2. 自动补全PEM标签(处理Java可能缺失标签的情况)
	if !strings.HasPrefix(privKeyStr, "-----BEGIN PRIVATE KEY-----") {
		privKeyStr = "-----BEGIN PRIVATE KEY-----\n" + privKeyStr
	}
	if !strings.HasSuffix(privKeyStr, "-----END PRIVATE KEY-----") {
		privKeyStr = privKeyStr + "\n-----END PRIVATE KEY-----"
	}

	// 3. 解码PEM
	block, rest := pem.Decode([]byte(privKeyStr))
	if block == nil {
		// 调试信息:输出无法解码的内容(生产环境可删除)
		fmt.Printf("PEM解码失败,原始内容: %s\n", privKeyStr)
		fmt.Printf("剩余未解码内容: %s\n", string(rest))
		return nil, fmt.Errorf("failed to decode PEM block containing private key")
	}

	// 4. 解析PKCS#8格式私钥(兼容Java默认格式)
	priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		// 尝试兼容PKCS#1格式(Java有时也会生成)
		priv, err = x509.ParsePKCS1PrivateKey(block.Bytes)
		if err != nil {
			return nil, fmt.Errorf("解析私钥失败: %v", err)
		}
	}

	// 5. 确认是RSA私钥
	switch priv := priv.(type) {
	case *rsa.PrivateKey:
		return priv, nil
	default:
		return nil, fmt.Errorf("不是RSA私钥")
	}
}

// 以下为其他辅助函数(与之前相同,保持兼容)
func generateKeyPair() (publicKey, privateKey string, err error) {
	privateKeyObj, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return "", "", err
	}

	privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(privateKeyObj)
	if err != nil {
		return "", "", err
	}

	privateKeyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "PRIVATE KEY",
		Bytes: privateKeyBytes,
	})

	publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKeyObj.PublicKey)
	if err != nil {
		return "", "", err
	}

	publicKeyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: publicKeyBytes,
	})

	return string(publicKeyPEM), string(privateKeyPEM), nil
}

func loadPublicKey(pubKeyStr string) (*rsa.PublicKey, error) {
	pubKeyStr = strings.TrimSpace(pubKeyStr)

	// 自动补全公钥PEM标签
	if !strings.HasPrefix(pubKeyStr, "-----BEGIN PUBLIC KEY-----") {
		pubKeyStr = "-----BEGIN PUBLIC KEY-----\n" + pubKeyStr
	}
	if !strings.HasSuffix(pubKeyStr, "-----END PUBLIC KEY-----") {
		pubKeyStr = pubKeyStr + "\n-----END PUBLIC KEY-----"
	}

	block, _ := pem.Decode([]byte(pubKeyStr))
	if block == nil {
		return nil, fmt.Errorf("failed to decode PEM block containing public key")
	}

	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	switch pub := pub.(type) {
	case *rsa.PublicKey:
		return pub, nil
	default:
		return nil, fmt.Errorf("not an RSA public key")
	}
}

// 分段加密函数 - 解决消息过长问题
func encrypt(data string, pubKey *rsa.PublicKey) (string, error) {
	// RSA加密最大长度计算 (密钥长度/8 - 11填充字节)
	maxLen := pubKey.Size() - 11
	srcData := []byte(data)

	// 如果数据长度小于等于最大长度,直接加密
	if len(srcData) <= maxLen {
		ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, srcData)
		if err != nil {
			return "", err
		}
		return base64.StdEncoding.EncodeToString(ciphertext), nil
	}

	// 否则进行分段加密
	var encryptedData []string
	for i := 0; i < len(srcData); i += maxLen {
		end := i + maxLen
		if end > len(srcData) {
			end = len(srcData)
		}

		chunk := srcData[i:end]
		ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, chunk)
		if err != nil {
			return "", err
		}
		encryptedData = append(encryptedData, base64.StdEncoding.EncodeToString(ciphertext))
	}

	// 用"|"连接各段加密数据
	return strings.Join(encryptedData, "|"), nil
}

func decrypt(ciphertext string, privKey *rsa.PrivateKey) (string, error) {
	// 检查是否为分段加密数据
	if strings.Contains(ciphertext, "|") {
		// 分段解密
		chunks := strings.Split(ciphertext, "|")
		var decryptedData []byte

		for _, chunk := range chunks {
			data, err := base64.StdEncoding.DecodeString(chunk)
			if err != nil {
				return "", err
			}

			plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, privKey, data)
			if err != nil {
				return "", err
			}

			decryptedData = append(decryptedData, plaintext...)
		}

		return string(decryptedData), nil
	}

	// 单段解密
	data, err := base64.StdEncoding.DecodeString(ciphertext)
	if err != nil {
		return "", err
	}

	plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, privKey, data)
	if err != nil {
		return "", err
	}

	return string(plaintext), nil
}

// 生成签名
// 签名内容:encryptedData + randomNum + timestamp
func sign(encryptedText string, randomNum string, timestamp int64, privateKey *rsa.PrivateKey) (string, error) {
	if privateKey == nil {
		return "", errors.New("私钥未初始化")
	}

	// 拼接数据
	dataToSign := encryptedText + randomNum + strconv.FormatInt(timestamp, 10)

	hashed := sha256.Sum256([]byte(dataToSign))

	signature, err := rsa.SignPKCS1v15(nil, privateKey, crypto.SHA256, hashed[:])
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(signature), nil
}

const (
	TIMESTAMP_MAX_OFFSET = 300000 // 假设与Java版本相同的5分钟偏移量(单位毫秒)
)

func verify(encryptedText string, randomNum string, timestamp int64, signatureStr string, publicKey *rsa.PublicKey) (bool, error) {
	// 1. 验证时间戳是否在允许的偏移范围内
	currentTime := time.Now().UnixNano() / int64(time.Millisecond)
	if math.Abs(float64(timestamp-currentTime)) > TIMESTAMP_MAX_OFFSET {
		return false, nil
	}

	// 2. 验证签名
	dataToVerify := encryptedText + randomNum + strconv.FormatInt(timestamp, 10)
	hashed := sha256.Sum256([]byte(dataToVerify))

	signature, err := base64.StdEncoding.DecodeString(signatureStr)
	if err != nil {
		return false, err
	}

	err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], signature)
	if err != nil {
		if err == rsa.ErrVerification {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

// 生成指定长度的随机数字字符串

func generateRandomNumbers() (string, int64) {
	// 1. 生成10位随机数字字符串
	const digits = "0123456789"
	//把digits 做成随机生成的
	randomNum := make([]byte, 10)
	for i := range randomNum {
		randomNum[i] = digits[mrand.Intn(len(digits))]
	}

	// 2. 获取当前时间戳(毫秒)
	timestamp := time.Now().UnixNano() / int64(time.Millisecond)

	return string(randomNum), timestamp
}

func main() {
	//makeKeyPair()
	//EncryptData()
	//DecryptData()
}

func makeKeyPair() {
	// 生成密钥对
	publicKey, privateKey, err := generateKeyPair()
	if err != nil {
		fmt.Printf("生成密钥对失败: %v\n", err)
		return
	}
	fmt.Println("公钥:")
	fmt.Println(publicKey)
	fmt.Println("私钥:")
	fmt.Println(privateKey)
}
func EncryptData(originalData string) (signature, encryptedText, randomNum string, timestamp int64, err error) {

	/*rsaPath, err := static.RsakeyPath("go_private.key")
	if err != nil {
		fmt.Printf("读取私钥文件失败: %v\n", err)
		return
	}
	// 从.key文件读取go私钥
	keyContent, err := readKeyFromFile(rsaPath)
	if err != nil {
		fmt.Printf("读取私钥文件失败: %v\n", err)
		return
	}

	privKey, err := loadPrivateKey(keyContent)
	if err != nil {
		fmt.Printf("加载私钥失败: %v\n", err)
		return
	}
	fmt.Println("====================私钥加载成功========================")

	rsaPath, err = static.RsakeyPath("public_java.key")
	if err != nil {
		fmt.Printf("读取公钥文件失败: %v\n", err)
		return "", "", "", 0, nil
	}
	// public.key文件读取java公钥
	keyContent1, err := readKeyFromFile(rsaPath)
	if err != nil {
		fmt.Printf("读取公钥文件失败: %v\n", err)
		return
	}

	pubKey, err := loadPublicKey(keyContent1)
	if err != nil {
		fmt.Printf("加载公钥失败: %v\n", err)
		return
	}
	fmt.Println("====================公钥加载成功========================")*/
	// 从FTP读取私钥
	privateKeyContent, err := readRSAKeyFromFTP("go_private.key")
	if err != nil {
		return
	}

	privKey, err := loadPrivateKey(privateKeyContent)
	if err != nil {
		return
	}

	// 从FTP读取公钥
	publicKeyContent, err := readRSAKeyFromFTP("public_java.key")
	if err != nil {
		return
	}

	pubKey, err := loadPublicKey(publicKeyContent)
	if err != nil {
		return
	}
	// 生成10位随机数
	randomNum, timestamp = generateRandomNumbers()
	fmt.Println("随机数: " + randomNum)

	// 生成时间戳
	timestamp = time.Now().UnixMilli()
	fmt.Println("时间戳: ", timestamp)

	encryptedText, err = encrypt(originalData, pubKey)
	if err != nil {
		fmt.Printf("加密失败: %v\n", err)
		return
	}
	fmt.Println("加密后:", encryptedText)
	// 生成签名(实际使用时需要传入正确加载的privateKey)
	if privKey != nil {
		signature, err = sign(encryptedText, randomNum, timestamp, privKey)
		if err != nil {
			fmt.Println("签名错误:", err)
			return
		}
		fmt.Println("签名: " + signature)
	}
	return signature, encryptedText, randomNum, timestamp, nil

}
func DecryptData(signature, encryptedText, randomNum string, timestamp int64) (decryptData string, err error) {
	// 从key文件读取私钥
	/*rsaPath, err := static.RsakeyPath("go_private.key")
	if err != nil {
		fmt.Printf("读取私钥文件失败: %v\n", err)
		return "", err
	}
	keyContent, err := readKeyFromFile(rsaPath)
	if err != nil {
		fmt.Printf("读取私钥文件失败: %v\n", err)
		return decryptData, err
	}

	privKey, err := loadPrivateKey(keyContent)
	if err != nil {
		fmt.Printf("加载私钥失败: %v\n", err)
		return "", err
	}
	fmt.Println("私钥加载成功")

	// public.key文件读取公钥
	rsaPath, err = static.RsakeyPath("public_java.key")
	keyContent1, err := readKeyFromFile(rsaPath)
	if err != nil {
		fmt.Printf("读取公钥文件失败: %v\n", err)
		return "", err
	}

	pubKey, err := loadPublicKey(keyContent1)
	if err != nil {
		fmt.Printf("加载公钥失败: %v\n", err)
		return "", err
	}
	fmt.Println("公钥加载成功")*/

	// 从FTP读取私钥
	privateKeyContent, err := readRSAKeyFromFTP("go_private.key")
	if err != nil {
		return
	}

	privKey, err := loadPrivateKey(privateKeyContent)
	if err != nil {
		return
	}

	// 从FTP读取公钥
	publicKeyContent, err := readRSAKeyFromFTP("public_java.key")
	if err != nil {
		return
	}

	pubKey, err := loadPublicKey(publicKeyContent)
	if err != nil {
		return
	}

	// 验证签名(实际使用时需要传入正确加载的publicKey)
	if pubKey != nil {
		valid, err := verify(encryptedText, randomNum, int64(timestamp), signature, pubKey)
		if err != nil {
			fmt.Println("验证错误:", err)
		} else {
			fmt.Println("签名验证结果: ", valid)
		}
	} else {
		fmt.Println("请先加载公钥")
	}
	decryptData, err = decrypt(encryptedText, privKey)
	if err != nil {
		fmt.Printf("解密失败: %v\n", err)
		return decryptData, nil
	}

	fmt.Println("解密后:", decryptData)
	return decryptData, nil
}
func readRSAKeyFromFTP(filename string) (string, error) {
	// 获取FTP配置
	ftpConn, err := file_store.Ftp()
	if err != nil {
		return "", err
	}
	defer ftpConn.Quit()

	// 构建完整的FTP路径
	basePath := client.ReadConfig("ftp.ftp_base_path")
	remotePath := basePath + "rsa_key/" + filename

	// 读取文件
	response, err := ftpConn.Retr(remotePath)
	if err != nil {
		return "", fmt.Errorf("FTP读取失败: %v", err)
	}
	defer response.Close()

	data, err := io.ReadAll(response)
	if err != nil {
		return "", fmt.Errorf("读取数据失败: %v", err)
	}

	return string(data), nil
}