Интерфейс cipher.Stream
Интерфейс cipher.Stream представляет поточный шифр,
который преобразует данные блоками произвольного размера.
Он определяет метод XORKeyStream, который принимает
слайсы байт dst и src и выполняет операцию
исключающего ИЛИ (XOR) между данными и ключевым потоком.
Результат записывается в dst. Важно, что dst
и src могут указывать на одну и ту же область памяти,
что позволяет выполнять шифрование "на месте".
Синтаксис
type Stream interface {
XORKeyStream(dst, src []byte)
}
Метод XORKeyStream принимает два слайса байт:
первый параметр dst — это буфер для записи результата,
второй параметр src — исходные данные для шифрования.
Размеры слайсов должны быть одинаковыми. Метод изменяет
состояние шифра, поэтому один экземпляр не может быть
использован повторно для разных данных.
Пример
Давайте создадим поточный шифр на основе режима CTR (Counter) с использованием алгоритма AES и зашифруем небольшой фрагмент данных:
package 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)
}
Результат выполнения кода:
"7a9e3d8f2c1b5a6e4d8f2c1b5a6e4d8f"
Пример
Давайте расшифруем данные, используя тот же потоковый шифр и тот же ключ. Поскольку режим CTR является потоковым, процесс расшифровки идентичен процессу шифрования:
package 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)
}
Результат выполнения кода:
"Hello, World!"
Пример
Давайте выполним шифрование "на месте", используя один и тот же слайс для входа и выхода. Это эффективный способ избежать дополнительного выделения памяти:
package 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)
}
Результат выполнения кода:
"5c1b3d9e7a2f6c4d8e1b3a5c7d9e2f4a"
Смотрите также
-
интерфейс
cipher.Block,
который представляет блочный шифр -
интерфейс
cipher.BlockMode,
который представляет режим работы блочного шифра -
функцию
cipher.NewCTR,
которая создает потоковый шифр в режиме CTR -
функцию
cipher.NewOFB,
которая создает потоковый шифр в режиме OFB