RSA 加密算法与 golang 代码实现

2023-11-27 22:25:20 浏览数 (1)

最近参与借贷业务的开发,接口传输过程中需要使用 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
}
go

0 人点赞