diff options
Diffstat (limited to 'src/pkg/crypto/openpgp/write.go')
| -rw-r--r-- | src/pkg/crypto/openpgp/write.go | 104 |
1 files changed, 97 insertions, 7 deletions
diff --git a/src/pkg/crypto/openpgp/write.go b/src/pkg/crypto/openpgp/write.go index a7e9332c13..9884472ce7 100644 --- a/src/pkg/crypto/openpgp/write.go +++ b/src/pkg/crypto/openpgp/write.go @@ -12,6 +12,7 @@ import ( "crypto/openpgp/s2k" "crypto/rand" _ "crypto/sha256" + "hash" "io" "os" "strconv" @@ -144,11 +145,18 @@ func hashToHashId(h crypto.Hash) uint8 { } // Encrypt encrypts a message to a number of recipients and, optionally, signs -// it. (Note: signing is not yet implemented.) hints contains optional -// information, that is also encrypted, that aids the recipients in processing -// the message. The resulting WriteCloser must be closed after the contents of -// the file have been written. +// it. hints contains optional information, that is also encrypted, that aids +// the recipients in processing the message. The resulting WriteCloser must +// be closed after the contents of the file have been written. func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err os.Error) { + var signer *packet.PrivateKey + if signed != nil { + signer = signed.signingKey().PrivateKey + if signer == nil || signer.Encrypted { + return nil, error.InvalidArgumentError("signing key must be decrypted") + } + } + // These are the possible ciphers that we'll use for the message. candidateCiphers := []uint8{ uint8(packet.CipherAES128), @@ -194,7 +202,7 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } cipher := packet.CipherFunction(candidateCiphers[0]) - // hash := s2k.HashIdToHash(candidateHashes[0]) + hash, _ := s2k.HashIdToHash(candidateHashes[0]) symKey := make([]byte, cipher.KeySize()) if _, err := io.ReadFull(rand.Reader, symKey); err != nil { return nil, err @@ -206,13 +214,95 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } } - w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey) + encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey) if err != nil { return } + if signer != nil { + ops := &packet.OnePassSignature{ + SigType: packet.SigTypeBinary, + Hash: hash, + PubKeyAlgo: signer.PubKeyAlgo, + KeyId: signer.KeyId, + IsLast: true, + } + if err := ops.Serialize(encryptedData); err != nil { + return nil, err + } + } + if hints == nil { hints = &FileHints{} } - return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) + + w := encryptedData + if signer != nil { + // If we need to write a signature packet after the literal + // data then we need to stop literalData from closing + // encryptedData. + w = noOpCloser{encryptedData} + + } + literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) + if err != nil { + return nil, err + } + + if signer != nil { + return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil + } + return literalData, nil +} + +// signatureWriter hashes the contents of a message while passing it along to +// literalData. When closed, it closes literalData, writes a signature packet +// to encryptedData and then also closes encryptedData. +type signatureWriter struct { + encryptedData io.WriteCloser + literalData io.WriteCloser + hashType crypto.Hash + h hash.Hash + signer *packet.PrivateKey +} + +func (s signatureWriter) Write(data []byte) (int, os.Error) { + s.h.Write(data) + return s.literalData.Write(data) +} + +func (s signatureWriter) Close() os.Error { + sig := &packet.Signature{ + SigType: packet.SigTypeBinary, + PubKeyAlgo: s.signer.PubKeyAlgo, + Hash: s.hashType, + CreationTime: uint32(time.Seconds()), + IssuerKeyId: &s.signer.KeyId, + } + + if err := sig.Sign(s.h, s.signer); err != nil { + return err + } + if err := s.literalData.Close(); err != nil { + return err + } + if err := sig.Serialize(s.encryptedData); err != nil { + return err + } + return s.encryptedData.Close() +} + +// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. +// TODO: we have two of these in OpenPGP packages alone. This probably needs +// to be promoted somewhere more common. +type noOpCloser struct { + w io.Writer +} + +func (c noOpCloser) Write(data []byte) (n int, err os.Error) { + return c.w.Write(data) +} + +func (c noOpCloser) Close() os.Error { + return nil } |
