Go 语言

Go 语言教程 Go 语言环境安装 Go 语言结构 Go 语言基础语法 Go 语言数据类型 Go 语言变量 Go 语言常量 Go 语言运算符 Go 语言条件语句 Go 语言 if 语句 Go 语言 if...else 语句 Go 语言 if 语句嵌套 Go 语言 switch 语句 Go 语言 select 语句 Go 语言循环语句 Go 语言 for 循环 Go 语言循环嵌套 Go 语言 break 语句 Go 语言 continue 语句 Go 语言 goto 语句 Go 语言函数 Go 语言函数值传递值 Go 语言函数引用传递值 Go 语言函数作为值 Go 语言函数闭包 Go 语言函数方法 Go 语言变量作用域 Go 语言数组 Go 语言多维数组 Go 语言向函数传递数组 Go 语言指针 Go 语言指针数组 Go 语言指向指针的指针 Go 语言指针作为函数参数 Go 语言结构体 Go 语言切片(Slice) Go 语言范围(Range) Go 语言Map(集合) Go 语言递归函数 Go 语言类型转换 Go 语言接口 Go 错误处理 Go 语言开发工具Go 语言标准库

Go 语言标准库


package cipher

import "crypto/cipher"

cipher包实现了多个标准的用于包装底层块加密算法的加密算法实现。

参见http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html和NIST Special Publication 800-38A。

