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

Delta Between Two Patch Sets: openpgp/armor/encode.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 | « openpgp/armor/armor_test.go ('k') | openpgp/canonical_text.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
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, armorE nd, 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.Wr iteCloser, 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), new line)
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 }
LEFTRIGHT

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