// Package file implements signify file format package file import ( "bufio" "encoding" "encoding/base64" "errors" "fmt" "io" "io/ioutil" "os" "strings" ) const ( ModeSec os.FileMode = 0600 ModePub os.FileMode = 0644 ModeSig os.FileMode = 0644 untrusted = "untrusted comment:" ) var ErrComment = errors.New("expected untrusted comment") // block represents a encoded signify key or signature // // The encoded form is: // untrusted comment: comment // base64-encoded key // optional message type block struct { Comment string Bytes []byte Message []byte // TODO replace with io.ReadCloser } func decodeBlock(r io.Reader) (*block, error) { buf := bufio.NewReader(r) comment, err := buf.ReadString('\n') if err != nil { return nil, err } if !strings.HasPrefix(comment, untrusted) { return nil, ErrComment } raw, err := buf.ReadString('\n') if err != nil { return nil, err } b, err := base64.StdEncoding.DecodeString(raw) if err != nil { return nil, err } message, err := ioutil.ReadAll(buf) if err != nil { return nil, err } return &block{ Comment: strings.TrimSpace(comment[len(untrusted):]), Bytes: b, Message: message, }, nil } func DecodeFile(fname string, u encoding.BinaryUnmarshaler) (string, []byte, error) { fd, err := os.Open(fname) if err != nil { return "", nil, err } defer fd.Close() return Decode(fd, u) } func Decode(r io.Reader, u encoding.BinaryUnmarshaler) (string, []byte, error) { block, err := decodeBlock(r) if err != nil { return "", nil, err } if err := u.UnmarshalBinary(block.Bytes); err != nil { return "", nil, err } return block.Comment, block.Message, nil } func encodeBlock(w io.Writer, b *block) error { fmt.Fprintln(w, untrusted, b.Comment) fmt.Fprintln(w, base64.StdEncoding.EncodeToString(b.Bytes)) w.Write(b.Message) return nil } func EncodeFile(fname string, perm os.FileMode, u encoding.BinaryMarshaler, comment string, msg []byte) error { fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) if err != nil { return err } defer fd.Close() return Encode(fd, u, comment, msg) } func Encode(w io.Writer, u encoding.BinaryMarshaler, comment string, msg []byte) error { raw, err := u.MarshalBinary() if err != nil { return err } b := &block{ Comment: comment, Bytes: raw, Message: msg, } return encodeBlock(w, b) }