Skip to content

Commit 364cb83

Browse files
committed
crypto/openpgp/packet: add basic routines
Since nobody suggested major changes to the higher level API, I'm splitting up the lower level code for review. This is the first of the changes for the packet reading/writing code. It deliberately doesn't include a Makefile because the package is incomplete. R=bradfitzgo CC=golang-dev https://golang.org/cl/4080051
1 parent 2a2995c commit 364cb83

File tree

2 files changed

+587
-0
lines changed

2 files changed

+587
-0
lines changed
Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
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+
// This package implements parsing and serialisation of OpenPGP packets, as
6+
// specified in RFC 4880.
7+
package packet
8+
9+
import (
10+
"crypto/aes"
11+
"crypto/cast5"
12+
"crypto/cipher"
13+
"crypto/openpgp/error"
14+
"io"
15+
"os"
16+
)
17+
18+
// readFull is the same as io.ReadFull except that reading zero bytes returns
19+
// ErrUnexpectedEOF rather than EOF.
20+
func readFull(r io.Reader, buf []byte) (n int, err os.Error) {
21+
n, err = io.ReadFull(r, buf)
22+
if err == os.EOF {
23+
err = io.ErrUnexpectedEOF
24+
}
25+
return
26+
}
27+
28+
// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
29+
func readLength(r io.Reader) (length int64, isPartial bool, err os.Error) {
30+
var buf [4]byte
31+
_, err = readFull(r, buf[:1])
32+
if err != nil {
33+
return
34+
}
35+
switch {
36+
case buf[0] < 192:
37+
length = int64(buf[0])
38+
case buf[0] < 224:
39+
length = int64(buf[0]-192) << 8
40+
_, err = readFull(r, buf[0:1])
41+
if err != nil {
42+
return
43+
}
44+
length += int64(buf[0]) + 192
45+
case buf[0] < 255:
46+
length = int64(1) << (buf[0] & 0x1f)
47+
isPartial = true
48+
default:
49+
_, err = readFull(r, buf[0:4])
50+
if err != nil {
51+
return
52+
}
53+
length = int64(buf[0])<<24 |
54+
int64(buf[1])<<16 |
55+
int64(buf[2])<<8 |
56+
int64(buf[3])
57+
}
58+
return
59+
}
60+
61+
// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
62+
// The continuation lengths are parsed and removed from the stream and EOF is
63+
// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
64+
type partialLengthReader struct {
65+
r io.Reader
66+
remaining int64
67+
isPartial bool
68+
}
69+
70+
func (r *partialLengthReader) Read(p []byte) (n int, err os.Error) {
71+
for r.remaining == 0 {
72+
if !r.isPartial {
73+
return 0, os.EOF
74+
}
75+
r.remaining, r.isPartial, err = readLength(r.r)
76+
if err != nil {
77+
return 0, err
78+
}
79+
}
80+
81+
toRead := int64(len(p))
82+
if toRead > r.remaining {
83+
toRead = r.remaining
84+
}
85+
86+
n, err = r.r.Read(p[:int(toRead)])
87+
r.remaining -= int64(n)
88+
if n < int(toRead) && err == os.EOF {
89+
err = io.ErrUnexpectedEOF
90+
}
91+
return
92+
}
93+
94+
// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
95+
// underlying Reader returns EOF before the limit has been reached.
96+
type spanReader struct {
97+
r io.Reader
98+
n int64
99+
}
100+
101+
func (l *spanReader) Read(p []byte) (n int, err os.Error) {
102+
if l.n <= 0 {
103+
return 0, os.EOF
104+
}
105+
if int64(len(p)) > l.n {
106+
p = p[0:l.n]
107+
}
108+
n, err = l.r.Read(p)
109+
l.n -= int64(n)
110+
if l.n > 0 && err == os.EOF {
111+
err = io.ErrUnexpectedEOF
112+
}
113+
return
114+
}
115+
116+
// readHeader parses a packet header and returns an io.Reader which will return
117+
// the contents of the packet. See RFC 4880, section 4.2.
118+
func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err os.Error) {
119+
var buf [4]byte
120+
_, err = io.ReadFull(r, buf[:1])
121+
if err != nil {
122+
return
123+
}
124+
if buf[0]&0x80 == 0 {
125+
err = error.StructuralError("tag byte does not have MSB set")
126+
return
127+
}
128+
if buf[0]&0x40 == 0 {
129+
// Old format packet
130+
tag = packetType((buf[0] & 0x3f) >> 2)
131+
lengthType := buf[0] & 3
132+
if lengthType == 3 {
133+
length = -1
134+
contents = r
135+
return
136+
}
137+
lengthBytes := 1 << lengthType
138+
_, err = readFull(r, buf[0:lengthBytes])
139+
if err != nil {
140+
return
141+
}
142+
for i := 0; i < lengthBytes; i++ {
143+
length <<= 8
144+
length |= int64(buf[i])
145+
}
146+
contents = &spanReader{r, length}
147+
return
148+
}
149+
150+
// New format packet
151+
tag = packetType(buf[0] & 0x3f)
152+
length, isPartial, err := readLength(r)
153+
if err != nil {
154+
return
155+
}
156+
if isPartial {
157+
contents = &partialLengthReader{
158+
remaining: length,
159+
isPartial: true,
160+
r: r,
161+
}
162+
length = -1
163+
} else {
164+
contents = &spanReader{r, length}
165+
}
166+
return
167+
}
168+
169+
// serialiseHeader writes an OpenPGP packet header to w. See RFC 4880, section
170+
// 4.2.
171+
func serialiseHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
172+
var buf [5]byte
173+
var n int
174+
175+
buf[0] = 0x80 | 0x40 | byte(ptype)
176+
if length < 192 {
177+
buf[1] = byte(length)
178+
n = 2
179+
} else if length < 8384 {
180+
length -= 192
181+
buf[1] = byte(length >> 8)
182+
buf[2] = byte(length)
183+
n = 3
184+
} else {
185+
buf[0] = 255
186+
buf[1] = byte(length >> 24)
187+
buf[2] = byte(length >> 16)
188+
buf[3] = byte(length >> 8)
189+
buf[4] = byte(length)
190+
n = 5
191+
}
192+
193+
_, err = w.Write(buf[:n])
194+
return
195+
}
196+
197+
// Packet represents an OpenPGP packet. Users are expected to try casting
198+
// instances of this interface to specific packet types.
199+
type Packet interface {
200+
parse(io.Reader) os.Error
201+
}
202+
203+
// consumeAll reads from the given Reader until error, returning the number of
204+
// bytes read.
205+
func consumeAll(r io.Reader) (n int64, err os.Error) {
206+
var m int
207+
var buf [1024]byte
208+
209+
for {
210+
m, err = r.Read(buf[:])
211+
n += int64(m)
212+
if err == os.EOF {
213+
err = nil
214+
return
215+
}
216+
if err != nil {
217+
return
218+
}
219+
}
220+
221+
panic("unreachable")
222+
}
223+
224+
// packetType represents the numeric ids of the different OpenPGP packet types. See
225+
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
226+
type packetType uint8
227+
228+
const (
229+
packetTypeEncryptedKey packetType = 1
230+
packetTypeSignature packetType = 2
231+
packetTypeSymmetricKeyEncrypted packetType = 3
232+
packetTypeOnePassSignature packetType = 4
233+
packetTypePrivateKey packetType = 5
234+
packetTypePublicKey packetType = 6
235+
packetTypePrivateSubkey packetType = 7
236+
packetTypeCompressed packetType = 8
237+
packetTypeSymmetricallyEncrypted packetType = 9
238+
packetTypeLiteralData packetType = 11
239+
packetTypeUserId packetType = 13
240+
packetTypePublicSubkey packetType = 14
241+
packetTypeSymmetricallyEncryptedMDC packetType = 18
242+
)
243+
244+
// Read reads a single OpenPGP packet from the given io.Reader. If there is an
245+
// error parsing a packet, the whole packet is consumed from the input.
246+
func Read(r io.Reader) (p Packet, err os.Error) {
247+
tag, _, contents, err := readHeader(r)
248+
if err != nil {
249+
return
250+
}
251+
252+
switch tag {
253+
case packetTypeEncryptedKey:
254+
p = new(EncryptedKey)
255+
case packetTypeSignature:
256+
p = new(Signature)
257+
case packetTypeSymmetricKeyEncrypted:
258+
p = new(SymmetricKeyEncrypted)
259+
case packetTypeOnePassSignature:
260+
p = new(OnePassSignature)
261+
case packetTypePrivateKey, packetTypePrivateSubkey:
262+
pk := new(PrivateKey)
263+
if tag == packetTypePrivateSubkey {
264+
pk.IsSubKey = true
265+
}
266+
p = pk
267+
case packetTypePublicKey, packetTypePublicSubkey:
268+
pk := new(PublicKey)
269+
if tag == packetTypePublicSubkey {
270+
pk.IsSubKey = true
271+
}
272+
p = pk
273+
case packetTypeCompressed:
274+
p = new(Compressed)
275+
case packetTypeSymmetricallyEncrypted:
276+
p = new(SymmetricallyEncrypted)
277+
case packetTypeLiteralData:
278+
p = new(LiteralData)
279+
case packetTypeUserId:
280+
p = new(UserId)
281+
case packetTypeSymmetricallyEncryptedMDC:
282+
se := new(SymmetricallyEncrypted)
283+
se.MDC = true
284+
p = se
285+
default:
286+
err = error.UnknownPacketTypeError(tag)
287+
}
288+
if p != nil {
289+
err = p.parse(contents)
290+
}
291+
if err != nil {
292+
consumeAll(contents)
293+
}
294+
return
295+
}
296+
297+
// SignatureType represents the different semantic meanings of an OpenPGP
298+
// signature. See RFC 4880, section 5.2.1.
299+
type SignatureType uint8
300+
301+
const (
302+
SigTypeBinary SignatureType = 0
303+
SigTypeText SignatureType = 1
304+
SigTypeGenericCert = 0x10
305+
SigTypePersonaCert = 0x11
306+
SigTypeCasualCert = 0x12
307+
SigTypePositiveCert = 0x13
308+
SigTypeSubkeyBinding = 0x18
309+
)
310+
311+
// PublicKeyAlgorithm represents the different public key system specified for
312+
// OpenPGP. See
313+
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
314+
type PublicKeyAlgorithm uint8
315+
316+
const (
317+
PubKeyAlgoRSA PublicKeyAlgorithm = 1
318+
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
319+
PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
320+
PubKeyAlgoElgamal PublicKeyAlgorithm = 16
321+
PubKeyAlgoDSA PublicKeyAlgorithm = 17
322+
)
323+
324+
// CipherFunction represents the different block ciphers specified for OpenPGP. See
325+
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
326+
type CipherFunction uint8
327+
328+
const (
329+
CipherCAST5 = 3
330+
CipherAES128 = 7
331+
CipherAES192 = 8
332+
CipherAES256 = 9
333+
)
334+
335+
// keySize returns the key size, in bytes, of cipher.
336+
func (cipher CipherFunction) keySize() int {
337+
switch cipher {
338+
case CipherCAST5:
339+
return cast5.KeySize
340+
case CipherAES128:
341+
return 16
342+
case CipherAES192:
343+
return 24
344+
case CipherAES256:
345+
return 32
346+
}
347+
return 0
348+
}
349+
350+
// blockSize returns the block size, in bytes, of cipher.
351+
func (cipher CipherFunction) blockSize() int {
352+
switch cipher {
353+
case CipherCAST5:
354+
return 8
355+
case CipherAES128, CipherAES192, CipherAES256:
356+
return 16
357+
}
358+
return 0
359+
}
360+
361+
// new returns a fresh instance of the given cipher.
362+
func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
363+
switch cipher {
364+
case CipherCAST5:
365+
block, _ = cast5.NewCipher(key)
366+
case CipherAES128, CipherAES192, CipherAES256:
367+
block, _ = aes.NewCipher(key)
368+
}
369+
return
370+
}
371+
372+
// readMPI reads a big integer from r. The bit length returned is the bit
373+
// length that was specified in r. This is preserved so that the integer can be
374+
// reserialised exactly.
375+
func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
376+
var buf [2]byte
377+
_, err = readFull(r, buf[0:])
378+
if err != nil {
379+
return
380+
}
381+
bitLength = uint16(buf[0])<<8 | uint16(buf[1])
382+
numBytes := (int(bitLength) + 7) / 8
383+
mpi = make([]byte, numBytes)
384+
_, err = readFull(r, mpi)
385+
return
386+
}
387+
388+
// writeMPI serialises a big integer to r.
389+
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err os.Error) {
390+
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
391+
if err == nil {
392+
_, err = w.Write(mpiBytes)
393+
}
394+
return
395+
}

0 commit comments

Comments
 (0)