最近参与借贷业务的开发,接口传输过程中需要使用 RSA 加密算法对请求和返回进行加密,所以写了这篇博客。主要介绍 RSA 的基础知识和 golang 使用例子
概念介绍
RSA 是一个非对称加密算法,是目前使用最广的数据安全加密算法之一。
RSA 通过生成公钥和与之对应的私钥来进行加解密的,公钥与私钥一一对应。
虽然私钥可以用于加密数据,但因为公钥是对外的,所以加密数据的意义不大,因为知道公钥的都能解密,所以 RSA 常见用法有下面两种
- 公钥加密数据,私钥解密数据
- 私钥则用户签名,公钥用于验签
密钥格式
- PKCS#8 密钥格式,多用于JAVA、PHP程序加解密中,为目前用的比较多的密钥、证书格式;
- PKCS#1 密钥格式,多用于JS等其它程序加解密,属于比较老的格式标准。
PKCS#1 和 PKCS#8 的主要区别,从本质上说,PKCS#8 格式增加验证数据段,保证密钥正确性。
RSA 加解密(PKCS#8 格式)
RSA非对称加密算法,被加密的数据长度,需要短于公私钥的长度,否则会加密失败。所以针对比较长的数据一般采用分段加解密
代码语言:javascript复制// RsaPubEncrypt 使用公钥分段加密数据
func RsaPubEncrypt(data []byte, publicKeyPEM string) (bytesEncrypt string, err error) {
// 解码公钥
publicKeyPEM, err = ReadFile(publicKeyPEM)
block, _ := pem.Decode([]byte(publicKeyPEM))
if block == nil {
return "", fmt.Errorf("failed to parse public key")
}
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return
}
keySize, srcSize := publicKey.(*rsa.PublicKey).Size(), len(data)
//单次加密的长度需要减掉padding的长度,PKCS1为11
offSet, once := 0, keySize-11
buffer := bytes.Buffer{}
for offSet < srcSize {
endIndex := offSet once
if endIndex > srcSize {
endIndex = srcSize
}
// 加密一部分
bytesOnce, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey.(*rsa.PublicKey), data[offSet:endIndex])
if err != nil {
return "", err
}
buffer.Write(bytesOnce)
offSet = endIndex
}
bytesEncrypt = base64.StdEncoding.EncodeToString(buffer.Bytes())
return
}
// RsaPriDecrypt 使用私钥分段解密数据
func RsaPriDecrypt(encryptedData, privateKeyPEM string) (bytesDecrypt string, err error) {
privateKeyPEM, err = ReadFile(privateKeyPEM)
block, _ := pem.Decode([]byte(privateKeyPEM))
if block == nil {
return "", fmt.Errorf("failed to parse private key")
}
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return
}
// 解码加密的数据
encrypted, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return "", fmt.Errorf("failed to decode base64: %v", err)
}
keySize := privateKey.(*rsa.PrivateKey).Size()
srcSize := len(encrypted)
var offSet = 0
var buffer = bytes.Buffer{}
for offSet < srcSize {
endIndex := offSet keySize
if endIndex > srcSize {
endIndex = srcSize
}
bytesOnce, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), encrypted[offSet:endIndex])
if err != nil {
return "", err
}
buffer.Write(bytesOnce)
offSet = endIndex
}
bytesDecrypt = buffer.String()
return
}
RSA 验签(PKCS#8 格式)
代码语言:javascript复制// GetSign RSA生成签名
func GetSign(signString string, priKey string) (string, error) {
priKey, err := ReadFile(priKey)
block, _ := pem.Decode([]byte(priKey))
if block == nil {
return "", fmt.Errorf("Failed to decode PEM block")
}
privKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
h := sha1.New()
h.Write([]byte(signString))
hashed := h.Sum(nil)
signature, err := rsa.SignPKCS1v15(rand.Reader, privKey.(*rsa.PrivateKey), crypto.SHA1, hashed)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(signature), nil
}
// CheckSign RSA校验
func CheckSign(pubKey string, sign string, toSign string) (bool, error) {
pubKey, err := ReadFile(pubKey)
if err != nil {
return false, err
}
block, _ := pem.Decode([]byte(pubKey))
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return false, err
}
signature, _ := base64.StdEncoding.DecodeString(sign)
h := sha1.New()
h.Write([]byte(toSign))
hashed := h.Sum(nil)
err = rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA1, hashed, signature)
if err != nil {
return false, err
}
return true, nil
}