~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/golang.org/x/crypto/openpgp/armor/encode.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

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
)
 
11
 
 
12
var armorHeaderSep = []byte(": ")
 
13
var blockEnd = []byte("\n=")
 
14
var newline = []byte("\n")
 
15
var armorEndOfLineOut = []byte("-----\n")
 
16
 
 
17
// writeSlices writes its arguments to the given Writer.
 
18
func 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'.
 
30
type lineBreaker struct {
 
31
        lineLength  int
 
32
        line        []byte
 
33
        used        int
 
34
        out         io.Writer
 
35
        haveWritten bool
 
36
}
 
37
 
 
38
func 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
 
 
47
func (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
 
 
83
func (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
 
100
type encoding struct {
 
101
        out       io.Writer
 
102
        breaker   *lineBreaker
 
103
        b64       io.WriteCloser
 
104
        crc       uint32
 
105
        blockType []byte
 
106
}
 
107
 
 
108
func (e *encoding) Write(data []byte) (n int, err error) {
 
109
        e.crc = crc24(e.crc, data)
 
110
        return e.b64.Write(data)
 
111
}
 
112
 
 
113
func (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.
 
133
func 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
}