Paquete crypto en Go
El paquete crypto en Go es una colección de subpaquetes que proporcionan diversas funcionalidades criptográficas. Este documento explora en detalle cada subpaquete con ejemplos prácticos y casos de uso.
1. crypto/aes (Advanced Encryption Standard)
1.1 Cifrado AES-GCM
func ejemploAESGCM() {
// Clave debe ser de 16, 24 o 32 bytes (para AES-128, AES-192 o AES-256)
key := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, key); err != nil {
panic(err)
}
// Crear cipher block
block, err := aes.NewCipher(key)
if (err != nil) {
panic(err)
}
// Crear GCM (Galois/Counter Mode)
gcm, err := cipher.NewGCM(block)
if (err != nil) {
panic(err)
}
// Crear nonce
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
panic(err)
}
// Datos a cifrar
plaintext := []byte("Información secreta")
// Cifrar
ciphertext := gcm.Seal(nil, nonce, plaintext, nil)
// Descifrar
plaintext2, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err)
}
fmt.Printf("Texto original: %s\n", plaintext)
fmt.Printf("Texto descifrado: %s\n", plaintext2)
}
1.2 Cifrar Archivo con AES
func cifrarArchivo(inputPath, outputPath string, key []byte) error {
// Abrir archivo de entrada
input, err := os.Open(inputPath)
if err != nil {
return err
}
defer input.Close()
// Crear archivo de salida
output, err := os.Create(outputPath)
if err != nil {
return err
}
defer output.Close()
// Crear cipher block
block, err := aes.NewCipher(key)
if err != nil {
return err
}
// Crear GCM
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
// Crear nonce
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return err
}
// Escribir nonce al inicio del archivo
if _, err := output.Write(nonce); err != nil {
return err
}
// Crear writer con cifrado
writer := &cipher.StreamWriter{
S: cipher.NewCTR(block, nonce),
W: output,
}
// Copiar y cifrar datos
if _, err := io.Copy(writer, input); err != nil {
return err
}
return nil
}
2. crypto/rsa
2.1 Cifrado y Descifrado RSA
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"fmt"
)
func main() {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
message := []byte("Hello, world!")
label := []byte("")
hash := sha256.New()
ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, publicKey, message, label)
if err != nil {
panic(err)
}
fmt.Printf("Encrypted message: %x\n", ciphertext)
plaintext, err := rsa.DecryptOAEP(hash, rand.Reader, privateKey, ciphertext, label)
if err != nil {
panic(err)
}
fmt.Printf("Decrypted message: %s\n", plaintext)
}
2.2 Generar y Guardar Claves RSA
func generarGuardarClaves() error {
// Generar par de claves
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return err
}
// Convertir a PEM
privateKeyPEM := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
}
publicKeyPEM := &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: x509.MarshalPKCS1PublicKey(&privateKey.PublicKey),
}
// Guardar clave privada
privateKeyFile, err := os.Create("private.pem")
if err != nil {
return err
}
defer privateKeyFile.Close()
if err := pem.Encode(privateKeyFile, privateKeyPEM); err != nil {
return err
}
// Guardar clave pública
publicKeyFile, err := os.Create("public.pem")
if err != nil {
return err
}
defer publicKeyFile.Close()
return pem.Encode(publicKeyFile, publicKeyPEM)
}
2.3 Firmar y Verificar Documentos con RSA
type DocumentoFirmado struct {
Contenido []byte
Firma []byte
FechaFirma time.Time
FirmadoPor string
}
func firmarDocumento(documento []byte, privateKey *rsa.PrivateKey, firmadoPor string) (*DocumentoFirmado, error) {
// Calcular hash del documento
hashed := sha256.Sum256(documento)
// Firmar el hash
firma, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA256, hashed[:], nil)
if err != nil {
return nil, err
}
return &DocumentoFirmado{
Contenido: documento,
Firma: firma,
FechaFirma: time.Now(),
FirmadoPor: firmadoPor,
}, nil
}
func verificarFirma(doc *DocumentoFirmado, publicKey *rsa.PublicKey) error {
// Calcular hash del documento
hashed := sha256.Sum256(doc.Contenido)
// Verificar firma
return rsa.VerifyPSS(publicKey, crypto.SHA256, hashed[:], doc.Firma, nil)
}
3. crypto/md5
3.1 Hash MD5
package main
import (
"crypto/md5"
"fmt"
)
func main() {
data := []byte("Hello, world!")
hash := md5.Sum(data)
fmt.Printf("MD5 hash: %x\n", hash)
}
4. crypto/sha256
4.1 Hash SHA-256
package main
import (
"crypto/sha256"
"fmt"
)
func main() {
data := []byte("Hello, world!")
hash := sha256.Sum256(data)
fmt.Printf("SHA-256 hash: %x\n", hash)
}
5. crypto/hmac
5.1 HMAC con SHA-256
package main
import (
"crypto/hmac"
"crypto/sha256"
"fmt"
)
func main() {
key := []byte("secret key")
message := []byte("Hello, world!")
hash := hmac.New(sha256.New, key)
hash.Write(message)
sum := hash.Sum(nil)
fmt.Printf("HMAC: %x\n", sum)
}
5.2 Crear y Verificar Mensaje Autenticado
type MensajeAutenticado struct {
Contenido []byte
HMAC []byte
Timestamp time.Time
}
func crearMensajeAutenticado(contenido []byte, key []byte) *MensajeAutenticado {
h := hmac.New(sha256.New, key)
h.Write(contenido)
return &MensajeAutenticado{
Contenido: contenido,
HMAC: h.Sum(nil),
Timestamp: time.Now(),
}
}
func verificarMensaje(mensaje *MensajeAutenticado, key []byte) bool {
h := hmac.New(sha256.New, key)
h.Write(mensaje.Contenido)
expectedHMAC := h.Sum(nil)
return hmac.Equal(mensaje.HMAC, expectedHMAC)
}
Subpaquetes adicionales en crypto
crypto/ecdsa: Implementa las funciones para la firma y verificación con el algoritmo ECDSA (Elliptic Curve Digital Signature Algorithm).crypto/elliptic: Implementa las curvas elípticas utilizadas en criptografía.crypto/des: Implementa el cifrado y descifrado según el estándar DES (Data Encryption Standard) y Triple DES.
Descripción General
crypto/aes: Cifrado y descifrado simétrico según AES.crypto/rsa: Cifrado, descifrado, firma y verificación según RSA.crypto/md5: Algoritmo de hash MD5 (no recomendado para criptografía).crypto/sha256: Algoritmo de hash SHA-256.crypto/hmac: Algoritmo HMAC para autenticación e integridad de mensajes.crypto/ecdsa: Firma y verificación con ECDSA.crypto/elliptic: Implementaciones de curvas elípticas.crypto/des: Cifrado y descifrado según DES y Triple DES.
Estos son algunos de los componentes más importantes del paquete crypto en Go. Cada uno de estos subpaquetes ofrece herramientas esenciales para implementar diversas funcionalidades criptográficas. Si necesitas más información o ejemplos sobre algún subpaquete en particular, ¡háblame! Estoy aquí para ayudarte.
6. Generar Contraseñas Seguras
6.1 Generar Contraseña Aleatoria
func generarPassword(longitud int) (string, error) {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+"
bytes := make([]byte, longitud)
if _, err := rand.Read(bytes); err != nil {
return "", err
}
for i, b := range bytes {
bytes[i] = charset[b%byte(len(charset))]
}
return string(bytes), nil
}
6.2 Hash de Contraseña
func hashPassword(password string) (string, error) {
// Generar salt aleatorio
salt := make([]byte, 16)
if _, err := rand.Read(salt); err != nil {
return "", err
}
// Derivar clave usando Argon2
key := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)
// Codificar resultado
encoded := base64.StdEncoding.EncodeToString(append(salt, key...))
return encoded, nil
}
Mejores Prácticas
- Gestión de Claves
- Almacenar claves de forma segura
- Rotar claves periódicamente
- Usar generadores de números aleatorios seguros
- Manejo de Errores
- Validar entradas
- Manejar errores criptográficos apropiadamente
- No exponer información sensible en errores
- Consideraciones de Rendimiento
- Usar búfers para operaciones grandes
- Implementar caché cuando sea apropiado
- Considerar operaciones concurrentes