aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/openpgp/write.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/openpgp/write.go')
-rw-r--r--vendor/golang.org/x/crypto/openpgp/write.go378
1 files changed, 378 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/openpgp/write.go b/vendor/golang.org/x/crypto/openpgp/write.go
new file mode 100644
index 0000000..65a304c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/write.go
@@ -0,0 +1,378 @@
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
5package openpgp
6
7import (
8 "crypto"
9 "hash"
10 "io"
11 "strconv"
12 "time"
13
14 "golang.org/x/crypto/openpgp/armor"
15 "golang.org/x/crypto/openpgp/errors"
16 "golang.org/x/crypto/openpgp/packet"
17 "golang.org/x/crypto/openpgp/s2k"
18)
19
20// DetachSign signs message with the private key from signer (which must
21// already have been decrypted) and writes the signature to w.
22// If config is nil, sensible defaults will be used.
23func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
24 return detachSign(w, signer, message, packet.SigTypeBinary, config)
25}
26
27// ArmoredDetachSign signs message with the private key from signer (which
28// must already have been decrypted) and writes an armored signature to w.
29// If config is nil, sensible defaults will be used.
30func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) {
31 return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config)
32}
33
34// DetachSignText signs message (after canonicalising the line endings) with
35// the private key from signer (which must already have been decrypted) and
36// writes the signature to w.
37// If config is nil, sensible defaults will be used.
38func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
39 return detachSign(w, signer, message, packet.SigTypeText, config)
40}
41
42// ArmoredDetachSignText signs message (after canonicalising the line endings)
43// with the private key from signer (which must already have been decrypted)
44// and writes an armored signature to w.
45// If config is nil, sensible defaults will be used.
46func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
47 return armoredDetachSign(w, signer, message, packet.SigTypeText, config)
48}
49
50func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
51 out, err := armor.Encode(w, SignatureType, nil)
52 if err != nil {
53 return
54 }
55 err = detachSign(out, signer, message, sigType, config)
56 if err != nil {
57 return
58 }
59 return out.Close()
60}
61
62func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
63 if signer.PrivateKey == nil {
64 return errors.InvalidArgumentError("signing key doesn't have a private key")
65 }
66 if signer.PrivateKey.Encrypted {
67 return errors.InvalidArgumentError("signing key is encrypted")
68 }
69
70 sig := new(packet.Signature)
71 sig.SigType = sigType
72 sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
73 sig.Hash = config.Hash()
74 sig.CreationTime = config.Now()
75 sig.IssuerKeyId = &signer.PrivateKey.KeyId
76
77 h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
78 if err != nil {
79 return
80 }
81 io.Copy(wrappedHash, message)
82
83 err = sig.Sign(h, signer.PrivateKey, config)
84 if err != nil {
85 return
86 }
87
88 return sig.Serialize(w)
89}
90
91// FileHints contains metadata about encrypted files. This metadata is, itself,
92// encrypted.
93type FileHints struct {
94 // IsBinary can be set to hint that the contents are binary data.
95 IsBinary bool
96 // FileName hints at the name of the file that should be written. It's
97 // truncated to 255 bytes if longer. It may be empty to suggest that the
98 // file should not be written to disk. It may be equal to "_CONSOLE" to
99 // suggest the data should not be written to disk.
100 FileName string
101 // ModTime contains the modification time of the file, or the zero time if not applicable.
102 ModTime time.Time
103}
104
105// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
106// The resulting WriteCloser must be closed after the contents of the file have
107// been written.
108// If config is nil, sensible defaults will be used.
109func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
110 if hints == nil {
111 hints = &FileHints{}
112 }
113
114 key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config)
115 if err != nil {
116 return
117 }
118 w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config)
119 if err != nil {
120 return
121 }
122
123 literaldata := w
124 if algo := config.Compression(); algo != packet.CompressionNone {
125 var compConfig *packet.CompressionConfig
126 if config != nil {
127 compConfig = config.CompressionConfig
128 }
129 literaldata, err = packet.SerializeCompressed(w, algo, compConfig)
130 if err != nil {
131 return
132 }
133 }
134
135 var epochSeconds uint32
136 if !hints.ModTime.IsZero() {
137 epochSeconds = uint32(hints.ModTime.Unix())
138 }
139 return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds)
140}
141
142// intersectPreferences mutates and returns a prefix of a that contains only
143// the values in the intersection of a and b. The order of a is preserved.
144func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
145 var j int
146 for _, v := range a {
147 for _, v2 := range b {
148 if v == v2 {
149 a[j] = v
150 j++
151 break
152 }
153 }
154 }
155
156 return a[:j]
157}
158
159func hashToHashId(h crypto.Hash) uint8 {
160 v, ok := s2k.HashToHashId(h)
161 if !ok {
162 panic("tried to convert unknown hash")
163 }
164 return v
165}
166
167// Encrypt encrypts a message to a number of recipients and, optionally, signs
168// it. hints contains optional information, that is also encrypted, that aids
169// the recipients in processing the message. The resulting WriteCloser must
170// be closed after the contents of the file have been written.
171// If config is nil, sensible defaults will be used.
172func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
173 var signer *packet.PrivateKey
174 if signed != nil {
175 signKey, ok := signed.signingKey(config.Now())
176 if !ok {
177 return nil, errors.InvalidArgumentError("no valid signing keys")
178 }
179 signer = signKey.PrivateKey
180 if signer == nil {
181 return nil, errors.InvalidArgumentError("no private key in signing key")
182 }
183 if signer.Encrypted {
184 return nil, errors.InvalidArgumentError("signing key must be decrypted")
185 }
186 }
187
188 // These are the possible ciphers that we'll use for the message.
189 candidateCiphers := []uint8{
190 uint8(packet.CipherAES128),
191 uint8(packet.CipherAES256),
192 uint8(packet.CipherCAST5),
193 }
194 // These are the possible hash functions that we'll use for the signature.
195 candidateHashes := []uint8{
196 hashToHashId(crypto.SHA256),
197 hashToHashId(crypto.SHA512),
198 hashToHashId(crypto.SHA1),
199 hashToHashId(crypto.RIPEMD160),
200 }
201 // In the event that a recipient doesn't specify any supported ciphers
202 // or hash functions, these are the ones that we assume that every
203 // implementation supports.
204 defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
205 defaultHashes := candidateHashes[len(candidateHashes)-1:]
206
207 encryptKeys := make([]Key, len(to))
208 for i := range to {
209 var ok bool
210 encryptKeys[i], ok = to[i].encryptionKey(config.Now())
211 if !ok {
212 return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
213 }
214
215 sig := to[i].primaryIdentity().SelfSignature
216
217 preferredSymmetric := sig.PreferredSymmetric
218 if len(preferredSymmetric) == 0 {
219 preferredSymmetric = defaultCiphers
220 }
221 preferredHashes := sig.PreferredHash
222 if len(preferredHashes) == 0 {
223 preferredHashes = defaultHashes
224 }
225 candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
226 candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
227 }
228
229 if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
230 return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
231 }
232
233 cipher := packet.CipherFunction(candidateCiphers[0])
234 // If the cipher specified by config is a candidate, we'll use that.
235 configuredCipher := config.Cipher()
236 for _, c := range candidateCiphers {
237 cipherFunc := packet.CipherFunction(c)
238 if cipherFunc == configuredCipher {
239 cipher = cipherFunc
240 break
241 }
242 }
243
244 var hash crypto.Hash
245 for _, hashId := range candidateHashes {
246 if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() {
247 hash = h
248 break
249 }
250 }
251
252 // If the hash specified by config is a candidate, we'll use that.
253 if configuredHash := config.Hash(); configuredHash.Available() {
254 for _, hashId := range candidateHashes {
255 if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash {
256 hash = h
257 break
258 }
259 }
260 }
261
262 if hash == 0 {
263 hashId := candidateHashes[0]
264 name, ok := s2k.HashIdToString(hashId)
265 if !ok {
266 name = "#" + strconv.Itoa(int(hashId))
267 }
268 return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
269 }
270
271 symKey := make([]byte, cipher.KeySize())
272 if _, err := io.ReadFull(config.Random(), symKey); err != nil {
273 return nil, err
274 }
275
276 for _, key := range encryptKeys {
277 if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil {
278 return nil, err
279 }
280 }
281
282 encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config)
283 if err != nil {
284 return
285 }
286
287 if signer != nil {
288 ops := &packet.OnePassSignature{
289 SigType: packet.SigTypeBinary,
290 Hash: hash,
291 PubKeyAlgo: signer.PubKeyAlgo,
292 KeyId: signer.KeyId,
293 IsLast: true,
294 }
295 if err := ops.Serialize(encryptedData); err != nil {
296 return nil, err
297 }
298 }
299
300 if hints == nil {
301 hints = &FileHints{}
302 }
303
304 w := encryptedData
305 if signer != nil {
306 // If we need to write a signature packet after the literal
307 // data then we need to stop literalData from closing
308 // encryptedData.
309 w = noOpCloser{encryptedData}
310
311 }
312 var epochSeconds uint32
313 if !hints.ModTime.IsZero() {
314 epochSeconds = uint32(hints.ModTime.Unix())
315 }
316 literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
317 if err != nil {
318 return nil, err
319 }
320
321 if signer != nil {
322 return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil
323 }
324 return literalData, nil
325}
326
327// signatureWriter hashes the contents of a message while passing it along to
328// literalData. When closed, it closes literalData, writes a signature packet
329// to encryptedData and then also closes encryptedData.
330type signatureWriter struct {
331 encryptedData io.WriteCloser
332 literalData io.WriteCloser
333 hashType crypto.Hash
334 h hash.Hash
335 signer *packet.PrivateKey
336 config *packet.Config
337}
338
339func (s signatureWriter) Write(data []byte) (int, error) {
340 s.h.Write(data)
341 return s.literalData.Write(data)
342}
343
344func (s signatureWriter) Close() error {
345 sig := &packet.Signature{
346 SigType: packet.SigTypeBinary,
347 PubKeyAlgo: s.signer.PubKeyAlgo,
348 Hash: s.hashType,
349 CreationTime: s.config.Now(),
350 IssuerKeyId: &s.signer.KeyId,
351 }
352
353 if err := sig.Sign(s.h, s.signer, s.config); err != nil {
354 return err
355 }
356 if err := s.literalData.Close(); err != nil {
357 return err
358 }
359 if err := sig.Serialize(s.encryptedData); err != nil {
360 return err
361 }
362 return s.encryptedData.Close()
363}
364
365// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
366// TODO: we have two of these in OpenPGP packages alone. This probably needs
367// to be promoted somewhere more common.
368type noOpCloser struct {
369 w io.Writer
370}
371
372func (c noOpCloser) Write(data []byte) (n int, err error) {
373 return c.w.Write(data)
374}
375
376func (c noOpCloser) Close() error {
377 return nil
378}