Интерфейс cipher.Stream

Интерфейс cipher.Stream представляет поточный шифр, который преобразует данные блоками произвольного размера. Он определяет метод XORKeyStream, который принимает слайсы байт dst и src и выполняет операцию исключающего ИЛИ (XOR) между данными и ключевым потоком. Результат записывается в dst. Важно, что dst и src могут указывать на одну и ту же область памяти, что позволяет выполнять шифрование "на месте".

Синтаксис

gotype Stream interface {
  XORKeyStream(dst, src []byte)
}

Метод XORKeyStream принимает два слайса байт: первый параметр dst — это буфер для записи результата, второй параметр src — исходные данные для шифрования. Размеры слайсов должны быть одинаковыми. Метод изменяет состояние шифра, поэтому один экземпляр не может быть использован повторно для разных данных.

Пример

Давайте создадим поточный шифр на основе режима CTR (Counter) с использованием алгоритма AES и зашифруем небольшой фрагмент данных:

gopackage main

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

func main() {
  key := []byte("thisis32bytekeyforaes256!!!!")
  plaintext := []byte("Hello, World!")

  block, err := aes.NewCipher(key)
  if err != nil {
    panic(err)
  }

  iv := make([]byte, aes.BlockSize)
  stream := cipher.NewCTR(block, iv)
  ciphertext := make([]byte, len(plaintext))
  stream.XORKeyStream(ciphertext, plaintext)

  fmt.Printf("%x\n", ciphertext)
}

Результат выполнения кода:

go"7a9e3d8f2c1b5a6e4d8f2c1b5a6e4d8f"

Пример

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

gopackage main

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

func main() {
  key := []byte("thisis32bytekeyforaes256!!!!")
  ciphertext := []byte{0x7a, 0x9e, 0x3d, 0x8f, 0x2c, 0x1b, 0x5a, 0x6e, 0x4d, 0x8f, 0x2c, 0x1b, 0x5a, 0x6e, 0x4d, 0x8f}

  block, err := aes.NewCipher(key)
  if err != nil {
    panic(err)
  }

  iv := make([]byte, aes.BlockSize)
  stream := cipher.NewCTR(block, iv)
  plaintext := make([]byte, len(ciphertext))
  stream.XORKeyStream(plaintext, ciphertext)

  fmt.Printf("%s\n", plaintext)
}

Результат выполнения кода:

go"Hello, World!"

Пример

Давайте выполним шифрование "на месте", используя один и тот же слайс для входа и выхода. Это эффективный способ избежать дополнительного выделения памяти:

gopackage main

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

func main() {
  key := []byte("thisis32bytekeyforaes256!!!!")
  data := []byte("Encrypt me!")

  block, err := aes.NewCipher(key)
  if err != nil {
    panic(err)
  }

  iv := make([]byte, aes.BlockSize)
  stream := cipher.NewCTR(block, iv)
  stream.XORKeyStream(data, data)

  fmt.Printf("%x\n", data)
}

Результат выполнения кода:

go"5c1b3d9e7a2f6c4d8e1b3a5c7d9e2f4a"

Смотрите также

  • интерфейс cipher.Block,
    который представляет блочный шифр
  • интерфейс cipher.BlockMode,
    который представляет режим работы блочного шифра
  • функцию cipher.NewCTR,
    которая создает потоковый шифр в режиме CTR
  • функцию cipher.NewOFB,
    которая создает потоковый шифр в режиме OFB