go-gpgmime/encrypted.go

103 lines
2.1 KiB
Go

// Implements MIME security with OpenPGP, as defined in RFC 3156.
package pgpmime
import (
"io"
"mime/multipart"
"net/textproto"
"golang.org/x/crypto/openpgp"
)
// A PGP/MIME encrypter.
type Encrypter struct {
multipart *multipart.Writer
armored io.WriteCloser
encrypted io.WriteCloser
to []*openpgp.Entity
signed *openpgp.Entity
opened bool
}
// Write control information and create encrypted part.
func (ew *Encrypter) open() (err error) {
// Create control information
h := make(textproto.MIMEHeader)
h.Add("Content-Type", "application/pgp-encrypted")
hw, err := ew.multipart.CreatePart(h)
if err != nil {
return
}
if _, err = io.WriteString(hw, "Version: 1\r\n"); err != nil {
return
}
// Create body part
h = make(textproto.MIMEHeader)
h.Add("Content-Type", "application/octet-stream")
h.Add("Content-Disposition", "inline")
bw, err := ew.multipart.CreatePart(h)
if err != nil {
return
}
// Create encrypted part
if ew.armored, err = EncodeArmoredMessage(bw); err != nil {
return
}
if ew.encrypted, err = openpgp.Encrypt(ew.armored, ew.to, ew.signed, nil, nil); err != nil {
return
}
return
}
// Write encrypted data.
func (ew *Encrypter) Write(b []byte) (n int, err error) {
// Make sure parts required at the begining of the message have been written
if !ew.opened {
if err = ew.open(); err != nil {
return
}
ew.opened = true
}
return ew.encrypted.Write(b)
}
// Finish the PGP/MIME message.
func (ew *Encrypter) Close() (err error) {
if !ew.opened {
if err = ew.open(); err != nil {
return
}
ew.opened = true
}
if err = ew.encrypted.Close(); err != nil {
return
}
if err = ew.armored.Close(); err != nil {
return
}
err = ew.multipart.Close()
return
}
// Get the Content-Type of this PGP/MIME message.
func (ew *Encrypter) ContentType() string {
return "multipart/encrypted; boundary=" + ew.multipart.Boundary() + "; protocol=\"application/pgp-encrypted\""
}
// Create a new PGP/MIME encrypter.
func NewEncrypter(w io.Writer, to []*openpgp.Entity, signed *openpgp.Entity) *Encrypter {
return &Encrypter{
multipart: multipart.NewWriter(w),
to: to,
signed: signed,
}
}