Что такое симметричное шифрование, его плюсы, минусы и пример на Go?

Ответ

Симметричное шифрование — это метод криптографии, при котором один и тот же ключ используется как для шифрования (превращения открытого текста в шифротекст), так и для расшифровки (обратного процесса).

Представьте, что у вас есть сейф с одним ключом. Вы запираете им ценности, а чтобы их достать, получатель должен использовать точную копию того же ключа.

Ключевые характеристики:

  • (+) Высокая скорость: Симметричные алгоритмы (например, AES) значительно быстрее асимметричных (например, RSA), что делает их идеальными для шифрования больших объемов данных.
  • (-) Проблема распределения ключей: Главный недостаток — необходимость безопасно передать секретный ключ получателю. Если ключ перехватят, вся система будет скомпрометирована.
  • Популярные алгоритмы: AES (Advanced Encryption Standard), ChaCha20, DES, 3DES, Blowfish.

Пример на Go (AES в режиме GCM):

AES-GCM — это современный и рекомендуемый режим, так как он обеспечивает не только конфиденциальность, но и аутентифицированное шифрование (AEAD), то есть защищает от подделки зашифрованных данных.

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "fmt"
    "io"
)

// encrypt шифрует данные с использованием AES-GCM
func encrypt(plaintext []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
    }

    // Nonce (number used once) — это уникальный для каждого шифрования номер.
    // Он не секретный, но должен быть уникальным для данной пары ключ-сообщение.
    nonce := make([]byte, gcm.NonceSize())
    if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
        return nil, err
    }

    // Шифруем и добавляем nonce в начало шифротекста для последующей расшифровки.
    ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
    return ciphertext, nil
}

// decrypt расшифровывает данные
func decrypt(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, encryptedMessage := ciphertext[:nonceSize], ciphertext[nonceSize:]
    return gcm.Open(nil, nonce, encryptedMessage, nil)
}

func main() {
    // Ключ должен быть 16, 24 или 32 байта для AES-128, AES-192, AES-256.
    key := make([]byte, 32)
    // В реальном приложении ключ должен быть сгенерирован и сохранен безопасно.
    rand.Read(key)

    data := []byte("очень секретное сообщение")

    encrypted, _ := encrypt(data, key)
    decrypted, _ := decrypt(encrypted, key)

    fmt.Printf("Расшифровано: %sn", string(decrypted))
}

Практическое применение:

  • HTTPS/TLS: После того как клиент и сервер безопасно обменялись сессионным ключом с помощью асимметричного шифрования, весь последующий трафик шифруется симметрично с помощью этого ключа.
  • Шифрование файлов и дисков: (например, BitLocker, VeraCrypt).
  • Защита данных в базах данных.