Skip to content

Commit

Permalink
Add new output format: "signify"
Browse files Browse the repository at this point in the history
This is BSD tool used to sign release, with simpler interface and
without support of old key types. It does not do encryption.

This is how signify can be used:

  $ signify -G -n -p new.pub -s new.key
  $ signify -S -s new.key -m message.txt # creates message.txt.sig
  $ signify -V -p new.pub -m message.txt # checks signature

Now first step can be replaced with:

  $ passphrase2pgp -f signify >new.combined

First two lines are the public key, and the next two are the secret key.
Note: signify(1) insists each begins with "untrusted comment: ".

Co-Authored: Christopher Wellons <[email protected]>
  • Loading branch information
Dmitry Bogatov authored and skeeto committed Mar 20, 2023
1 parent 4d2a7bb commit ed7f62f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 4 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Use `--help` (`-h`) for a full option listing:
```
Usage:
passphrase2pgp <-u id|-l key> [-hv] [-c id] [-i pwfile] [--pinentry[=cmd]]
-K [-anps] [-e[n]] [-f pgp|ssh|x509] [-r n] [-t secs] [-x[spec]]
-K [-anps] [-e[n]] [-f pgp|ssh|x509|signify] [-r n] [-t secs] [-x[spec]]
-S [-a] [-r n] [files...]
-T [-r n] >doc-signed.txt <doc.txt
Commands:
Expand All @@ -74,7 +74,7 @@ Options:
-a, --armor encode output in ASCII armor
-c, --check KEYID require last Key ID bytes to match
-e, --protect[=ASKS] protect private key with S2K
-f, --format pgp|ssh|x509 select key format [pgp]
-f, --format FORMAT select key format [pgp]
-h, --help print this help message
-i, --input FILE read passphrase from file
-l, --load FILE load key from file instead of generating
Expand Down
55 changes: 53 additions & 2 deletions passphrase2pgp.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"bytes"
"crypto/ed25519"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/hex"
stdpem "encoding/pem"
"fmt"
Expand Down Expand Up @@ -40,6 +42,7 @@ const (
formatPGP = iota
formatSSH
formatX509
formatSignify
)

var version = "1.2.0"
Expand Down Expand Up @@ -137,7 +140,7 @@ func usage(w io.Writer) {
}
f("Usage:")
f(i, p, "<-u id|-l key> [-hv] [-c id] [-i pwfile] [--pinentry[=cmd]]")
f(b, "-K [-anps] [-e[n]] [-f pgp|ssh|x509] [-r n] [-t secs] [-x[spec]]")
f(b, "-K [-anps] [-e[n]] [-f pgp|ssh|x509|signify] [-r n] [-t secs] [-x[spec]]")
f(b, "-S [-a] [-r n] [files...]")
f(b, "-T [-r n] >doc-signed.txt <doc.txt")
f("Commands:")
Expand All @@ -148,7 +151,7 @@ func usage(w io.Writer) {
f(i, "-a, --armor encode output in ASCII armor")
f(i, "-c, --check KEYID require last Key ID bytes to match")
f(i, "-e, --protect[=ASKS] protect private key with S2K")
f(i, "-f, --format pgp|ssh|x509 select key format [pgp]")
f(i, "-f, --format FORMAT select key format [pgp]")
f(i, "-h, --help print this help message")
f(i, "-i, --input FILE read passphrase from file")
f(i, "-l, --load FILE load key from file instead of generating")
Expand Down Expand Up @@ -270,6 +273,8 @@ func parse() *config {
conf.format = formatSSH
case "x509":
conf.format = formatX509
case "signify":
conf.format = formatSignify
default:
fatal("invalid format: %s", result.Optarg)
}
Expand Down Expand Up @@ -537,6 +542,8 @@ func main() {
ck.outputSSH(config)
case formatX509:
ck.outputX509(config)
case formatSignify:
ck.outputSignify(config)
}

case cmdSign:
Expand Down Expand Up @@ -718,6 +725,50 @@ func (k *completeKey) outputSSH(config *config) {
}
}

func (k *completeKey) outputSignify(config *config) {
key := k.key

pubkeyHash := sha512.Sum512([]byte(key.Pubkey()))
keynum := pubkeyHash[0:8]

salt := pubkeyHash[8:24]
output := bufio.NewWriter(os.Stdout)

// https://github.com/aperezdc/signify/blob/7960f78/signify.c#L62
output.WriteString("untrusted comment: signify public key for ")
output.Write(k.userid.ID)
output.WriteRune('\n')
pubkey := base64.NewEncoder(base64.StdEncoding, output)
pubkey.Write([]byte("Ed"))
pubkey.Write(keynum)
pubkey.Write(key.Pubkey())
pubkey.Close()
output.WriteRune('\n')

if !config.public {
hash := sha512.Sum512(key.Key)

// https://github.com/aperezdc/signify/blob/7960f78/signify.c#L52
output.WriteString("untrusted comment: signify private key for ")
output.Write(k.userid.ID)
output.WriteRune('\n')
privkey := base64.NewEncoder(base64.StdEncoding, output)
privkey.Write([]byte("Ed")) // pkalg
privkey.Write([]byte("BK")) // kdfalg
privkey.Write([]byte{0, 0, 0, 0}) // kdfrounds
privkey.Write(salt) // salt
privkey.Write(hash[0:8]) // checksum
privkey.Write(keynum) // keynum
privkey.Write(key.Key) // seckey (64 bytes)
privkey.Close()
output.WriteRune('\n')
}

if err := output.Flush(); err != nil {
fatal("%s", err)
}
}

func (k *completeKey) outputX509(config *config) {
key := k.key
uid := string(k.userid.ID)
Expand Down

0 comments on commit ed7f62f

Please sign in to comment.