package signify import ( "bufio" "bytes" "encoding/base64" "errors" "fmt" "io" "io/ioutil" "os" "strings" "dim13.org/signify/sig" ) type File struct { Comment string RawKey []byte Message []byte } const commentHdr = "untrusted comment:" 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) } //////////////////////////////////////////////////////////////////////// func WriteEnc(fname, comment string, key *EncKey) error { fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, SecMode) if err != nil { return err } defer fd.Close() b, err := Marshal(key) if err != nil { return err } block := &sig.Block{ Comment: comment + " secret key", Bytes: b, } return sig.Encode(fd, block) } func WritePub(fname, comment string, key *PubKey) error { fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, PubMode) if err != nil { return err } defer fd.Close() b, err := Marshal(key) if err != nil { return err } block := &sig.Block{ Comment: comment + " public key", Bytes: b, } return sig.Encode(fd, block) } func WriteSig(fname, comment string, message []byte, key *Sig) error { fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, PubMode) if err != nil { return err } defer fd.Close() b, err := Marshal(key) if err != nil { return err } block := &sig.Block{ Comment: "verify with " + comment, Bytes: b, Message: message, } return sig.Encode(fd, block) } //////////////////////////////////////////////////////////////////////// func OpenEnc(fname string) (*EncKey, error) { block, err := sig.DecodeFile(fname) if err != nil { return nil, err } key := new(EncKey) if err := Unmarshal(block.Bytes, key); err != nil { return nil, err } return key, nil } func OpenPub(fname string) (*PubKey, error) { block, err := sig.DecodeFile(fname) if err != nil { return nil, err } key := new(PubKey) if err := Unmarshal(block.Bytes, key); err != nil { return nil, err } return key, nil } func OpenSig(fname string) (*Sig, error) { block, err := sig.DecodeFile(fname) if err != nil { return nil, err } key := new(Sig) if err := Unmarshal(block.Bytes, key); err != nil { return nil, err } return key, nil }