一、對稱加密 對稱加密是一種加密方式,其中加密和解密過程使用相同的金鑰。在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.") } }