aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/openpgp/armor
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/openpgp/armor')
-rw-r--r--vendor/golang.org/x/crypto/openpgp/armor/armor.go219
-rw-r--r--vendor/golang.org/x/crypto/openpgp/armor/encode.go160
2 files changed, 379 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/openpgp/armor/armor.go b/vendor/golang.org/x/crypto/openpgp/armor/armor.go
new file mode 100644
index 0000000..592d186
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/armor/armor.go
@@ -0,0 +1,219 @@
1// Copyright 2010 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 armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
6// very similar to PEM except that it has an additional CRC checksum.
7package armor // import "golang.org/x/crypto/openpgp/armor"
8
9import (
10 "bufio"
11 "bytes"
12 "encoding/base64"
13 "golang.org/x/crypto/openpgp/errors"
14 "io"
15)
16
17// A Block represents an OpenPGP armored structure.
18//
19// The encoded form is:
20// -----BEGIN Type-----
21// Headers
22//
23// base64-encoded Bytes
24// '=' base64 encoded checksum
25// -----END Type-----
26// where Headers is a possibly empty sequence of Key: Value lines.
27//
28// Since the armored data can be very large, this package presents a streaming
29// interface.
30type Block struct {
31 Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
32 Header map[string]string // Optional headers.
33 Body io.Reader // A Reader from which the contents can be read
34 lReader lineReader
35 oReader openpgpReader
36}
37
38var ArmorCorrupt error = errors.StructuralError("armor invalid")
39
40const crc24Init = 0xb704ce
41const crc24Poly = 0x1864cfb
42const crc24Mask = 0xffffff
43
44// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
45func crc24(crc uint32, d []byte) uint32 {
46 for _, b := range d {
47 crc ^= uint32(b) << 16
48 for i := 0; i < 8; i++ {
49 crc <<= 1
50 if crc&0x1000000 != 0 {
51 crc ^= crc24Poly
52 }
53 }
54 }
55 return crc
56}
57
58var armorStart = []byte("-----BEGIN ")
59var armorEnd = []byte("-----END ")
60var armorEndOfLine = []byte("-----")
61
62// lineReader wraps a line based reader. It watches for the end of an armor
63// block and records the expected CRC value.
64type lineReader struct {
65 in *bufio.Reader
66 buf []byte
67 eof bool
68 crc uint32
69}
70
71func (l *lineReader) Read(p []byte) (n int, err error) {
72 if l.eof {
73 return 0, io.EOF
74 }
75
76 if len(l.buf) > 0 {
77 n = copy(p, l.buf)
78 l.buf = l.buf[n:]
79 return
80 }
81
82 line, isPrefix, err := l.in.ReadLine()
83 if err != nil {
84 return
85 }
86 if isPrefix {
87 return 0, ArmorCorrupt
88 }
89
90 if len(line) == 5 && line[0] == '=' {
91 // This is the checksum line
92 var expectedBytes [3]byte
93 var m int
94 m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
95 if m != 3 || err != nil {
96 return
97 }
98 l.crc = uint32(expectedBytes[0])<<16 |
99 uint32(expectedBytes[1])<<8 |
100 uint32(expectedBytes[2])
101
102 line, _, err = l.in.ReadLine()
103 if err != nil && err != io.EOF {
104 return
105 }
106 if !bytes.HasPrefix(line, armorEnd) {
107 return 0, ArmorCorrupt
108 }
109
110 l.eof = true
111 return 0, io.EOF
112 }
113
114 if len(line) > 96 {
115 return 0, ArmorCorrupt
116 }
117
118 n = copy(p, line)
119 bytesToSave := len(line) - n
120 if bytesToSave > 0 {
121 if cap(l.buf) < bytesToSave {
122 l.buf = make([]byte, 0, bytesToSave)
123 }
124 l.buf = l.buf[0:bytesToSave]
125 copy(l.buf, line[n:])
126 }
127
128 return
129}
130
131// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
132// a running CRC of the resulting data and checks the CRC against the value
133// found by the lineReader at EOF.
134type openpgpReader struct {
135 lReader *lineReader
136 b64Reader io.Reader
137 currentCRC uint32
138}
139
140func (r *openpgpReader) Read(p []byte) (n int, err error) {
141 n, err = r.b64Reader.Read(p)
142 r.currentCRC = crc24(r.currentCRC, p[:n])
143
144 if err == io.EOF {
145 if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
146 return 0, ArmorCorrupt
147 }
148 }
149
150 return
151}
152
153// Decode reads a PGP armored block from the given Reader. It will ignore
154// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The
155// given Reader is not usable after calling this function: an arbitrary amount
156// of data may have been read past the end of the block.
157func Decode(in io.Reader) (p *Block, err error) {
158 r := bufio.NewReaderSize(in, 100)
159 var line []byte
160 ignoreNext := false
161
162TryNextBlock:
163 p = nil
164
165 // Skip leading garbage
166 for {
167 ignoreThis := ignoreNext
168 line, ignoreNext, err = r.ReadLine()
169 if err != nil {
170 return
171 }
172 if ignoreNext || ignoreThis {
173 continue
174 }
175 line = bytes.TrimSpace(line)
176 if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
177 break
178 }
179 }
180
181 p = new(Block)
182 p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
183 p.Header = make(map[string]string)
184 nextIsContinuation := false
185 var lastKey string
186
187 // Read headers
188 for {
189 isContinuation := nextIsContinuation
190 line, nextIsContinuation, err = r.ReadLine()
191 if err != nil {
192 p = nil
193 return
194 }
195 if isContinuation {
196 p.Header[lastKey] += string(line)
197 continue
198 }
199 line = bytes.TrimSpace(line)
200 if len(line) == 0 {
201 break
202 }
203
204 i := bytes.Index(line, []byte(": "))
205 if i == -1 {
206 goto TryNextBlock
207 }
208 lastKey = string(line[:i])
209 p.Header[lastKey] = string(line[i+2:])
210 }
211
212 p.lReader.in = r
213 p.oReader.currentCRC = crc24Init
214 p.oReader.lReader = &p.lReader
215 p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
216 p.Body = &p.oReader
217
218 return
219}
diff --git a/vendor/golang.org/x/crypto/openpgp/armor/encode.go b/vendor/golang.org/x/crypto/openpgp/armor/encode.go
new file mode 100644
index 0000000..6f07582
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/armor/encode.go
@@ -0,0 +1,160 @@
1// Copyright 2010 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 armor
6
7import (
8 "encoding/base64"
9 "io"
10)
11
12var armorHeaderSep = []byte(": ")
13var blockEnd = []byte("\n=")
14var newline = []byte("\n")
15var armorEndOfLineOut = []byte("-----\n")
16
17// writeSlices writes its arguments to the given Writer.
18func writeSlices(out io.Writer, slices ...[]byte) (err error) {
19 for _, s := range slices {
20 _, err = out.Write(s)
21 if err != nil {
22 return err
23 }
24 }
25 return
26}
27
28// lineBreaker breaks data across several lines, all of the same byte length
29// (except possibly the last). Lines are broken with a single '\n'.
30type lineBreaker struct {
31 lineLength int
32 line []byte
33 used int
34 out io.Writer
35 haveWritten bool
36}
37
38func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
39 return &lineBreaker{
40 lineLength: lineLength,
41 line: make([]byte, lineLength),
42 used: 0,
43 out: out,
44 }
45}
46
47func (l *lineBreaker) Write(b []byte) (n int, err error) {
48 n = len(b)
49
50 if n == 0 {
51 return
52 }
53
54 if l.used == 0 && l.haveWritten {
55 _, err = l.out.Write([]byte{'\n'})
56 if err != nil {
57 return
58 }
59 }
60
61 if l.used+len(b) < l.lineLength {
62 l.used += copy(l.line[l.used:], b)
63 return
64 }
65
66 l.haveWritten = true
67 _, err = l.out.Write(l.line[0:l.used])
68 if err != nil {
69 return
70 }
71 excess := l.lineLength - l.used
72 l.used = 0
73
74 _, err = l.out.Write(b[0:excess])
75 if err != nil {
76 return
77 }
78
79 _, err = l.Write(b[excess:])
80 return
81}
82
83func (l *lineBreaker) Close() (err error) {
84 if l.used > 0 {
85 _, err = l.out.Write(l.line[0:l.used])
86 if err != nil {
87 return
88 }
89 }
90
91 return
92}
93
94// encoding keeps track of a running CRC24 over the data which has been written
95// to it and outputs a OpenPGP checksum when closed, followed by an armor
96// trailer.
97//
98// It's built into a stack of io.Writers:
99// encoding -> base64 encoder -> lineBreaker -> out
100type encoding struct {
101 out io.Writer
102 breaker *lineBreaker
103 b64 io.WriteCloser
104 crc uint32
105 blockType []byte
106}
107
108func (e *encoding) Write(data []byte) (n int, err error) {
109 e.crc = crc24(e.crc, data)
110 return e.b64.Write(data)
111}
112
113func (e *encoding) Close() (err error) {
114 err = e.b64.Close()
115 if err != nil {
116 return
117 }
118 e.breaker.Close()
119
120 var checksumBytes [3]byte
121 checksumBytes[0] = byte(e.crc >> 16)
122 checksumBytes[1] = byte(e.crc >> 8)
123 checksumBytes[2] = byte(e.crc)
124
125 var b64ChecksumBytes [4]byte
126 base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
127
128 return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
129}
130
131// Encode returns a WriteCloser which will encode the data written to it in
132// OpenPGP armor.
133func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
134 bType := []byte(blockType)
135 err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
136 if err != nil {
137 return
138 }
139
140 for k, v := range headers {
141 err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
142 if err != nil {
143 return
144 }
145 }
146
147 _, err = out.Write(newline)
148 if err != nil {
149 return
150 }
151
152 e := &encoding{
153 out: out,
154 breaker: newLineBreaker(out, 64),
155 crc: crc24Init,
156 blockType: bType,
157 }
158 e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
159 return e, nil
160}