Что такое симметричное шифрование, его плюсы, минусы и пример на 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).
  • Защита данных в базах данных.

Ответ 18+ 🔞

Давай я тебе про симметричное шифрование так объясню, чтобы ты не просто понял, а прочувствовал, как будто тебе на пальцах выложили, блядь.

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

Чем оно, сука, хорошо и плохо:

  • (+) Быстро, как угорелое: Алгоритмы эти, типа AES, просто летают по сравнению со своими асимметричными собратьями (это те, что RSA, с двумя ключами). Для шифрования терабайтов всякой хуйни — самое то.
  • (-) Головная боль с передачей ключа: А вот тут, блядь, собака зарыта. Как этому самому корежу ключ передать? По почте голубиной? Перехватят — и всё, пиздец вашей секретности, всё накрылось медным тазом. Вся безопасность в этом одном ключе висит, как волосок, сука.
  • Что почём: AES, ChaCha20 — это сейчас короли, блядь. DES уже старый пердун, его только в музее показывать.

Смотри, как на Go это выглядит (AES-GCM):

Этот режим — вообще красава, ёпта. Он не просто шифрует, а ещё и проверяет, что никто твои зашифрованные данные по дороге не поковырял. Называется — аутентифицированное шифрование. Умно, блядь.

package main

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

// encrypt — запирает сейф
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 — это типа одноразовый номер, уникальный для каждой операции. Не секретный, но должен быть разным всегда!
    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() {
    // Ключ. 32 байта — это для 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, этот самый: Сначала браузер и сервер через асимметричное шифрование (медленное, но безопасное) договариваются: "Так, брат, вот наш сессионный ключ". А дальше — понеслась душа в рай! Весь трафик гоняется уже по симметричному, быстрому.
  • Шифрование дисков (BitLocker, VeraCrypt): Твой комп превращается в сейф. Ключ — твой пароль.
  • Базы данных: Чтобы если утечка, то читали только свои, а не какие-то пидары налетели.

Вот так вот, просто и с душой. Понял да? Один ключ — и вся ответственность. Не потеряй, блядь.