OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / openpgp / packet / symmetrically_encrypted.go
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 }