package signify import ( "bufio" "bytes" "encoding/base64" "errors" "fmt" "io" "io/ioutil" "os" "strings" ) type EncFile struct { Comment string Key *EncKey } type PubFile struct { Comment string Key *PubKey } type SigFile struct { Comment string Sig *Sig Message []byte } type File struct { Comment string RawKey []byte Message []byte } const ( commentHdr = "untrusted comment:" sigFrom = "signature from %s" ) var ( ErrCommentSize = errors.New("comment line to long") ErrUntrustedComment = errors.New("expected untrusted comment") ) func checkComment(comment string) error { // compatibility with original version if len(comment) > 1024 { return ErrCommentSize } if !strings.HasPrefix(comment, commentHdr) { return ErrUntrustedComment } return nil } func (f *File) Embedded() bool { return len(f.Message) > 0 } func read(r io.Reader) (string, []byte, []byte, error) { buf := bufio.NewReader(r) comment, err := buf.ReadString('\n') if err != nil { return "", nil, nil, err } if err := checkComment(comment); err != nil { return "", nil, nil, err } comment = strings.TrimSpace(comment[len(commentHdr):]) raw, err := buf.ReadString('\n') if err != nil { return "", nil, nil, err } rawKey, err := base64.StdEncoding.DecodeString(raw) if err != nil { return "", nil, nil, err } message, err := ioutil.ReadAll(buf) if err != nil { return "", nil, nil, err } return comment, rawKey, message, nil } func (f *File) ReadFrom(r io.Reader) (err error) { f.Comment, f.RawKey, f.Message, err = read(r) if err != nil { return err } return nil } func Parse(b []byte) (*File, error) { r := bytes.NewReader(b) f := new(File) return f, f.ReadFrom(r) } func ParseFile(fname string) (*File, error) { fd, err := os.Open(fname) if err != nil { return nil, err } defer fd.Close() f := new(File) return f, f.ReadFrom(fd) } func (f File) Bytes() ([]byte, error) { buf := new(bytes.Buffer) err := f.WriteTo(buf) if err != nil { return nil, err } return buf.Bytes(), nil } func write(w io.Writer, comment string, key, message []byte) error { fmt.Fprintln(w, commentHdr, comment) fmt.Fprintln(w, base64.StdEncoding.EncodeToString(key)) if message != nil { w.Write(message) } return nil } func (f File) WriteTo(w io.Writer) error { return write(w, f.Comment, f.RawKey, f.Message) } const ( SecMode os.FileMode = 0600 PubMode os.FileMode = 0644 ) func (f File) WriteFile(fname string, perm os.FileMode) error { fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, perm) if err != nil { return err } defer fd.Close() return f.WriteTo(fd) }