OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / crypto / openpgp / clearsign / clearsign.go
1 // 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
5 // Package clearsign generates and processes OpenPGP, clear-signed data. See
6 // RFC 4880, section 7.
7 //
8 // Clearsigned messages are cryptographically signed, but the contents of the
9 // message are kept in plaintext so that it can be read without special tools.
10 package clearsign // import "golang.org/x/crypto/openpgp/clearsign"
11
12 import (
13         "bufio"
14         "bytes"
15         "crypto"
16         "hash"
17         "io"
18         "net/textproto"
19         "strconv"
20
21         "golang.org/x/crypto/openpgp/armor"
22         "golang.org/x/crypto/openpgp/errors"
23         "golang.org/x/crypto/openpgp/packet"
24 )
25
26 // A Block represents a clearsigned message. A signature on a Block can
27 // be checked by passing Bytes into openpgp.CheckDetachedSignature.
28 type Block struct {
29         Headers          textproto.MIMEHeader // Optional message headers
30         Plaintext        []byte               // The original message text
31         Bytes            []byte               // The signed message
32         ArmoredSignature *armor.Block         // The signature block
33 }
34
35 // start is the marker which denotes the beginning of a clearsigned message.
36 var start = []byte("\n-----BEGIN PGP SIGNED MESSAGE-----")
37
38 // dashEscape is prefixed to any lines that begin with a hyphen so that they
39 // can't be confused with endText.
40 var dashEscape = []byte("- ")
41
42 // endText is a marker which denotes the end of the message and the start of
43 // an armored signature.
44 var endText = []byte("-----BEGIN PGP SIGNATURE-----")
45
46 // end is a marker which denotes the end of the armored signature.
47 var end = []byte("\n-----END PGP SIGNATURE-----")
48
49 var crlf = []byte("\r\n")
50 var lf = byte('\n')
51
52 // getLine returns the first \r\n or \n delineated line from the given byte
53 // array. The line does not include the \r\n or \n. The remainder of the byte
54 // array (also not including the new line bytes) is also returned and this will
55 // always be smaller than the original argument.
56 func getLine(data []byte) (line, rest []byte) {
57         i := bytes.Index(data, []byte{'\n'})
58         var j int
59         if i < 0 {
60                 i = len(data)
61                 j = i
62         } else {
63                 j = i + 1
64                 if i > 0 && data[i-1] == '\r' {
65                         i--
66                 }
67         }
68         return data[0:i], data[j:]
69 }
70
71 // Decode finds the first clearsigned message in data and returns it, as well
72 // as the suffix of data which remains after the message.
73 func Decode(data []byte) (b *Block, rest []byte) {
74         // start begins with a newline. However, at the very beginning of
75         // the byte array, we'll accept the start string without it.
76         rest = data
77         if bytes.HasPrefix(data, start[1:]) {
78                 rest = rest[len(start)-1:]
79         } else if i := bytes.Index(data, start); i >= 0 {
80                 rest = rest[i+len(start):]
81         } else {
82                 return nil, data
83         }
84
85         // Consume the start line.
86         _, rest = getLine(rest)
87
88         var line []byte
89         b = &Block{
90                 Headers: make(textproto.MIMEHeader),
91         }
92
93         // Next come a series of header lines.
94         for {
95                 // This loop terminates because getLine's second result is
96                 // always smaller than its argument.
97                 if len(rest) == 0 {
98                         return nil, data
99                 }
100                 // An empty line marks the end of the headers.
101                 if line, rest = getLine(rest); len(line) == 0 {
102                         break
103                 }
104
105                 i := bytes.Index(line, []byte{':'})
106                 if i == -1 {
107                         return nil, data
108                 }
109
110                 key, val := line[0:i], line[i+1:]
111                 key = bytes.TrimSpace(key)
112                 val = bytes.TrimSpace(val)
113                 b.Headers.Add(string(key), string(val))
114         }
115
116         firstLine := true
117         for {
118                 start := rest
119
120                 line, rest = getLine(rest)
121                 if len(line) == 0 && len(rest) == 0 {
122                         // No armored data was found, so this isn't a complete message.
123                         return nil, data
124                 }
125                 if bytes.Equal(line, endText) {
126                         // Back up to the start of the line because armor expects to see the
127                         // header line.
128                         rest = start
129                         break
130                 }
131
132                 // The final CRLF isn't included in the hash so we don't write it until
133                 // we've seen the next line.
134                 if firstLine {
135                         firstLine = false
136                 } else {
137                         b.Bytes = append(b.Bytes, crlf...)
138                 }
139
140                 if bytes.HasPrefix(line, dashEscape) {
141                         line = line[2:]
142                 }
143                 line = bytes.TrimRight(line, " \t")
144                 b.Bytes = append(b.Bytes, line...)
145
146                 b.Plaintext = append(b.Plaintext, line...)
147                 b.Plaintext = append(b.Plaintext, lf)
148         }
149
150         // We want to find the extent of the armored data (including any newlines at
151         // the end).
152         i := bytes.Index(rest, end)
153         if i == -1 {
154                 return nil, data
155         }
156         i += len(end)
157         for i < len(rest) && (rest[i] == '\r' || rest[i] == '\n') {
158                 i++
159         }
160         armored := rest[:i]
161         rest = rest[i:]
162
163         var err error
164         b.ArmoredSignature, err = armor.Decode(bytes.NewBuffer(armored))
165         if err != nil {
166                 return nil, data
167         }
168
169         return b, rest
170 }
171
172 // A dashEscaper is an io.WriteCloser which processes the body of a clear-signed
173 // message. The clear-signed message is written to buffered and a hash, suitable
174 // for signing, is maintained in h.
175 //
176 // When closed, an armored signature is created and written to complete the
177 // message.
178 type dashEscaper struct {
179         buffered *bufio.Writer
180         h        hash.Hash
181         hashType crypto.Hash
182
183         atBeginningOfLine bool
184         isFirstLine       bool
185
186         whitespace []byte
187         byteBuf    []byte // a one byte buffer to save allocations
188
189         privateKey *packet.PrivateKey
190         config     *packet.Config
191 }
192
193 func (d *dashEscaper) Write(data []byte) (n int, err error) {
194         for _, b := range data {
195                 d.byteBuf[0] = b
196
197                 if d.atBeginningOfLine {
198                         // The final CRLF isn't included in the hash so we have to wait
199                         // until this point (the start of the next line) before writing it.
200                         if !d.isFirstLine {
201                                 d.h.Write(crlf)
202                         }
203                         d.isFirstLine = false
204                 }
205
206                 // Any whitespace at the end of the line has to be removed so we
207                 // buffer it until we find out whether there's more on this line.
208                 if b == ' ' || b == '\t' || b == '\r' {
209                         d.whitespace = append(d.whitespace, b)
210                         d.atBeginningOfLine = false
211                         continue
212                 }
213
214                 if d.atBeginningOfLine {
215                         // At the beginning of a line, hyphens have to be escaped.
216                         if b == '-' {
217                                 // The signature isn't calculated over the dash-escaped text so
218                                 // the escape is only written to buffered.
219                                 if _, err = d.buffered.Write(dashEscape); err != nil {
220                                         return
221                                 }
222                                 d.h.Write(d.byteBuf)
223                                 d.atBeginningOfLine = false
224                         } else if b == '\n' {
225                                 // Nothing to do because we delay writing CRLF to the hash.
226                         } else {
227                                 d.h.Write(d.byteBuf)
228                                 d.atBeginningOfLine = false
229                         }
230                         if err = d.buffered.WriteByte(b); err != nil {
231                                 return
232                         }
233                 } else {
234                         if b == '\n' {
235                                 // We got a raw \n. Drop any trailing whitespace and write a
236                                 // CRLF.
237                                 d.whitespace = d.whitespace[:0]
238                                 // We delay writing CRLF to the hash until the start of the
239                                 // next line.
240                                 if err = d.buffered.WriteByte(b); err != nil {
241                                         return
242                                 }
243                                 d.atBeginningOfLine = true
244                         } else {
245                                 // Any buffered whitespace wasn't at the end of the line so
246                                 // we need to write it out.
247                                 if len(d.whitespace) > 0 {
248                                         d.h.Write(d.whitespace)
249                                         if _, err = d.buffered.Write(d.whitespace); err != nil {
250                                                 return
251                                         }
252                                         d.whitespace = d.whitespace[:0]
253                                 }
254                                 d.h.Write(d.byteBuf)
255                                 if err = d.buffered.WriteByte(b); err != nil {
256                                         return
257                                 }
258                         }
259                 }
260         }
261
262         n = len(data)
263         return
264 }
265
266 func (d *dashEscaper) Close() (err error) {
267         if !d.atBeginningOfLine {
268                 if err = d.buffered.WriteByte(lf); err != nil {
269                         return
270                 }
271         }
272         sig := new(packet.Signature)
273         sig.SigType = packet.SigTypeText
274         sig.PubKeyAlgo = d.privateKey.PubKeyAlgo
275         sig.Hash = d.hashType
276         sig.CreationTime = d.config.Now()
277         sig.IssuerKeyId = &d.privateKey.KeyId
278
279         if err = sig.Sign(d.h, d.privateKey, d.config); err != nil {
280                 return
281         }
282
283         out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil)
284         if err != nil {
285                 return
286         }
287
288         if err = sig.Serialize(out); err != nil {
289                 return
290         }
291         if err = out.Close(); err != nil {
292                 return
293         }
294         if err = d.buffered.Flush(); err != nil {
295                 return
296         }
297         return
298 }
299
300 // Encode returns a WriteCloser which will clear-sign a message with privateKey
301 // and write it to w. If config is nil, sensible defaults are used.
302 func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
303         if privateKey.Encrypted {
304                 return nil, errors.InvalidArgumentError("signing key is encrypted")
305         }
306
307         hashType := config.Hash()
308         name := nameOfHash(hashType)
309         if len(name) == 0 {
310                 return nil, errors.UnsupportedError("unknown hash type: " + strconv.Itoa(int(hashType)))
311         }
312
313         if !hashType.Available() {
314                 return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType)))
315         }
316         h := hashType.New()
317
318         buffered := bufio.NewWriter(w)
319         // start has a \n at the beginning that we don't want here.
320         if _, err = buffered.Write(start[1:]); err != nil {
321                 return
322         }
323         if err = buffered.WriteByte(lf); err != nil {
324                 return
325         }
326         if _, err = buffered.WriteString("Hash: "); err != nil {
327                 return
328         }
329         if _, err = buffered.WriteString(name); err != nil {
330                 return
331         }
332         if err = buffered.WriteByte(lf); err != nil {
333                 return
334         }
335         if err = buffered.WriteByte(lf); err != nil {
336                 return
337         }
338
339         plaintext = &dashEscaper{
340                 buffered: buffered,
341                 h:        h,
342                 hashType: hashType,
343
344                 atBeginningOfLine: true,
345                 isFirstLine:       true,
346
347                 byteBuf: make([]byte, 1),
348
349                 privateKey: privateKey,
350                 config:     config,
351         }
352
353         return
354 }
355
356 // nameOfHash returns the OpenPGP name for the given hash, or the empty string
357 // if the name isn't known. See RFC 4880, section 9.4.
358 func nameOfHash(h crypto.Hash) string {
359         switch h {
360         case crypto.MD5:
361                 return "MD5"
362         case crypto.SHA1:
363                 return "SHA1"
364         case crypto.RIPEMD160:
365                 return "RIPEMD160"
366         case crypto.SHA224:
367                 return "SHA224"
368         case crypto.SHA256:
369                 return "SHA256"
370         case crypto.SHA384:
371                 return "SHA384"
372         case crypto.SHA512:
373                 return "SHA512"
374         }
375         return ""
376 }