crypto/cipher
加密包
import "crypto/cipher"
- 概述
- 索引
- 示例
概述
加密包(Package cipher)实现了标准块密码模式,可以围绕低级块密码实现。请参阅http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html和NIST Special Publication
索引
- type AEAD
- func NewGCM(cipher Block) (AEAD, error)
- func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error)
- type Block
- type BlockMode
- func NewCBCDecrypter(b Block, iv []byte) BlockMode
- func NewCBCEncrypter(b Block, iv []byte) BlockMode
- type Stream
- func NewCFBDecrypter(block Block, iv []byte) Stream
- func NewCFBEncrypter(block Block, iv []byte) Stream
- func NewCTR(block Block, iv []byte) Stream
- func NewOFB(b Block, iv []byte) Stream
- type StreamReader
- func (r StreamReader) Read(dst []byte) (n int, err error)
- type StreamWriter
- func (w StreamWriter) Close() error
- func (w StreamWriter) Write(src []byte) (n int, err error)
示例
NewCBCDecrypter NewCBCEncrypter NewCFBDecrypter NewCFBEncrypter NewCTR NewGCM (Decrypt) NewGCM (Encrypt) NewOFB StreamReader StreamWriter
文件包
cbc.go cfb.go cipher.go ctr.go gcm.go io.go ofb.go xor.go
type AEAD(查看源代码)
AEAD是一种密码模式,提供带有关联数据的认证加密。有关该方法的说明,请参阅
https://en.wikipedia.org/wiki/Authenticated_encryption
type AEAD interface {
// NonceSize返回必须传递给Seal的随机数的大小
// and Open.
NonceSize() int
// Overhead返回以下两者间的最大差异
// plaintext 和 its ciphertext.
Overhead() int
// 密封加密和验证明文,验证
// 附加数据并将结果附加到dst,并返回更新
// slice。 nonce必须是NonceSize()字节长且对所有人都是唯一的
// time, 对于给定的密钥。
//
// 明文和dst可能完全或根本不是别名。 重用
// 明文的加密输出存储,使用 plaintext[:0]作为dst。
Seal(dst, nonce, plaintext, additionalData []byte) []byte
// 打开解密并验证密文,验证密文
// 额外的数据,如果成功的话,附加结果明文
// 到dst,返回更新的片。 nonce必须是NonceSize()
// 字节长,它和附加数据必须匹配
// 值传递给Seal。
//
// 密文和dst可以完全混淆或根本不混淆。 重用
// 密文的解密输出存储,使用ciphertext [:0]作为dst。
//
// 即使该功能失败,dst的内容,直到其容量,
// 可能会被覆盖。
Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error)
}
func NewGCM(查看源代码)
func NewGCM(cipher Block) (AEAD, error)
NewGCM 返回给定的128-bit,以伽罗华计数器模式(Galois Counter Mode包装的分组密码,其标准随机数长度。
一般来说,这种 GCM 实施的 GHASH 操作不是一个固定时间。当硬件支持 AES 的系统上由 aes.NewCipher 创建底层 Block 时,则是个例外。有关详细信息,请参阅 crypto/aes 软件包文档。
示例(Decrypt)
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
)
func main() {
// 关键参数应该是AES密钥,16或32个字节
// 选择 AES-128 或 AES-256。
key := []byte("AES256Key-32Characters1234567890")
ciphertext, _ := hex.DecodeString("1019aa66cd7c024f9efd0038899dae1973ee69427f5a6579eba292ffe1b5a260")
nonce, _ := hex.DecodeString("37b8e8a308c354048d245f6d")
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)
}
示例(Encrypt)
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
)
func main() {
// 关键参数应该是AES密钥,16或32个字节
// 选择AES-128或AES-256。
key := []byte("AES256Key-32Characters1234567890")
plaintext := []byte("exampleplaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
// 由于存在重复的风险,请勿使用给定密钥使用超过2^32个随机值。
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)
}
func NewGCMWithNonceSize(查看源代码)
func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error)
NewGCMWithNonceSize 返回给定的 128 位,以 Galois 计数器模式包装的分组密码,它接受给定长度的随机数。
如果您需要与使用非标准随机数长度的现有密码系统兼容,请仅使用此功能。所有其他用户都应该使用 NewGCM,它更快,更耐滥用。
type Block(查看源代码)
块表示使用给定密钥的分组密码的实现。它提供了加密或解密各个块的功能。模式实现将该能力扩展到块流。
type Block interface {
// BlockSize返回密码的块大小。
BlockSize() int
// 加密将src中的第一个块加密到dst中。
// Dst和src可能指向相同的内存。
Encrypt(dst, src []byte)
// 解密将src中的第一个块解密为dst。
// Dst和src可能指向相同的内存。
Decrypt(dst, src []byte)
}
type BlockMode(查看源代码)
BlockMode表示以基于块的模式运行的分组密码(CBC,ECB等)。
type BlockMode interface {
// BlockSize返回模式的块大小。
BlockSize() int
// CryptBlocks加密或解密一些块。 The length of
// src必须是块大小的倍数。 Dst和src可能指向
// 相同的内存。
CryptBlocks(dst, src []byte)
}
func NewCBCDecrypter(查看源代码)
func NewCBCDecrypter(b Block, iv []byte) BlockMode
NewCBCDecrypter 返回一个 BlockMode,它使用给定的Block 以密码块链接模式解密。iv 的长度必须与 Block 的块大小相同,并且必须与用于加密数据的 iv 相匹配。
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
)
func main() {
key := []byte("example key 1234")
ciphertext, _ := hex.DecodeString("f363f3ccdcb12bb883abf484ba77d9cd7d32b5baecb3d4b1b3e0e4beffdb3ded")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// IV需要独特,但不安全。 所以这很常见
// 将其包括在密文的开头。
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
// CBC模式总是在整个模块中工作。
if len(ciphertext)%aes.BlockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// 如果两个参数相同,CryptBlocks可以在原地工作。
mode.CryptBlocks(ciphertext, ciphertext)
// 如果原始plaintext长度不是块的倍数
// 大小,填充将不得不在加密时添加,这将是
// 在这一点删除。 有关示例,请参阅
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. 然而,
// 至关重要的是要注意密文必须被认证(即通过
// 使用crypto/hmac)解密之前,以避免创建
// 一个填充oracle。
fmt.Printf("%s\n", ciphertext)
}
func NewCBCEncrypter(查看源代码)
func NewCBCEncrypter(b Block, iv []byte) BlockMode
NewCBCEncrypter 返回一个 BlockMode,它使用给定的 Block 以密码块链接模式加密。iv 的长度必须与块的块大小相同。
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
)
func main() {
key := []byte("example key 1234")
plaintext := []byte("exampleplaintext")
// CBC模式在块上工作,所以明文可能需要填充到块
// 下一个整块。 有关这种填充的示例,请参阅
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. 这里,我们将
// 假定 plaintext 已经是正确的长度。
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)
}
// IV需要独特,但不安全。 所以这很常见
// 将其包括在密文的开头。
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)
// 记住密文必须经过认证是很重要的
// (即通过使用crypto/hmac)以及为了加密而被加密
// 保持secure。
fmt.Printf("%x\n", ciphertext)
}
type Stream(查看源代码)
Stream表示流密码。
type Stream interface {
// XORKeyStream将给定片中的每个字节与来自该字节的一个字节异或
// 密码的密钥流。 Dst和src可能指向相同的内存。
// 如果len(dst)<len(src),XORKeyStream应该是恐慌的。 它是可以接受的
// 传递比src更大的dst,在那种情况下,XORKeyStream会
// 只更新dst[:len(src)]并且不会触及dst的其余部分。
XORKeyStream(dst, src []byte)
}
func NewCFBDecrypter(查看源代码)
func NewCFBDecrypter(block Block, iv []byte) Stream
新的 CFB 解密器使用给定的块返回一个使用密码反馈模式解密的 Stream。iv 的长度必须与块的块大小相同。
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
)
func main() {
key := []byte("example key 1234")
ciphertext, _ := hex.DecodeString("22277966616d9bc47177bd02603d08c9a67d5380d0fe8cf3b44438dff7b9")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// IV需要独特,但不安全。 所以这很常见
// 将其包括在密文的开头。
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
// 如果两个参数相同,XORKeyStream可以在原地工作。
stream.XORKeyStream(ciphertext, ciphertext)
fmt.Printf("%s", ciphertext)
}
func NewCFBEncrypter(查看源代码)
func NewCFBEncrypter(block Block, iv []byte) Stream
NewCFBEncrypter 使用给定的 Block 返回一个使用密码反馈模式加密的 Stream。iv 的长度必须与块的块大小相同。
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
func main() {
key := []byte("example key 1234")
plaintext := []byte("some plaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// IV需要独特,但不安全。 所以这很常见
// 将其包括在密文的开头。
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)
// 记住密文必须经过认证是很重要的
// (即通过使用crypto/hmac)以及为了加密而被加密
// 保持secure。
}
func NewCTR(查看源代码)
func NewCTR(block Block, iv []byte) Stream
NewCTR 返回一个 Stream,它使用计数器模式下的给定 Block加密/解密。iv 的长度必须与块的块大小相同。
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
)
func main() {
key := []byte("example key 1234")
plaintext := []byte("some plaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// IV需要独特,但不安全。 所以这很常见
// 将其包括在密文的开头。
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)
// 记住密文必须经过认证是很重要的
// (即通过使用crypto/hmac)以及为了加密而被加密
// 保持secure。
// CTR模式对于加密和解密都是一样的,所以我们可以
// 也用NewCTR解密该密文。
plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewCTR(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
fmt.Printf("%s\n", plaintext2)
}
func NewOFB(查看源代码)
func NewOFB(b Block, iv []byte) Stream
NewOFB 返回一个在输出反馈模式下使用分组密码 b 进行加密或解密的 Stream。初始化矢量 iv 的长度必须等于 b 的块大小。
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
)
func main() {
key := []byte("example key 1234")
plaintext := []byte("some plaintext")
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// IV需要独特,但不安全。 所以这很常见
// 将其包括在密文的开头。
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)
// 记住密文必须经过认证是很重要的
// (即通过使用crypto/hmac)以及为了加密而被加密
// 保持secure。
// OFB模式对加密和解密都是一样的,所以我们可以
// 也使用 NewOFB 解密该密文。
plaintext2 := make([]byte, len(plaintext))
stream = cipher.NewOFB(block, iv)
stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
fmt.Printf("%s\n", plaintext2)
}
type StreamReader(查看源代码)
StreamReader 将 Stream 封装到 io.Reader 中。它调用 XORKeyStream 来处理通过的每一片数据。
type StreamReader struct {
S Stream
R io.Reader
}
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"io"
"os"
)
func main() {
key := []byte("example key 1234")
inFile, err := os.Open("encrypted-file")
if err != nil {
panic(err)
}
defer inFile.Close()
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// 如果密钥对于每个密文都是唯一的,那么可以使用零
// IV.
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
outFile, err := os.OpenFile("decrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
panic(err)
}
defer outFile.Close()
reader := &cipher.StreamReader{S: stream, R: inFile}
// 将输入文件复制到输出文件,随着我们的解密。
if _, err := io.Copy(outFile, reader err != nil {
panic(err)
}
// 请注意,这个例子是简单的,因为它省略了
// 加密数据的认证。 如果你真的使用
// StreamReader以这种方式,攻击者可以翻转任意位
// 输出。
}
func (StreamReader) Read(查看源代码)
func (r StreamReader) Read(dst []byte) (n int, err error)
type StreamWriter(查看源代码)
StreamWriter 将 Stream 封装到 io.Writer 中。它调用 XORKeyStream 来处理通过的每一片数据。如果任何写入调用返回短,那么 StreamWriter 不同步并且必须被丢弃。StreamWriter 没有内部缓冲;不需要调用 Close 来刷新写入数据。
type StreamWriter struct {
S Stream
W io.Writer
Err error // unused
}
示例
package main
import (
"crypto/aes"
"crypto/cipher"
"io"
"os"
)
func main() {
key := []byte("example key 1234")
inFile, err := os.Open("plaintext-file")
if err != nil {
panic(err)
}
defer inFile.Close()
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
// 如果密钥对于每个密文都是唯一的,那么可以使用zero
// IV.
var iv [aes.BlockSize]byte
stream := cipher.NewOFB(block, iv[:])
outFile, err := os.OpenFile("encrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
panic(err)
}
defer outFile.Close()
writer := &cipher.StreamWriter{S: stream, W: outFile}
// 将输入文件复制到输出文件,并随时加密。
if _, err := io.Copy(writer, inFile err != nil {
panic(err)
}
// 请注意,这个例子是简单的,因为它省略了
// 加密数据的认证。 如果你真的使用
// StreamReader以这种方式,攻击者可以翻转任意位
// 解密的结果。
}
func (StreamWriter) Close(查看源代码)
func (w StreamWriter) Close() error
Close 关闭底层 Writer 并返回其 Close 返回值,如果 Writer 也是 io.Closer。否则它返回零。
func (StreamWriter) Write(查看源代码)
func (w StreamWriter) Write(src []byte) (n int, err error)