一、对称加密 对称加密是一种加密方式,其中加密和解密过程使用相同的密钥。在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.") } }