aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/openpgp/armor/encode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/openpgp/armor/encode.go')
-rw-r--r--vendor/golang.org/x/crypto/openpgp/armor/encode.go160
1 files changed, 160 insertions, 0 deletions
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}