Go语言标准库 >>


  • type Block
  • type BlockMode
  • type Stream
  • type StreamReader
  • type StreamWriter
  • type AEAD
  • Examples

    Go语言标准库 >>


  • NewCBCDecrypter
  • NewCBCEncrypter
  • NewCFBDecrypter
  • NewCFBEncrypter
  • NewCTR
  • NewOFB
  • StreamReader
  • StreamWriter
  • type Block

    type Block interface {
        // 返回加密字节块的大小
        BlockSize() int
        // 加密src的第一块数据并写入dst,src和dst可指向同一内存地址
        Encrypt(dst, src []byte)
        // 解密src的第一块数据并写入dst,src和dst可指向同一内存地址
        Decrypt(dst, src []byte)
    }

    Block接口代表一个使用特定密钥的底层块加/解密器。它提供了加密和解密独立数据块的能力。

    type BlockMode

    type BlockMode interface {
        // 返回加密字节块的大小
        BlockSize() int
        // 加密或解密连续的数据块,src的尺寸必须是块大小的整数倍,src和dst可指向同一内存地址
        CryptBlocks(dst, src []byte)
    }

    BlockMode接口代表一个工作在块模式(如CBC、ECB等)的加/解密器。

    func NewCBCEncrypter

    func NewCBCEncrypter(b Block, iv []byte) BlockMode

    返回一个密码分组链接模式的、底层用b加密的BlockMode接口,初始向量iv的长度必须等于b的块尺寸。

    Example
    key := []byte("example key 1234")
    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)
    

    func NewCBCDecrypter

    func NewCBCDecrypter(b Block, iv []byte) BlockMode

    返回一个密码分组链接模式的、底层用b解密的BlockMode接口,初始向量iv必须和加密时使用的iv相同。

    Example
    key := []byte("example key 1234")
    ciphertext, _ := hex.DecodeString("f363f3ccdcb12bb883abf484ba77d9cd7d32b5baecb3d4b1b3e0e4beffdb3ded")
    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)

    Output:

    exampleplaintext
    

    type Stream

    type Stream interface {
        // 从加密器的key流和src中依次取出字节二者xor后写入dst,src和dst可指向同一内存地址
        XORKeyStream(dst, src []byte)
    }

    Stream接口代表一个流模式的加/解密器。

    func NewCFBEncrypter

    func NewCFBEncrypter(block Block, iv []byte) Stream

    返回一个密码反馈模式的、底层用block加密的Stream接口,初始向量iv的长度必须等于block的块尺寸。

    Example
    key := []byte("example key 1234")
    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.
    

    func NewCFBDecrypter

    func NewCFBDecrypter(block Block, iv []byte) Stream

    返回一个密码反馈模式的、底层用block解密的Stream接口,初始向量iv必须和加密时使用的iv相同。

    Example
    key := []byte("example key 1234")
    ciphertext, _ := hex.DecodeString("22277966616d9bc47177bd02603d08c9a67d5380d0fe8cf3b44438dff7b9")
    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)

    Output:

    some plaintext
    

    func NewOFB

    func NewOFB(b Block, iv []byte) Stream

    返回一个输出反馈模式的、底层采用b生成key流的Stream接口,初始向量iv的长度必须等于b的块尺寸。

    Example
    key := []byte("example key 1234")
    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)

    Output:

    some plaintext
    

    func NewCTR

    func NewCTR(block Block, iv []byte) Stream

    返回一个计数器模式的、底层采用block生成key流的Stream接口,初始向量iv的长度必须等于block的块尺寸。

    Example
    key := []byte("example key 1234")
    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)

    Output:

    some plaintext
    

    type StreamReader

    type StreamReader struct {
        S   Stream
        R   io.Reader
    }

    将一个Stream与一个io.Reader接口关联起来,Read方法会调用XORKeyStream方法来处理获取的所有切片。

    Example
    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)
    }
    // 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[:])
    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}
    // Copy the input file to the output file, decrypting as we go.
    if _, err := io.Copy(outFile, reader); err != nil {
        panic(err)
    }
    // Note that this example is simplistic in that it omits any
    // authentication of the encrypted data. It you were actually to use
    // StreamReader in this manner, an attacker could flip arbitrary bits in
    // the output.
    

    func (StreamReader) Read

    func (r StreamReader) Read(dst []byte) (n int, err error)

    type StreamWriter

    type StreamWriter struct {
        S   Stream
        W   io.Writer
        Err error // unused
    }

    将一个Stream与一个io.Writer接口关联起来,Write方法会调用XORKeyStream方法来处理提供的所有切片。如果Write方法返回的n小于提供的切片的长度,则表示StreamWriter不同步,必须丢弃。StreamWriter没有内建的缓存,不需要调用Close方法去清空缓存。

    Example
    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)
    }
    // 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[:])
    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}
    // Copy the input file to the output file, encrypting as we go.
    if _, err := io.Copy(writer, inFile); err != nil {
        panic(err)
    }
    // Note that this example is simplistic in that it omits any
    // authentication of the encrypted data. It you were actually to use
    // StreamReader in this manner, an attacker could flip arbitrary bits in
    // the decrypted result.
    

    func (StreamWriter) Write

    func (w StreamWriter) Write(src []byte) (n int, err error)

    func (StreamWriter) Close

    func (w StreamWriter) Close() error

    如果w.W字段实现了io.Closer接口,本方法会调用其Close方法并返回该方法的返回值;否则不做操作返回nil。

    type AEAD

    type AEAD interface {
        // 返回提供给Seal和Open方法的随机数nonce的字节长度
        NonceSize() int
        // 返回原始文本和加密文本的最大长度差异
        Overhead() int
        // 加密并认证明文,认证附加的data,将结果添加到dst,返回更新后的切片。
        // nonce的长度必须是NonceSize()字节,且对给定的key和时间都是独一无二的。
        // plaintext和dst可以是同一个切片,也可以不同。
        Seal(dst, nonce, plaintext, data []byte) []byte
        // 解密密文并认证,认证附加的data,如果认证成功,将明文添加到dst,返回更新后的切片。
        // nonce的长度必须是NonceSize()字节,nonce和data都必须和加密时使用的相同。
        // ciphertext和dst可以是同一个切片,也可以不同。
        Open(dst, nonce, ciphertext, data []byte) ([]byte, error)
    }

    AEAD接口是一种提供了使用关联数据进行认证加密的功能的加密模式。

    func NewGCM

    func NewGCM(cipher Block) (AEAD, error)

    函数用迦洛瓦计数器模式包装提供的128位Block接口,并返回AEAD接口。