diff options
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.go | 290 |
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 | |||
5 | package packet | ||
6 | |||
7 | import ( | ||
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. | ||
20 | type 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 | |||
26 | const symmetricallyEncryptedVersion = 1 | ||
27 | |||
28 | func (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. | ||
47 | func (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. | ||
91 | type seReader struct { | ||
92 | in io.Reader | ||
93 | } | ||
94 | |||
95 | func (ser seReader) Read(buf []byte) (int, error) { | ||
96 | return ser.in.Read(buf) | ||
97 | } | ||
98 | |||
99 | func (ser seReader) Close() error { | ||
100 | return nil | ||
101 | } | ||
102 | |||
103 | const 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. | ||
109 | type 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 | |||
119 | func (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. | ||
179 | const mdcPacketTagByte = byte(0x80) | 0x40 | 19 | ||
180 | |||
181 | func (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. | ||
213 | type seMDCWriter struct { | ||
214 | w io.WriteCloser | ||
215 | h hash.Hash | ||
216 | } | ||
217 | |||
218 | func (w *seMDCWriter) Write(buf []byte) (n int, err error) { | ||
219 | w.h.Write(buf) | ||
220 | return w.w.Write(buf) | ||
221 | } | ||
222 | |||
223 | func (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. | ||
240 | type noOpCloser struct { | ||
241 | w io.Writer | ||
242 | } | ||
243 | |||
244 | func (c noOpCloser) Write(data []byte) (n int, err error) { | ||
245 | return c.w.Write(data) | ||
246 | } | ||
247 | |||
248 | func (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. | ||
256 | func 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 | } | ||