Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(125)

Delta Between Two Patch Sets: openpgp/armor/armor.go

Issue 5564059: code review 5564059: go.crypto: initial code (Closed)
Left Patch Set: Created 12 years, 2 months ago
Right Patch Set: diff -r b50a7fb49394 https://code.google.com/p/go.crypto Created 12 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « ocsp/ocsp_test.go ('k') | openpgp/armor/armor_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
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.
7 package armor
8
9 import (
10 "bufio"
11 "bytes"
12 "code.google.com/p/go.crypto/openpgp/errors"
13 "encoding/base64"
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.
30 type Block struct {
31 Type string // The type, taken from the preamble (i.e. "PG P SIGNATURE").
32 Header map[string]string // Optional headers.
33 Body io.Reader // A Reader from which the contents can be rea d
34 lReader lineReader
35 oReader openpgpReader
36 }
37
38 var ArmorCorrupt error = errors.StructuralError("armor invalid")
39
40 const crc24Init = 0xb704ce
41 const crc24Poly = 0x1864cfb
42 const crc24Mask = 0xffffff
43
44 // crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
45 func 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
58 var armorStart = []byte("-----BEGIN ")
59 var armorEnd = []byte("-----END ")
60 var 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.
64 type lineReader struct {
65 in *bufio.Reader
66 buf []byte
67 eof bool
68 crc uint32
69 }
70
71 func (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) > 64 {
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.
134 type openpgpReader struct {
135 lReader *lineReader
136 b64Reader io.Reader
137 currentCRC uint32
138 }
139
140 func (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.
157 func Decode(in io.Reader) (p *Block, err error) {
158 r, _ := bufio.NewReaderSize(in, 100)
159 var line []byte
160 ignoreNext := false
161
162 TryNextBlock:
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.HasP refix(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 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b