First commit

This commit is contained in:
emersion 2016-06-06 22:55:15 +02:00
parent f292f9b79f
commit e40281a273
2 changed files with 134 additions and 0 deletions

102
encrypted.go Normal file
View File

@ -0,0 +1,102 @@
// 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,
}
}

32
message.go Normal file
View File

@ -0,0 +1,32 @@
package pgpmime
import (
"errors"
"io"
"golang.org/x/crypto/openpgp/armor"
)
// Armored type for PGP encrypted messages.
const MessageType = "PGP MESSAGE"
// Encode a PGP message armor.
func EncodeArmoredMessage(w io.Writer) (io.WriteCloser, error) {
return armor.Encode(w, MessageType, nil)
}
// Decode an armored PGP message.
func DecodeArmoredMessage(in io.Reader) (out io.Reader, err error) {
block, err := armor.Decode(in)
if err != nil {
return
}
if block.Type != MessageType {
err = errors.New("Not an armored PGP message")
return
}
out = block.Body
return
}