RSA 加密算法是一种非对称加密算法,在许多项目中广泛使用,是当前数据安全加密中最常用的算法之一。在 Go 语言中,RSA 的加密、解密、签名与验签主要通过 crypto/x509
和 crypto/rsa
两个包的方法来实现。
加密与解密
RSA 通过生成一对公钥和私钥来进行加密和解密,公钥与私钥是相互对应的。公钥可以用来加密数据,但不能用于解密;而私钥则可以解密由对应公钥加密的数据。公钥可以公开分发,而私钥需要妥善保管,只有拥有私钥的人才能解密通过公钥加密的信息。
加密
代码示例:
func RsaEncryptBase64(originalData, publicKey string) (string, error) { block, _ := pem.Decode([]byte(publicKey)) if block == nil { return "", errors.New("公钥解码失败") }
pubKey, parseErr := x509.ParsePKIXPublicKey(block.Bytes) if parseErr != nil { return "", fmt.Errorf("解析公钥失败: %v", parseErr) }
keySize := pubKey.(*rsa.PublicKey).Size() maxEncryptSize := keySize - 11
var encryptedData []byte for len(originalData) > 0 { segment := originalData if len(segment) > maxEncryptSize { segment = originalData[:maxEncryptSize] }
encryptedSegment, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey.(*rsa.PublicKey), []byte(segment)) if err != nil { return "", fmt.Errorf("加密失败: %v", err) }
encryptedData = append(encryptedData, encryptedSegment...) originalData = originalData[len(segment):] }
return base64.StdEncoding.EncodeToString(encryptedData), nil }
|
解析:
originalData
,需要加密的原始数据。publicKey
,RSA 公钥。
注: RSA 加密时对明文长度有限制,超过限制需要分段处理。通常情况下,RSA 不用于加密过长的数据。具体限制为 密钥长度除8减11字节。例如,1024 位的 RSA 密钥最长可以加密 1024/8-11=117 Byte 的数据。
解密
代码示例:
func RsaDecryptBase64(encryptedData, privateKey string) (string, error) { encryptedDecodeBytes, err := base64.StdEncoding.DecodeString(encryptedData) if err != nil { return "", fmt.Errorf("Base64 解码失败: %v", err) }
block, _ := pem.Decode([]byte(privateKey)) if block == nil { return "", errors.New("私钥解码失败") }
priKey, parseErr := x509.ParsePKCS8PrivateKey(block.Bytes) if parseErr != nil { return "", fmt.Errorf("解析私钥失败: %v", parseErr) }
keySize := priKey.(*rsa.PrivateKey).Size()
var decryptedData []byte for len(encryptedDecodeBytes) > 0 { segment := encryptedDecodeBytes if len(segment) > keySize { segment = encryptedDecodeBytes[:keySize] }
decryptedSegment, err := rsa.DecryptPKCS1v15(rand.Reader, priKey.(*rsa.PrivateKey), segment) if err != nil { return "", fmt.Errorf("解密失败: %v", err) }
decryptedData = append(decryptedData, decryptedSegment...) encryptedDecodeBytes = encryptedDecodeBytes[len(segment):] }
return string(decryptedData), nil }
|
解析:
originalData
,Base64 编码的密文内容。privateKey
,RSA 私钥。返回值1
解密后的明文数据。
注: RSA 解密时对内容有同样的长度限制,见前文说明。
签名与验签
RSA 密钥对也可以用于签名和验签。不同于加密,签名的目的是验证消息的真实性,而非保护其机密性。消息的接收者通过验证签名来判断消息是否被篡改。只有持有私钥的人才能对信息进行签名,而持有公钥的人则可以验证签名的正确性。
签名
func signBase64(originalData, privateKey string) (string, error) { block, _ := pem.Decode([]byte(privateKey)) if block == nil { return "", errors.New("解析私钥失败: 无法解码PEM数据") }
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return "", fmt.Errorf("解析私钥失败: %v", err) }
hash := sha256.Sum256([]byte(originalData)) signature, err := rsa.SignPKCS1v15(rand.Reader, priKey.(*rsa.PrivateKey), crypto.SHA256, hash[:]) if err != nil { return "", fmt.Errorf("签名失败: %v", err) }
return base64.StdEncoding.EncodeToString(signature), nil }
|
验签
func verifySignWithBase64(originalData, signData, pubKey string) (bool, error) { sign, err := base64.StdEncoding.DecodeString(signData) if err != nil { return false, fmt.Errorf("签名解码失败: %v", err) }
block, _ := pem.Decode([]byte(pubKey)) if block == nil { return false, errors.New("解析公钥失败: 无法解码PEM数据") }
pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return false, fmt.Errorf("解析公钥失败: %v", err) }
hash := sha256.Sum256([]byte(originalData)) err = rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hash[:], sign) if err != nil { return false, fmt.Errorf("验签失败: %v", err) }
return true, nil }
|
附1:公私钥的生成
使用 Go 语言生成 RSA 公私钥非常简单。需要特别注意的是,私钥必须严格保密,防止泄露。以下是生成公私钥的代码:
func GenRsaKey(bits int) (privateKey, publicKey string) { priKey, err2 := rsa.GenerateKey(rand.Reader, bits) if err2 != nil { panic(err2) }
derStream := x509.MarshalPKCS1PrivateKey(priKey) block := &pem.Block{ Type: "PRIVATE KEY", Bytes: derStream, } prvKey := pem.EncodeToMemory(block) puKey := &priKey.PublicKey derPkix, err := x509.MarshalPKIXPublicKey(puKey) if err != nil { panic(err) } block = &pem.Block{ Type: "PUBLIC KEY", Bytes: derPkix, } pubKey := pem.EncodeToMemory(block)
privateKey = string(prvKey) publicKey = string(pubKey) return }
|
附2: PHP 中对应用法
加密
function rsaEncryptBase64($data, $publicKey) { $publicKey = openssl_get_publickey($publicKey); openssl_public_encrypt($data, $encrypt, $publicKey); openssl_free_key($publicKey); return base64_encode($encrypt); }
|
解密
function rsaEncryptBase64($data, $privateKey) { $privateKey = openssl_get_privatekey($privateKey); openssl_private_decrypt($data, $encrypt, $privateKey); openssl_free_key($privateKey); return base64_encode($encrypt); }
|
签名
function verySignWithBase64($original_data, $private_key) { $openssl_res = openssl_get_privatekey($private_key); openssl_sign($original_data, $signature, $openssl_res, OPENSSL_ALGO_SHA256); openssl_free_key($openssl_res);
return base64_encode($signature); }
|
验签
function verySignWithBase64($original_data, $signature, $public_key) { $openssl_res = openssl_get_publickey($public_key); $verify_res = openssl_verify($original_data, base64_decode($signature), $openssl_res, OPENSSL_ALGO_SHA256); openssl_free_key($openssl_res);
return 1 == $verify_res; }
|