Пакет шифрования
Обзор
Пакет cipher реализует стандартные режимы блочного шифрования, которые можно использовать вместе с реализациями блочных шифров низкого уровня. См. https://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html и Специальное издание NIST 800-38A.
Индекс
Примеры
Файлы пакета
cbc.go cfb.go cipher.go ctr.go gcm.go io.go ofb.go
тип AEAD 1.2
AEAD — это режим шифрования, предоставляющий аутентифицированное шифрование с сопутствующими данными. Для описания методологии см. https://en.wikipedia.org/wiki/Authenticated_encryption.
type AEAD interface {
// NonceSize returns the size of the nonce that must be passed to Seal
// and Open.
NonceSize() int
// Overhead returns the maximum difference between the lengths of a
// plaintext and its ciphertext.
Overhead() int
// Seal encrypts and authenticates plaintext, authenticates the
// additional data and appends the result to dst, returning the updated
// slice. The nonce must be NonceSize() bytes long and unique for all
// time, for a given key.
//
// To reuse plaintext's storage for the encrypted output, use plaintext[:0]
// as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
// dst and additionalData may not overlap.
Seal(dst, nonce, plaintext, additionalData []byte) []byte
// Open decrypts and authenticates ciphertext, authenticates the
// additional data and, if successful, appends the resulting plaintext
// to dst, returning the updated slice. The nonce must be NonceSize()
// bytes long and both it and the additional data must match the
// value passed to Seal.
//
// To reuse ciphertext's storage for the decrypted output, use ciphertext[:0]
// as dst. Otherwise, the remaining capacity of dst must not overlap ciphertext.
// dst and additionalData may not overlap.
//
// Even if the function fails, the contents of dst, up to its capacity,
// may be overwritten.
Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error)
} функция NewGCM 1.2
func NewGCM(cipher Block) (AEAD, error)
NewGCM возвращает заданный 128-битный, блочный шифр, упакованный в режиме Galois Counter с стандартной длиной nonce.
В общем случае операция GHASH, выполняемая этой реализацией GCM, не является постоянной по времени. Исключением является случай, когда базовый Block был создан функцией aes.NewCipher на системах с аппаратной поддержкой AES. Подробности см. в документации пакета crypto/aes.
Пример (Расшифрование)
Код:
// Load your secret key from a safe place and reuse it across multiple
// Seal/Open calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
// When decoded the key should be 16 bytes (AES-128) or 32 (AES-256).
key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
ciphertext, _ := hex.DecodeString("c3aaa29f002ca75870806e44086700f62ce4d43e902b3888e23ceff797a7a471")
nonce, _ := hex.DecodeString("64a9433eae7ccceee2fc0eda")
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}
fmt.Printf("%s\n", plaintext)
Вывод:
exampleplaintext
Пример (Шифрование)
Код:
// Load your secret key from a safe place and reuse it across multiple
// Seal/Open calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
// When decoded the key should be 16 bytes (AES-128) or 32 (AES-256).
key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
plaintext := []byte("exampleplaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
fmt.Printf("%x\n", ciphertext)
функция NewGCMWithNonceSize 1.5
func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error)
NewGCMWithNonceSize возвращает заданный 128-битный, блочный шифр, упакованный в режиме Galois Counter Mode, который принимает nonce заданной длины. Длина не должна быть равна нулю.
Используйте эту функцию только если вам нужна совместимость с существующей криптосистемой, которая использует нестандартные длины nonce. Все остальные пользователи должны использовать NewGCM, который быстрее и более устойчив к злоупотреблениям.
функция NewGCMWithRandomNonce 1.24
func NewGCMWithRandomNonce(cipher Block) (AEAD, error)
NewGCMWithRandomNonce возвращает заданный шифр, упакованный в Galois Counter Mode, со случайными nonce. Шифр должен быть создан с помощью aes.NewCipher.
Он генерирует случайный 96-битный nonce, который добавляется в заголовок шифрованного текста функцией Seal, и извлекается из зашифрованного текста функцией Open. Размер nonce AEAD равен нулю, в то время как Overhead составляет 28 байт (комбинация размера nonce и размера тега).
Заданный ключ НЕ ДОЛЖЕН использоваться для шифрования более 2^32 сообщений, чтобы ограничить риск столкновения случайных nonce до незначительных уровней.
функция NewGCMWithTagSize 1.11
func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error)
NewGCMWithTagSize возвращает заданный 128-битный, блочный шифр, упакованный в режиме Galois Counter Mode, который генерирует теги заданной длины.
Разрешены размеры тегов от 12 до 16 байт.
Используйте эту функцию только если вам нужна совместимость с существующей криптосистемой, которая использует нестандартные длины тегов. Все остальные пользователи должны использовать NewGCM, который более устойчив к злоупотреблениям.
тип Block
Block представляет реализацию блочного шифра с использованием заданного ключа. Он предоставляет возможность шифрования или дешифрования отдельных блоков. Реализации режима расширяют эту возможность до потоков блоков.
type Block interface {
// BlockSize returns the cipher's block size.
BlockSize() int
// Encrypt encrypts the first block in src into dst.
// Dst and src must overlap entirely or not at all.
Encrypt(dst, src []byte)
// Decrypt decrypts the first block in src into dst.
// Dst and src must overlap entirely or not at all.
Decrypt(dst, src []byte)
} тип BlockMode
BlockMode представляет собой блочный шифр, работающий в блочном режиме (CBC, ECB и т. д.).
type BlockMode interface {
// BlockSize returns the mode's block size.
BlockSize() int
// CryptBlocks encrypts or decrypts a number of blocks. The length of
// src must be a multiple of the block size. Dst and src must overlap
// entirely or not at all.
//
// If len(dst) < len(src), CryptBlocks should panic. It is acceptable
// to pass a dst bigger than src, and in that case, CryptBlocks will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to CryptBlocks behave as if the concatenation of
// the src buffers was passed in a single run. That is, BlockMode
// maintains state and does not reset at each CryptBlocks call.
CryptBlocks(dst, src []byte)
} функция NewCBCDecrypter
func NewCBCDecrypter(b Block, iv []byte) BlockMode
NewCBCDecrypter возвращает BlockMode, который расшифровывает в режиме шифра с цепочкой блоков, используя заданный Block. Длина iv должна быть такой же, как размер блока Block, и должна совпадать с iv, используемым для шифрования данных.
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
// CBC mode always works in whole blocks.
if len(ciphertext)%aes.BlockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(ciphertext, ciphertext)
// If the original plaintext lengths are not a multiple of the block
// size, padding would have to be added when encrypting, which would be
// removed at this point. For an example, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's
// critical to note that ciphertexts must be authenticated (i.e. by
// using crypto/hmac) before being decrypted in order to avoid creating
// a padding oracle.
fmt.Printf("%s\n", ciphertext)
Вывод:
exampleplaintext
функция NewCBCEncrypter
func NewCBCEncrypter(b Block, iv []byte) BlockMode
NewCBCEncrypter возвращает BlockMode, который шифрует в режиме шифра с цепочкой блоков, используя заданный Block. Длина iv должна быть такой же, как размер блока Block.
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("exampleplaintext")
// CBC mode works on blocks so plaintexts may need to be padded to the
// next whole block. For an example of such padding, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
// assume that the plaintext is already of the correct length.
if len(plaintext)%aes.BlockSize != 0 {
panic("plaintext is not a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
fmt.Printf("%x\n", ciphertext)
тип Stream
Stream представляет собой потоковый шифр.
type Stream interface {
// XORKeyStream XORs each byte in the given slice with a byte from the
// cipher's key stream. Dst and src must overlap entirely or not at all.
//
// If len(dst) < len(src), XORKeyStream should panic. It is acceptable
// to pass a dst bigger than src, and in that case, XORKeyStream will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to XORKeyStream behave as if the concatenation of
// the src buffers was passed in a single run. That is, Stream
// maintains state and does not reset at each XORKeyStream call.
XORKeyStream(dst, src []byte)
} функция NewCFBDecrypter
func NewCFBDecrypter(block Block, iv []byte) Stream
NewCFBDecrypter возвращает Stream, который расшифровывает с режимом обратной связи шифра, используя заданный Block. iv должен иметь такой же размер, как размер блока Block.
Устарело: Режим CFB не является аутентифицированным, что, как правило, позволяет активным атакам манипулировать и восстанавливать открытый текст. Рекомендуется использовать режимы AEAD вместо этого. Стандартная реализация CFB в библиотеке также не оптимизирована и не валидирована как часть модуля FIPS 140-3. Если требуется неаутентифицированный режим Stream, используйте NewCTR вместо этого.
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
// XORKeyStream can work in-place if the two arguments are the same.
stream.XORKeyStream(ciphertext, ciphertext)
fmt.Printf("%s", ciphertext)
Вывод:
some plaintext
функция NewCFBEncrypter
func NewCFBEncrypter(block Block, iv []byte) Stream
NewCFBEncrypter возвращает Stream, который шифрует с режимом обратной связи шифра, используя заданный Block. iv должен иметь такой же размер, как размер блока Block.
Устарело: Режим CFB не является аутентифицированным, что, как правило, позволяет активным атакам манипулировать и восстанавливать открытый текст. Рекомендуется использовать режимы AEAD вместо этого. Стандартная реализация CFB в библиотеке также не оптимизирована и не валидирована как часть модуля FIPS 140-3. Если требуется неаутентифицированный режим Stream, используйте NewCTR вместо этого.
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
fmt.Printf("%x\n", ciphertext)
функция NewCTR
func NewCTR(block Block, iv []byte) Stream
NewCTR возвращает Stream, который шифрует/расшифровывает, используя заданный Block в режиме счетчика. Длина iv должна быть такой же, как размер блока Block.
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
// CTR mode is the same for both encryption and decryption, so we can
// also decrypt that ciphertext with NewCTR.
plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewCTR(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
fmt.Printf("%s\n", plaintext2)
Вывод:
some plaintext
функция NewOFB
func NewOFB(b Block, iv []byte) Stream
NewOFB возвращает Stream, который шифрует или расшифровывает, используя блочный шифр b в режиме обратной связи выхода. Длина инициализирующего вектора iv должна быть равна размеру блока b.
Устарело: Режим OFB не является аутентифицированным, что, как правило, позволяет активным атакам манипулировать и восстанавливать открытый текст. Рекомендуется использовать режимы AEAD вместо этого. Стандартная реализация OFB в библиотеке также не оптимизирована и не валидирована как часть модуля FIPS 140-3. Если требуется неаутентифицированный режим Stream, используйте NewCTR вместо этого.
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
plaintext := []byte("some plaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
// It's important to remember that ciphertexts must be authenticated
// (i.e. by using crypto/hmac) as well as being encrypted in order to
// be secure.
// OFB mode is the same for both encryption and decryption, so we can
// also decrypt that ciphertext with NewOFB.
plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewOFB(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
fmt.Printf("%s\n", plaintext2)
Вывод:
some plaintext
тип StreamReader
StreamReader обертывает Stream в io.Reader. Он вызывает XORKeyStream для обработки каждого фрагмента данных, который проходит через него.
type StreamReader struct {
S Stream
R io.Reader
}
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
encrypted, _ := hex.DecodeString("cf0495cc6f75dafc23948538e79904a9")
bReader := bytes.NewReader(encrypted)
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// If the key is unique for each ciphertext, then it's ok to use a zero
// IV.
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
reader := &cipher.StreamReader{S: stream, R: bReader}
// Copy the input to the output stream, decrypting as we go.
if _, err := io.Copy(os.Stdout, reader); err != nil {
panic(err)
}
// Note that this example is simplistic in that it omits any
// authentication of the encrypted data. If you were actually to use
// StreamReader in this manner, an attacker could flip arbitrary bits in
// the output.
Вывод:
some secret text
функция (StreamReader) Read
func (r StreamReader) Read(dst []byte) (n int, err error)
тип StreamWriter
StreamWriter обертывает Stream в io.Writer. Он вызывает XORKeyStream для обработки каждого фрагмента данных, который проходит через него. Если какой-либо вызов StreamWriter.Write возвращает короткий результат, то StreamWriter не синхронизирован и его нужно отбросить. У StreamWriter нет внутренней буферизации; StreamWriter.Close не нужно вызывать для сброса данных записи.
type StreamWriter struct {
S Stream
W io.Writer
Err error // unused
}
Пример
Код:
// Load your secret key from a safe place and reuse it across multiple
// NewCipher calls. (Obviously don't use this example key for anything
// real.) If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
key, _ := hex.DecodeString("6368616e676520746869732070617373")
bReader := bytes.NewReader([]byte("some secret text"))
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// If the key is unique for each ciphertext, then it's ok to use a zero
// IV.
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
var out bytes.Buffer
writer := &cipher.StreamWriter{S: stream, W: &out}
// Copy the input to the output buffer, encrypting as we go.
if _, err := io.Copy(writer, bReader); err != nil {
panic(err)
}
// Note that this example is simplistic in that it omits any
// authentication of the encrypted data. If you were actually to use
// StreamReader in this manner, an attacker could flip arbitrary bits in
// the decrypted result.
fmt.Printf("%x\n", out.Bytes())
Вывод:
cf0495cc6f75dafc23948538e79904a9
функция (StreamWriter) Close
func (w StreamWriter) Close() error
Закрывает лежащий в основе Writer и возвращает его значение Close, если Writer также является io.Closer. В противном случае возвращает nil.
func (StreamWriter) Write
func (w StreamWriter) Write(src []byte) (n int, err error)
© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/crypto/cipher/