切換語言為:簡體

盤點 Go 語言中的六種加密技術

  • 爱糖宝
  • 2024-10-11
  • 2045
  • 0
  • 0

一、對稱加密 對稱加密是一種加密方式,其中加密和解密過程使用相同的金鑰。在Go中,可以利用crypto/aes包來實現AES(高階加密標準)加密。以下是一個簡單的示例:

package main
import (
    "crypto/aes"
    "crypto/cipher"
    "fmt"
)

func main() {
    key := []byte("this is a very secret key") // 金鑰長度必須是16, 24或者32位元組
    plaintext := []byte("hello world")

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }

    ciphertext := make([]byte, aes.BlockSize+len(plaintext))
    iv := ciphertext[:aes.BlockSize]
    if _, err := rand.Read(iv); err != nil {
        panic(err)
    }
    stream := cipher.NewCFBEncrypter(block, iv)
    stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

    fmt.Printf("%x\n", ciphertext)  // 輸出加密後的文字
}

二、非對稱加密 非對稱加密採用一對金鑰:公鑰和私鑰。公鑰用於加密資訊,而私鑰則用於解密。RSA是一種廣泛使用的非對稱加密演算法,在Go中可以透過crypto/rsa包來使用它。

package main

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

// 生成RSA金鑰對
func generateKeyPair() (*rsa.PrivateKey, error) {
    return rsa.GenerateKey(rand.Reader, 2048)
}

// 將私鑰編碼為PEM格式
func encodePrivateKeyToPEM(privateKey *rsa.PrivateKey) (string, error) {
    privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
    pemBlock := &pem.Block{
        Type:  "RSA PRIVATE KEY",
        Bytes: privateKeyBytes,
    }
    return pem.EncodeToMemory(pemBlock), nil
}

// 將公鑰編碼為PEM格式
func encodePublicKeyToPEM(publicKey *rsa.PublicKey) (string, error) {
    publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
    if err != nil {
        return "", err
    }
    pemBlock := &pem.Block{
        Type:  "PUBLIC KEY",
        Bytes: publicKeyBytes,
    }
    return pem.EncodeToMemory(pemBlock), nil
}

// 使用公鑰加密資料
func encryptWithPublicKey(plaintext []byte, publicKey *rsa.PublicKey) ([]byte, error) {
    return rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, plaintext, nil)
}

// 使用私鑰解密資料
func decryptWithPrivateKey(ciphertext []byte, privateKey *rsa.PrivateKey) ([]byte, error) {
    return rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, nil)
}

func main() {
    // 生成金鑰對
    privateKey, err := generateKeyPair()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to generate key pair: %v\n", err)
        return
    }

    // 編碼金鑰為PEM格式
    privPEM, err := encodePrivateKeyToPEM(privateKey)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to encode private key: %v\n", err)
        return
    }
    pubPEM, err := encodePublicKeyToPEM(&privateKey.PublicKey)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to encode public key: %v\n", err)
        return
    }

    // 顯示PEM格式的金鑰
    fmt.Println("Private Key (PEM):")
    fmt.Println(string(privPEM))
    fmt.Println("Public Key (PEM):")
    fmt.Println(string(pubPEM))

    // 加密訊息
    message := []byte("Hello, RSA!")
    encrypted, err := encryptWithPublicKey(message, &privateKey.PublicKey)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Encryption failed: %v\n", err)
        return
    }
    fmt.Printf("Encrypted: %x\n", encrypted)

    // 解密訊息
    decrypted, err := decryptWithPrivateKey(encrypted, privateKey)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Decryption failed: %v\n", err)
        return
    }
    if string(decrypted) != string(message) {
        errors.New("Decrypted data does not match the original message")
    }
    fmt.Printf("Decrypted: %s\n", decrypted)
}

三、雜湊函式 雜湊函式可以將任意長度的資料對映為固定長度的值,並且這個轉換過程是不可逆的。常用的雜湊函式如SHA-256可以在crypto/sha256包中找到。下面是如何計算一段文字的SHA-256雜湊值的例子:

Go
import (
    "crypto/sha256"
    "fmt"
)

func main() {
    text := "Secure message"
    hash := sha256.Sum256([]byte(text))
    fmt.Printf("%x\n", hash)  // 輸出雜湊結果
}

四、數字簽名 數字簽名是一種用於驗證訊息完整性和來源的技術。在Go中,可以透過crypto/rsa包來建立和驗證RSA數字簽名。以下是一個簡單的例子:

Go
深色版本
package main
import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "fmt"
)

func main() {
    // 生成一對RSA金鑰
    privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        panic(err)
    }
    publicKey := &privateKey.PublicKey

    message := []byte("Very important data")
    hash := sha256.Sum256(message)

    // 使用私鑰對雜湊值進行簽名
    signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hash[:])
    if err != nil {
        panic(err)
    }

    // 驗證簽名
    err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hash[:], signature)
    if err != nil {
        fmt.Println("Signature verification failed.")
    } else {
        fmt.Println("Signature is valid.")
    }
}

五、安全的隨機數生成 對於任何加密操作而言,高質量的隨機性都是至關重要的。Go提供了crypto/rand包,它基於作業系統提供的加密級隨機源。例如,生成一個隨機位元組序列可以這樣實現:

Go
深色版本
package main
import (
    "crypto/rand"
    "fmt"
)

func main() {
    randomBytes := make([]byte, 32) // 生成32個位元組的隨機資料
    _, err := rand.Read(randomBytes)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%x\n", randomBytes)
}

六、密碼雜湊與加鹽 直接儲存使用者密碼是不安全的做法。通常我們會使用單向雜湊函式(如bcrypt)結合“鹽”來處理密碼。golang.org/x/crypto/bcrypt庫提供了一個方便的方式來執行這一過程:

Go
深色版本
package main
import (
    "golang.org/x/crypto/bcrypt"
    "fmt"
)

func main() {
    password := []byte("password123")

    // 生成帶鹽的雜湊值
    hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(hashedPassword))

    // 檢查密碼是否匹配
    err = bcrypt.CompareHashAndPassword(hashedPassword, password)
    if err == nil {
        fmt.Println("Password matches!")
    } else {
        fmt.Println("Incorrect password.")
    }
}

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.