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