Cryptography in Go (Golang): Data Encryption and Hashing
The Go language (Golang) provides a powerful and elegant standard library for cryptographic operations. Unlike many other languages where third-party packages need to be installed, Go includes support for symmetric and asymmetric encryption, as well as modern hashing algorithms, right out of the box. In this article, we will thoroughly examine how to use cryptography in Go to protect data on the educational portal pythonlib.ru.
Main Cryptography Packages in Go
All cryptography in Go is concentrated in the crypto package and its subpackages. Here are the key ones:
crypto/aes— implementation of the Advanced Encryption Standard (AES).crypto/cipher— interfaces for encryption modes (CBC, GCM, CTR).crypto/rsa— RSA asymmetric encryption.crypto/sha256,crypto/sha512— hash functions of the SHA-2 family.golang.org/x/crypto/bcrypt— adaptive password hashing (additional package).crypto/rand— cryptographically secure random number generator.
Symmetric AES Encryption in Go
Symmetric encryption uses the same key for encryption and decryption. Let's look at an example with AES-256 in GCM (Galois/Counter Mode), which provides data authentication.
package main
import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "fmt" "io")
func encryptAES(plaintext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err }
// Create GCM (Galois/Counter Mode) gcm, err := cipher.NewGCM(block) if err != nil { return nil, err }
// Generate a random nonce (number used once) nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err }
// Seal prepends the nonce to the ciphertext ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) return ciphertext, nil}
func decryptAES(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err }
gcm, err := cipher.NewGCM(block) if err != nil { return nil, err }
nonceSize := gcm.NonceSize() if len(ciphertext) < nonceSize { return nil, fmt.Errorf("ciphertext too short") }
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, err } return plaintext, nil}
func main() { key := []byte("examplekey123456") // 16 bytes for AES-128 plaintext := []byte("Secret data for PythonLib")
encrypted, _ := encryptAES(plaintext, key) fmt.Println("Encrypted (hex):", hex.EncodeToString(encrypted))
decrypted, _ := decryptAES(encrypted, key) fmt.Println("Decrypted:", string(decrypted))}Note: the key must be 16, 24, or 32 bytes long for AES-128, AES-192, or AES-256 respectively. The nonce (IV) is generated randomly and stored together with the ciphertext.
Asymmetric RSA Encryption in Go
RSA uses a pair of keys: a public key for encryption and a private key for decryption. This is ideal for secure data exchange between a server and a client.
package main
import ( "crypto/rand" "crypto/rsa" "crypto/sha256" "fmt")
func generateKeyPair(bits int) (*rsa.PrivateKey, error) {