非常教程

Go参考手册

加密 | crypto

crypto/cipher

  • import "crypto/cipher"
  • 概述
  • 索引
  • 示例

概述

加密包(Package cipher)实现了标准块密码模式,可以围绕低级块密码实现。请参阅http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html和NIST Special Publication

800-38A。

索引

  • 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

NewCB​​CDecrypter 返回一个 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

NewCB​​CEncrypter 返回一个 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)
Go

Go 是一种编译型语言,它结合了解释型语言的游刃有余,动态类型语言的开发效率,以及静态类型的安全性。它也打算成为现代的,支持网络与多核计算的语言。要满足这些目标,需要解决一些语言上的问题:一个富有表达能力但轻量级的类型系统,并发与垃圾回收机制,严格的依赖规范等等。这些无法通过库或工具解决好,因此Go也就应运而生了。

主页 https://golang.org/
源码 https://go.googlesource.com/go
发布版本 1.9.2

Go目录

1.档案 | archive
2.缓冲区 | bufio
3.内置 | builtin
4.字节 | bytes
5.压缩 | compress
6.容器 | container
7.上下文 | context
8.加密 | crypto
9.数据库 | database
10.调试 | debug
11.编码 | encoding
12.错误 | errors
13. expvar
14.flag
15. fmt
16. go
17.散列 | hash
18.html
19.图像 | image
20.索引 | index
21.io
22.日志 | log
23.数学 | math
24. math/big
25.math/bits
26.math/cmplx
27.math/rand
28.拟态 | mime
29.net
30.net/http
31. net/mail
32. net/rpc
33.net/smtp
34. net/textproto
35. net/url
36.os
37.路径 | path
38.插件 | plugin
39.反射 | reflect
40.正则表达式 | regexp
41.运行时 | runtime
42.排序算法 | sort
43.转换 | strconv
44.字符串 | strings
45.同步 | sync
46.系统调用 | syscall
47.测试 | testing
48.文本 | text
49.时间戳 | time
50.unicode
51.不安全性 | unsafe
52.Go 语言数据类型
53.Go 语言基础语法
54.Go 语言结构
55.Go 语言 select 语句
56.Go 语言 switch 语句
57.Go 语言 if 语句嵌套
58.Go 语言 if…else 语句
59.Go 语言 if 语句
60.Go 语言运算符
61.Go 语言常量
62.Go 语言函数闭包
63.Go 语言函数作为实参
64.Go 语言函数引用传递值
65.Go 语言函数值传递值
66.Go 语言函数
67.Go 语言 goto 语句
68.Go 语言 continue 语句
69.Go 语言 break 语句
70.Go 语言循环嵌套
71.Go 语言 for 循环
72.Go 语言结构体
73.Go 语言指针作为函数参数
74.Go 语言指向指针的指针
75.Go 语言指针数组
76.Go 语言指针
77.Go 语言向函数传递数组
78.Go 语言多维数组
79.Go 语言变量作用域
80.Go 语言函数方法
81.Go 错误处理
82.Go 语言接口
83.Go 语言类型转换
84.Go 语言递归函数
85.Go 语言Map(集合)
86.Go 语言范围(Range)
87.Go 语言切片(Slice)
88.Go 并发
89.Go fmt.Sprintf 格式化字符串