package main import ( "flag" "fmt" "io/ioutil" "log" "dim13.org/signify/ask" "dim13.org/signify/bhash" "dim13.org/signify/file" "dim13.org/signify/key" ) /* signify -C [-q] -p pubkey -x sigfile [file ...] signify -G [-n] [-c comment] -p pubkey -s seckey signify -S [-ez] [-x sigfile] -s seckey -m message signify -V [-eqz] [-p pubkey] [-t keytype] [-x sigfile] -m message */ const safePath = "/etc/signify" var ( checksum = flag.Bool("C", false, "Verify a signed checksum list") generate = flag.Bool("G", false, "Generate a new key pair") sign = flag.Bool("S", false, "Sign the specfied message") verify = flag.Bool("V", false, "Verify the message") comment = flag.String("c", "signify", "Comment") embed = flag.Bool("e", false, "Embed the message") msg = flag.String("m", "", "Message file") nopass = flag.Bool("n", false, "No key passphrase") pub = flag.String("p", "", "Public key file") quiet = flag.Bool("q", false, "Quiet mode") sec = flag.String("s", "", "Secret key file") sig = flag.String("x", "", "Signature file") gzip = flag.Bool("z", false, "Sign and verify gzip archives") ) func main() { flag.Parse() switch { case *generate: if err := Generate(*pub, *sec, *comment, *nopass); err != nil { log.Fatal(err) } case *sign: if err := Sign(*msg, *sec, *embed); err != nil { log.Fatal(err) } case *verify: if err := Verify(*msg, *pub); err != nil { log.Fatal(err) } default: flag.Usage() } } func Generate(pubFile, encFile, comment string, nopass bool) error { if err := file.Names(pubFile, encFile); err != nil { return err } pubKey, encKey, err := key.NewKey() if err != nil { return err } if nopass { encKey.KDFRounds = 0 } if err := Kdf(encKey, ask.Confirmed); err != nil { return err } encRaw, err := key.Marshal(encKey) if err != nil { return err } block := &file.Block{ Comment: fmt.Sprintf("%s secret key", comment), Bytes: encRaw, } if err := file.EncodeFile(encFile, file.EncMode, block); err != nil { return err } pubRaw, err := key.Marshal(pubKey) if err != nil { return err } block = &file.Block{ Comment: fmt.Sprintf("%s public key", comment), Bytes: pubRaw, } if err := file.EncodeFile(pubFile, file.PubMode, block); err != nil { return err } return nil } func OpenEnc(fname string) (*key.Enc, error) { block, err := file.DecodeFile(fname) if err != nil { return nil, err } encKey := new(key.Enc) if err := key.Unmarshal(block.Bytes, encKey); err != nil { return nil, err } if err := Kdf(encKey, ask.Password); err != nil { return nil, err } if err := encKey.Check(); err != nil { return nil, err } return encKey, nil } func OpenPub(fname string) (*key.Pub, error) { block, err := file.DecodeFile(fname) if err != nil { return nil, err } pubKey := new(key.Pub) if err := key.Unmarshal(block.Bytes, pubKey); err != nil { return nil, err } if err := pubKey.Check(); err != nil { return nil, err } return pubKey, nil } func OpenSig(fname string) (*key.Sig, []byte, error) { block, err := file.DecodeFile(fname + ".sig") if err != nil { return nil, nil, err } sig := new(key.Sig) if err := key.Unmarshal(block.Bytes, sig); err != nil { return nil, nil, err } if err := sig.Check(); err != nil { return nil, nil, err } if len(block.Message) > 0 { return sig, block.Message, nil } msg, err := ioutil.ReadFile(fname) if err != nil { return nil, nil, err } return sig, msg, nil } func Sign(msgFile, encFile string, embed bool) error { encKey, err := OpenEnc(encFile) if err != nil { return err } body, err := ioutil.ReadFile(msgFile) if err != nil { return err } sig := encKey.Sign(body) sigRaw, err := key.Marshal(sig) if err != nil { return err } block := &file.Block{ Comment: fmt.Sprintf("verify with %s", file.PubName(encFile)), Bytes: sigRaw, } if embed { block.Message = body } if err := file.EncodeFile(msgFile+".sig", file.SigMode, block); err != nil { return err } return nil } func Verify(msgFile, pubFile string) error { pubKey, err := OpenPub(pubFile) if err != nil { return err } sig, body, err := OpenSig(msgFile) if err != nil { return err } if err := pubKey.Verify(body, sig); err != nil { return err } log.Println("Signature Verfied") return nil } func Kdf(enc *key.Enc, ask func() (string, error)) error { if enc.KDFRounds == 0 { return nil } pass, err := ask() if err != nil { return err } xor := bhash.Pbkdf([]byte(pass), enc.Salt[:], int(enc.KDFRounds), len(enc.Key)) for i := range xor { enc.Key[i] ^= xor[i] } return nil }