blob: 1cfa982df4ba4d7de1fa2db172078002ed64a6dc [file] [log] [blame]
Colin Cross7bb052a2015-02-03 12:59:37 -08001// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package cipher_test
6
7import (
8 "crypto/aes"
9 "crypto/cipher"
10 "crypto/rand"
11 "encoding/hex"
12 "fmt"
13 "io"
14 "os"
15)
16
17func ExampleNewCBCDecrypter() {
18 key := []byte("example key 1234")
19 ciphertext, _ := hex.DecodeString("f363f3ccdcb12bb883abf484ba77d9cd7d32b5baecb3d4b1b3e0e4beffdb3ded")
20
21 block, err := aes.NewCipher(key)
22 if err != nil {
23 panic(err)
24 }
25
26 // The IV needs to be unique, but not secure. Therefore it's common to
27 // include it at the beginning of the ciphertext.
28 if len(ciphertext) < aes.BlockSize {
29 panic("ciphertext too short")
30 }
31 iv := ciphertext[:aes.BlockSize]
32 ciphertext = ciphertext[aes.BlockSize:]
33
34 // CBC mode always works in whole blocks.
35 if len(ciphertext)%aes.BlockSize != 0 {
36 panic("ciphertext is not a multiple of the block size")
37 }
38
39 mode := cipher.NewCBCDecrypter(block, iv)
40
41 // CryptBlocks can work in-place if the two arguments are the same.
42 mode.CryptBlocks(ciphertext, ciphertext)
43
44 // If the original plaintext lengths are not a multiple of the block
45 // size, padding would have to be added when encrypting, which would be
46 // removed at this point. For an example, see
47 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's
48 // critical to note that ciphertexts must be authenticated (i.e. by
49 // using crypto/hmac) before being decrypted in order to avoid creating
50 // a padding oracle.
51
52 fmt.Printf("%s\n", ciphertext)
53 // Output: exampleplaintext
54}
55
56func ExampleNewCBCEncrypter() {
57 key := []byte("example key 1234")
58 plaintext := []byte("exampleplaintext")
59
60 // CBC mode works on blocks so plaintexts may need to be padded to the
61 // next whole block. For an example of such padding, see
62 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
63 // assume that the plaintext is already of the correct length.
64 if len(plaintext)%aes.BlockSize != 0 {
65 panic("plaintext is not a multiple of the block size")
66 }
67
68 block, err := aes.NewCipher(key)
69 if err != nil {
70 panic(err)
71 }
72
73 // The IV needs to be unique, but not secure. Therefore it's common to
74 // include it at the beginning of the ciphertext.
75 ciphertext := make([]byte, aes.BlockSize+len(plaintext))
76 iv := ciphertext[:aes.BlockSize]
77 if _, err := io.ReadFull(rand.Reader, iv); err != nil {
78 panic(err)
79 }
80
81 mode := cipher.NewCBCEncrypter(block, iv)
82 mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
83
84 // It's important to remember that ciphertexts must be authenticated
85 // (i.e. by using crypto/hmac) as well as being encrypted in order to
86 // be secure.
87
88 fmt.Printf("%x\n", ciphertext)
89}
90
91func ExampleNewCFBDecrypter() {
92 key := []byte("example key 1234")
93 ciphertext, _ := hex.DecodeString("22277966616d9bc47177bd02603d08c9a67d5380d0fe8cf3b44438dff7b9")
94
95 block, err := aes.NewCipher(key)
96 if err != nil {
97 panic(err)
98 }
99
100 // The IV needs to be unique, but not secure. Therefore it's common to
101 // include it at the beginning of the ciphertext.
102 if len(ciphertext) < aes.BlockSize {
103 panic("ciphertext too short")
104 }
105 iv := ciphertext[:aes.BlockSize]
106 ciphertext = ciphertext[aes.BlockSize:]
107
108 stream := cipher.NewCFBDecrypter(block, iv)
109
110 // XORKeyStream can work in-place if the two arguments are the same.
111 stream.XORKeyStream(ciphertext, ciphertext)
112 fmt.Printf("%s", ciphertext)
113 // Output: some plaintext
114}
115
116func ExampleNewCFBEncrypter() {
117 key := []byte("example key 1234")
118 plaintext := []byte("some plaintext")
119
120 block, err := aes.NewCipher(key)
121 if err != nil {
122 panic(err)
123 }
124
125 // The IV needs to be unique, but not secure. Therefore it's common to
126 // include it at the beginning of the ciphertext.
127 ciphertext := make([]byte, aes.BlockSize+len(plaintext))
128 iv := ciphertext[:aes.BlockSize]
129 if _, err := io.ReadFull(rand.Reader, iv); err != nil {
130 panic(err)
131 }
132
133 stream := cipher.NewCFBEncrypter(block, iv)
134 stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
135
136 // It's important to remember that ciphertexts must be authenticated
137 // (i.e. by using crypto/hmac) as well as being encrypted in order to
138 // be secure.
139}
140
141func ExampleNewCTR() {
142 key := []byte("example key 1234")
143 plaintext := []byte("some plaintext")
144
145 block, err := aes.NewCipher(key)
146 if err != nil {
147 panic(err)
148 }
149
150 // The IV needs to be unique, but not secure. Therefore it's common to
151 // include it at the beginning of the ciphertext.
152 ciphertext := make([]byte, aes.BlockSize+len(plaintext))
153 iv := ciphertext[:aes.BlockSize]
154 if _, err := io.ReadFull(rand.Reader, iv); err != nil {
155 panic(err)
156 }
157
158 stream := cipher.NewCTR(block, iv)
159 stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
160
161 // It's important to remember that ciphertexts must be authenticated
162 // (i.e. by using crypto/hmac) as well as being encrypted in order to
163 // be secure.
164
165 // CTR mode is the same for both encryption and decryption, so we can
166 // also decrypt that ciphertext with NewCTR.
167
168 plaintext2 := make([]byte, len(plaintext))
169 stream = cipher.NewCTR(block, iv)
170 stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
171
172 fmt.Printf("%s\n", plaintext2)
173 // Output: some plaintext
174}
175
176func ExampleNewOFB() {
177 key := []byte("example key 1234")
178 plaintext := []byte("some plaintext")
179
180 block, err := aes.NewCipher(key)
181 if err != nil {
182 panic(err)
183 }
184
185 // The IV needs to be unique, but not secure. Therefore it's common to
186 // include it at the beginning of the ciphertext.
187 ciphertext := make([]byte, aes.BlockSize+len(plaintext))
188 iv := ciphertext[:aes.BlockSize]
189 if _, err := io.ReadFull(rand.Reader, iv); err != nil {
190 panic(err)
191 }
192
193 stream := cipher.NewOFB(block, iv)
194 stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
195
196 // It's important to remember that ciphertexts must be authenticated
197 // (i.e. by using crypto/hmac) as well as being encrypted in order to
198 // be secure.
199
200 // OFB mode is the same for both encryption and decryption, so we can
201 // also decrypt that ciphertext with NewOFB.
202
203 plaintext2 := make([]byte, len(plaintext))
204 stream = cipher.NewOFB(block, iv)
205 stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
206
207 fmt.Printf("%s\n", plaintext2)
208 // Output: some plaintext
209}
210
211func ExampleStreamReader() {
212 key := []byte("example key 1234")
213
214 inFile, err := os.Open("encrypted-file")
215 if err != nil {
216 panic(err)
217 }
218 defer inFile.Close()
219
220 block, err := aes.NewCipher(key)
221 if err != nil {
222 panic(err)
223 }
224
225 // If the key is unique for each ciphertext, then it's ok to use a zero
226 // IV.
227 var iv [aes.BlockSize]byte
228 stream := cipher.NewOFB(block, iv[:])
229
230 outFile, err := os.OpenFile("decrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
231 if err != nil {
232 panic(err)
233 }
234 defer outFile.Close()
235
236 reader := &cipher.StreamReader{S: stream, R: inFile}
237 // Copy the input file to the output file, decrypting as we go.
238 if _, err := io.Copy(outFile, reader); err != nil {
239 panic(err)
240 }
241
242 // Note that this example is simplistic in that it omits any
243 // authentication of the encrypted data. If you were actually to use
244 // StreamReader in this manner, an attacker could flip arbitrary bits in
245 // the output.
246}
247
248func ExampleStreamWriter() {
249 key := []byte("example key 1234")
250
251 inFile, err := os.Open("plaintext-file")
252 if err != nil {
253 panic(err)
254 }
255 defer inFile.Close()
256
257 block, err := aes.NewCipher(key)
258 if err != nil {
259 panic(err)
260 }
261
262 // If the key is unique for each ciphertext, then it's ok to use a zero
263 // IV.
264 var iv [aes.BlockSize]byte
265 stream := cipher.NewOFB(block, iv[:])
266
267 outFile, err := os.OpenFile("encrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
268 if err != nil {
269 panic(err)
270 }
271 defer outFile.Close()
272
273 writer := &cipher.StreamWriter{S: stream, W: outFile}
274 // Copy the input file to the output file, encrypting as we go.
275 if _, err := io.Copy(writer, inFile); err != nil {
276 panic(err)
277 }
278
279 // Note that this example is simplistic in that it omits any
280 // authentication of the encrypted data. If you were actually to use
281 // StreamReader in this manner, an attacker could flip arbitrary bits in
282 // the decrypted result.
283}