~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/pkg/crypto/openpgp/armor/encode.go

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-04-20 17:36:48 UTC
  • Revision ID: james.westby@ubuntu.com-20110420173648-ifergoxyrm832trd
Tags: upstream-2011.03.07.1
Import upstream version 2011.03.07.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
6
 
 
7
import (
 
8
        "encoding/base64"
 
9
        "io"
 
10
        "os"
 
11
)
 
12
 
 
13
var armorHeaderSep = []byte(": ")
 
14
var blockEnd = []byte("\n=")
 
15
var newline = []byte("\n")
 
16
var armorEndOfLineOut = []byte("-----\n")
 
17
 
 
18
// writeSlices writes its arguments to the given Writer.
 
19
func writeSlices(out io.Writer, slices ...[]byte) (err os.Error) {
 
20
        for _, s := range slices {
 
21
                _, err := out.Write(s)
 
22
                if err != nil {
 
23
                        return
 
24
                }
 
25
        }
 
26
        return
 
27
}
 
28
 
 
29
// lineBreaker breaks data across several lines, all of the same byte length
 
30
// (except possibly the last). Lines are broken with a single '\n'.
 
31
type lineBreaker struct {
 
32
        lineLength  int
 
33
        line        []byte
 
34
        used        int
 
35
        out         io.Writer
 
36
        haveWritten bool
 
37
}
 
38
 
 
39
func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
 
40
        return &lineBreaker{
 
41
                lineLength: lineLength,
 
42
                line:       make([]byte, lineLength),
 
43
                used:       0,
 
44
                out:        out,
 
45
        }
 
46
}
 
47
 
 
48
func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
 
49
        n = len(b)
 
50
 
 
51
        if n == 0 {
 
52
                return
 
53
        }
 
54
 
 
55
        if l.used == 0 && l.haveWritten {
 
56
                _, err = l.out.Write([]byte{'\n'})
 
57
                if err != nil {
 
58
                        return
 
59
                }
 
60
        }
 
61
 
 
62
        if l.used+len(b) < l.lineLength {
 
63
                l.used += copy(l.line[l.used:], b)
 
64
                return
 
65
        }
 
66
 
 
67
        l.haveWritten = true
 
68
        _, err = l.out.Write(l.line[0:l.used])
 
69
        if err != nil {
 
70
                return
 
71
        }
 
72
        excess := l.lineLength - l.used
 
73
        l.used = 0
 
74
 
 
75
        _, err = l.out.Write(b[0:excess])
 
76
        if err != nil {
 
77
                return
 
78
        }
 
79
 
 
80
        _, err = l.Write(b[excess:])
 
81
        return
 
82
}
 
83
 
 
84
func (l *lineBreaker) Close() (err os.Error) {
 
85
        if l.used > 0 {
 
86
                _, err = l.out.Write(l.line[0:l.used])
 
87
                if err != nil {
 
88
                        return
 
89
                }
 
90
        }
 
91
 
 
92
        return
 
93
}
 
94
 
 
95
// encoding keeps track of a running CRC24 over the data which has been written
 
96
// to it and outputs a OpenPGP checksum when closed, followed by an armor
 
97
// trailer.
 
98
//
 
99
// It's built into a stack of io.Writers:
 
100
//    encoding -> base64 encoder -> lineBreaker -> out
 
101
type encoding struct {
 
102
        out       io.Writer
 
103
        breaker   *lineBreaker
 
104
        b64       io.WriteCloser
 
105
        crc       uint32
 
106
        blockType []byte
 
107
}
 
108
 
 
109
func (e *encoding) Write(data []byte) (n int, err os.Error) {
 
110
        e.crc = crc24(e.crc, data)
 
111
        return e.b64.Write(data)
 
112
}
 
113
 
 
114
func (e *encoding) Close() (err os.Error) {
 
115
        err = e.b64.Close()
 
116
        if err != nil {
 
117
                return
 
118
        }
 
119
        e.breaker.Close()
 
120
 
 
121
        var checksumBytes [3]byte
 
122
        checksumBytes[0] = byte(e.crc >> 16)
 
123
        checksumBytes[1] = byte(e.crc >> 8)
 
124
        checksumBytes[2] = byte(e.crc)
 
125
 
 
126
        var b64ChecksumBytes [4]byte
 
127
        base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
 
128
 
 
129
        return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
 
130
}
 
131
 
 
132
// Encode returns a WriteCloser which will encode the data written to it in
 
133
// OpenPGP armor.
 
134
func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err os.Error) {
 
135
        bType := []byte(blockType)
 
136
        err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
 
137
        if err != nil {
 
138
                return
 
139
        }
 
140
 
 
141
        for k, v := range headers {
 
142
                err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
 
143
                if err != nil {
 
144
                        return
 
145
                }
 
146
        }
 
147
 
 
148
        _, err = out.Write(newline)
 
149
        if err != nil {
 
150
                return
 
151
        }
 
152
 
 
153
        e := &encoding{
 
154
                out:       out,
 
155
                breaker:   newLineBreaker(out, 64),
 
156
                crc:       crc24Init,
 
157
                blockType: bType,
 
158
        }
 
159
        e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
 
160
        return e, nil
 
161
}