aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go')
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go290
1 files changed, 290 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
new file mode 100644
index 0000000..6126030
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
@@ -0,0 +1,290 @@
1// Copyright 2011 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 packet
6
7import (
8 "crypto/cipher"
9 "crypto/sha1"
10 "crypto/subtle"
11 "golang.org/x/crypto/openpgp/errors"
12 "hash"
13 "io"
14 "strconv"
15)
16
17// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
18// encrypted contents will consist of more OpenPGP packets. See RFC 4880,
19// sections 5.7 and 5.13.
20type SymmetricallyEncrypted struct {
21 MDC bool // true iff this is a type 18 packet and thus has an embedded MAC.
22 contents io.Reader
23 prefix []byte
24}
25
26const symmetricallyEncryptedVersion = 1
27
28func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
29 if se.MDC {
30 // See RFC 4880, section 5.13.
31 var buf [1]byte
32 _, err := readFull(r, buf[:])
33 if err != nil {
34 return err
35 }
36 if buf[0] != symmetricallyEncryptedVersion {
37 return errors.UnsupportedError("unknown SymmetricallyEncrypted version")
38 }
39 }
40 se.contents = r
41 return nil
42}
43
44// Decrypt returns a ReadCloser, from which the decrypted contents of the
45// packet can be read. An incorrect key can, with high probability, be detected
46// immediately and this will result in a KeyIncorrect error being returned.
47func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
48 keySize := c.KeySize()
49 if keySize == 0 {
50 return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
51 }
52 if len(key) != keySize {
53 return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
54 }
55
56 if se.prefix == nil {
57 se.prefix = make([]byte, c.blockSize()+2)
58 _, err := readFull(se.contents, se.prefix)
59 if err != nil {
60 return nil, err
61 }
62 } else if len(se.prefix) != c.blockSize()+2 {
63 return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
64 }
65
66 ocfbResync := OCFBResync
67 if se.MDC {
68 // MDC packets use a different form of OCFB mode.
69 ocfbResync = OCFBNoResync
70 }
71
72 s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
73 if s == nil {
74 return nil, errors.ErrKeyIncorrect
75 }
76
77 plaintext := cipher.StreamReader{S: s, R: se.contents}
78
79 if se.MDC {
80 // MDC packets have an embedded hash that we need to check.
81 h := sha1.New()
82 h.Write(se.prefix)
83 return &seMDCReader{in: plaintext, h: h}, nil
84 }
85
86 // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
87 return seReader{plaintext}, nil
88}
89
90// seReader wraps an io.Reader with a no-op Close method.
91type seReader struct {
92 in io.Reader
93}
94
95func (ser seReader) Read(buf []byte) (int, error) {
96 return ser.in.Read(buf)
97}
98
99func (ser seReader) Close() error {
100 return nil
101}
102
103const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
104
105// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
106// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
107// MDC packet containing a hash of the previous contents which is checked
108// against the running hash. See RFC 4880, section 5.13.
109type seMDCReader struct {
110 in io.Reader
111 h hash.Hash
112 trailer [mdcTrailerSize]byte
113 scratch [mdcTrailerSize]byte
114 trailerUsed int
115 error bool
116 eof bool
117}
118
119func (ser *seMDCReader) Read(buf []byte) (n int, err error) {
120 if ser.error {
121 err = io.ErrUnexpectedEOF
122 return
123 }
124 if ser.eof {
125 err = io.EOF
126 return
127 }
128
129 // If we haven't yet filled the trailer buffer then we must do that
130 // first.
131 for ser.trailerUsed < mdcTrailerSize {
132 n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
133 ser.trailerUsed += n
134 if err == io.EOF {
135 if ser.trailerUsed != mdcTrailerSize {
136 n = 0
137 err = io.ErrUnexpectedEOF
138 ser.error = true
139 return
140 }
141 ser.eof = true
142 n = 0
143 return
144 }
145
146 if err != nil {
147 n = 0
148 return
149 }
150 }
151
152 // If it's a short read then we read into a temporary buffer and shift
153 // the data into the caller's buffer.
154 if len(buf) <= mdcTrailerSize {
155 n, err = readFull(ser.in, ser.scratch[:len(buf)])
156 copy(buf, ser.trailer[:n])
157 ser.h.Write(buf[:n])
158 copy(ser.trailer[:], ser.trailer[n:])
159 copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
160 if n < len(buf) {
161 ser.eof = true
162 err = io.EOF
163 }
164 return
165 }
166
167 n, err = ser.in.Read(buf[mdcTrailerSize:])
168 copy(buf, ser.trailer[:])
169 ser.h.Write(buf[:n])
170 copy(ser.trailer[:], buf[n:])
171
172 if err == io.EOF {
173 ser.eof = true
174 }
175 return
176}
177
178// This is a new-format packet tag byte for a type 19 (MDC) packet.
179const mdcPacketTagByte = byte(0x80) | 0x40 | 19
180
181func (ser *seMDCReader) Close() error {
182 if ser.error {
183 return errors.SignatureError("error during reading")
184 }
185
186 for !ser.eof {
187 // We haven't seen EOF so we need to read to the end
188 var buf [1024]byte
189 _, err := ser.Read(buf[:])
190 if err == io.EOF {
191 break
192 }
193 if err != nil {
194 return errors.SignatureError("error during reading")
195 }
196 }
197
198 if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
199 return errors.SignatureError("MDC packet not found")
200 }
201 ser.h.Write(ser.trailer[:2])
202
203 final := ser.h.Sum(nil)
204 if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
205 return errors.SignatureError("hash mismatch")
206 }
207 return nil
208}
209
210// An seMDCWriter writes through to an io.WriteCloser while maintains a running
211// hash of the data written. On close, it emits an MDC packet containing the
212// running hash.
213type seMDCWriter struct {
214 w io.WriteCloser
215 h hash.Hash
216}
217
218func (w *seMDCWriter) Write(buf []byte) (n int, err error) {
219 w.h.Write(buf)
220 return w.w.Write(buf)
221}
222
223func (w *seMDCWriter) Close() (err error) {
224 var buf [mdcTrailerSize]byte
225
226 buf[0] = mdcPacketTagByte
227 buf[1] = sha1.Size
228 w.h.Write(buf[:2])
229 digest := w.h.Sum(nil)
230 copy(buf[2:], digest)
231
232 _, err = w.w.Write(buf[:])
233 if err != nil {
234 return
235 }
236 return w.w.Close()
237}
238
239// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
240type noOpCloser struct {
241 w io.Writer
242}
243
244func (c noOpCloser) Write(data []byte) (n int, err error) {
245 return c.w.Write(data)
246}
247
248func (c noOpCloser) Close() error {
249 return nil
250}
251
252// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
253// to w and returns a WriteCloser to which the to-be-encrypted packets can be
254// written.
255// If config is nil, sensible defaults will be used.
256func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) {
257 if c.KeySize() != len(key) {
258 return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
259 }
260 writeCloser := noOpCloser{w}
261 ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
262 if err != nil {
263 return
264 }
265
266 _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
267 if err != nil {
268 return
269 }
270
271 block := c.new(key)
272 blockSize := block.BlockSize()
273 iv := make([]byte, blockSize)
274 _, err = config.Random().Read(iv)
275 if err != nil {
276 return
277 }
278 s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
279 _, err = ciphertext.Write(prefix)
280 if err != nil {
281 return
282 }
283 plaintext := cipher.StreamWriter{S: s, W: ciphertext}
284
285 h := sha1.New()
286 h.Write(iv)
287 h.Write(iv[blockSize-2:])
288 contents = &seMDCWriter{w: plaintext, h: h}
289 return
290}