Go 語言的 RSA 加密與解密:方法與最佳實踐

一般對接過支付業務的都知道,RSA 算法。

RSA 是一種廣泛應用於安全通信領域的非對稱加密算法。

它使用一對密鑰(公鑰和私鑰)來加密和解密數據,在互聯網通信、數字簽名等場景中具有重要作用。

咱們一起看一下,在 Go 語言中,如何使用 RSA 算法。

一、RSA 加密與解密的基礎知識

1. 非對稱加密

RSA 屬於非對稱加密算法,主要特點是密鑰成對使用:一個用於加密(公鑰),另一個用於解密(私鑰)。

使用公鑰加密的數據只能用對應的私鑰解密,反之亦然。

這一特性使 RSA 非常適合用於安全通信和數字簽名。

2. 密鑰生成

RSA 密鑰由公鑰和私鑰構成。公鑰可以公開分發,而私鑰必須嚴格保密。

Go 提供了 crypto/rsacrypto/rand 包,允許我們生成和使用 RSA 密鑰對。

二、RSA 加密與解密的實現

在 Go 中,實現 RSA 加密與解密涉及以下幾個步驟:

  1. 生成 RSA 密鑰對。

  2. 使用公鑰加密數據。

  3. 使用私鑰解密數據。

下面,我們將依次實現這些操作。

三、RSA 加密與解密方法

1. 生成 RSA 密鑰對

首先,我們需要生成一對 RSA 密鑰。

可以使用 crypto/rsacrypto/rand 包來完成這一步。

通常,密鑰長度建議使用 2048 位及以上,以保證安全性。

package main

import (
 "crypto/rand"
 "crypto/rsa"
 "crypto/x509"
 "encoding/pem"
 "fmt"
 "os"
)

// 生成 RSA 密鑰對並保存到文件中
func generateRSAKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey) {
 // 生成私鑰
 privateKey, err := rsa.GenerateKey(rand.Reader, bits)
 if err != nil {
  fmt.Println("Failed to generate private key:", err)
  return nil, nil
 }

 // 通過私鑰獲取公鑰
 publicKey := &privateKey.PublicKey

 // 保存私鑰到文件
 savePEMKey("private.pem", privateKey)

 // 保存公鑰到文件
 savePublicPEMKey("public.pem", publicKey)

 return privateKey, publicKey
}

// 將私鑰保存到 PEM 文件
func savePEMKey(fileName string, key *rsa.PrivateKey) {
 file, err := os.Create(fileName)
 if err != nil {
  fmt.Println("Failed to create key file:", err)
  return
 }
 defer file.Close()

 // 將私鑰編碼爲 PEM 格式
 privateKeyPEM := pem.EncodeToMemory(
  &pem.Block{
   Type:  "RSA PRIVATE KEY",
   Bytes: x509.MarshalPKCS1PrivateKey(key),
  },
 )

 file.Write(privateKeyPEM)
}

// 將公鑰保存到 PEM 文件
func savePublicPEMKey(fileName string, pubkey *rsa.PublicKey) {
 file, err := os.Create(fileName)
 if err != nil {
  fmt.Println("Failed to create key file:", err)
  return
 }
 defer file.Close()

 // 將公鑰編碼爲 PKIX 格式的 PEM
 pubKeyBytes, err := x509.MarshalPKIXPublicKey(pubkey)
 if err != nil {
  fmt.Println("Failed to marshal public key:", err)
  return
 }

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

 file.Write(publicKeyPEM)
}

上述代碼生成一對 RSA 密鑰,並將私鑰和公鑰分別保存到 private.pempublic.pem 文件中。

密鑰長度建議爲 2048 或 4096 位,以確保安全性。

2. 使用公鑰加密數據

使用公鑰加密數據時,通常需要使用 crypto/rsa 包的 EncryptOAEP 函數,該函數基於 Optimal Asymmetric Encryption Padding (OAEP):https://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding,提供了更高的安全性。

// 使用公鑰加密
func encryptWithPublicKey(msg string, pub *rsa.PublicKey) []byte {
 // 使用公鑰加密數據,採用 OAEP padding
 ciphertext, err := rsa.EncryptOAEP(
  sha256.New(),
  rand.Reader,
  pub,
  []byte(msg),
  nil,
 )
 if err != nil {
  fmt.Println("Encryption failed:", err)
  return nil
 }

 return ciphertext
}

在此示例中,使用 rsa.EncryptOAEP 進行加密,推薦使用 SHA-256 作爲哈希函數,確保數據安全。

3. 使用私鑰解密數據

要解密用公鑰加密的數據,需要使用私鑰。我們將使用 crypto/rsa 包中的 DecryptOAEP 函數來完成這一操作。

import (
 "crypto/sha256"
 "crypto/x509"
 "encoding/pem"
 "io/ioutil"
)

// 從 PEM 文件中加載私鑰
func loadPrivateKey(fileName string) *rsa.PrivateKey {
 data, err := ioutil.ReadFile(fileName)
 if err != nil {
  fmt.Println("Failed to read private key file:", err)
  return nil
 }

 block, _ := pem.Decode(data)
 if block == nil || block.Type != "RSA PRIVATE KEY" {
  fmt.Println("Failed to decode PEM block containing private key")
  return nil
 }

 // 解析私鑰
 privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
 if err != nil {
  fmt.Println("Failed to parse private key:", err)
  return nil
 }

 return privateKey
}

// 使用私鑰解密
func decryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) string {
 // 使用私鑰解密數據,採用 OAEP padding
 plaintext, err := rsa.DecryptOAEP(
  sha256.New(),
  rand.Reader,
  priv,
  ciphertext,
  nil,
 )
 if err != nil {
  fmt.Println("Decryption failed:", err)
  return ""
 }

 return string(plaintext)
}

在這個示例中,我們使用 rsa.DecryptOAEP 函數和私鑰解密數據,並將加密文本轉換回明文。

4. 完整示例:加密和解密

func main() {
 // 生成密鑰對
 privateKey, publicKey := generateRSAKeyPair(2048)

 // 原始消息
 message := "Hello, RSA!"

 // 使用公鑰加密
 ciphertext := encryptWithPublicKey(message, publicKey)
 fmt.Printf("Encrypted message: %x\n", ciphertext)

 // 使用私鑰解密
 plaintext := decryptWithPrivateKey(ciphertext, privateKey)
 fmt.Printf("Decrypted message: %s\n", plaintext)
}

四、最佳實踐

  1. 密鑰安全:私鑰必須妥善保存,絕不能以明文形式存儲在代碼倉庫中。可以使用加密密鑰庫(如 AWS KMS、HashiCorp Vault 等)來保護密鑰。

  2. OAEP Padding:在 RSA 加密中,始終使用 OAEP(Optimal Asymmetric Encryption Padding)以抵禦多種攻擊。

  3. 密鑰長度:使用至少 2048 位的密鑰長度,建議使用 4096 位以增強安全性。

  4. 錯誤處理:在加密和解密過程中,注意檢查並處理可能出現的錯誤,避免信息泄露。

  5. 避免直接加密大數據:RSA 不適合直接加密大量數據。通常應將數據先用對稱加密算法(如 AES)加密,再用 RSA 加密對稱密鑰。

五、最後

從密鑰生成開始,介紹瞭如何進行公鑰加密和私鑰解密,並給出了最佳實踐,以確保數據的安全性。

在實際應用中,請根據具體的安全要求合理使用 RSA。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/O4taKtCMyiwb0ksUOqE2OQ