~ubuntu-branches/ubuntu/utopic/hockeypuck/utopic-proposed

« back to all changes in this revision

Viewing changes to build/src/code.google.com/p/go.crypto/openpgp/packet/symmetrically_encrypted.go

  • Committer: Package Import Robot
  • Author(s): Casey Marshall
  • Date: 2014-04-13 20:06:01 UTC
  • Revision ID: package-import@ubuntu.com-20140413200601-oxdlqn1gy0x8m55u
Tags: 1.0~rel20140413+7a1892a~trusty
Hockeypuck 1.0 release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        "code.google.com/p/go.crypto/openpgp/errors"
 
9
        "crypto/cipher"
 
10
        "crypto/sha1"
 
11
        "crypto/subtle"
 
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
}