From a669acbda2c69a85a03d0e638f20e5bc89cd96de9feb4fb77ea5cbe52b89cab8 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 19 Feb 2025 17:49:17 +0300 Subject: [PATCH] More djb-style keys passing http://libpqcrypto.org/command.html --- go/cm/cmd/enctool/main.go | 110 +++++++++++++++++------------ go/cm/cmd/enctool/passphrase.t | 7 +- go/cm/cmd/enctool/prv-encrypted.t | 12 ++-- go/cm/cmd/enctool/pub.t | 37 +++++----- go/cm/cmd/enctool/usage.go | 8 +-- go/cm/cmd/keytool/certification.t | 60 ++++++++-------- go/cm/cmd/keytool/kem-generation.t | 3 +- go/cm/cmd/keytool/main.go | 89 +++++++++++------------ go/cm/cmd/keytool/usage.go | 12 ++-- go/cm/cmd/sigtool/basic.t | 29 ++++---- go/cm/cmd/sigtool/main.go | 28 ++++---- go/cm/cmd/sigtool/usage.go | 8 +-- go/cm/sign/pub.go | 3 + 13 files changed, 211 insertions(+), 195 deletions(-) diff --git a/go/cm/cmd/enctool/main.go b/go/cm/cmd/enctool/main.go index 7b152ac..2eeceb5 100644 --- a/go/cm/cmd/enctool/main.go +++ b/go/cm/cmd/enctool/main.go @@ -50,6 +50,11 @@ import ( "go.cypherpunks.su/keks/types" ) +const ( + FdPubR = 4 + FdPrvR = 8 +) + func blake2bHash() hash.Hash { h, err := blake2b.New512(nil) if err != nil { @@ -58,16 +63,8 @@ func blake2bHash() hash.Hash { return h } -func mustReadFile(p string) []byte { - data, err := os.ReadFile(p) - if err != nil { - log.Fatalln("read:", p, err) - } - return data -} - func readPasswd(prompt string) (passwd []byte) { - if raw := os.Getenv("ENCTOOL_PASSPHRASE"); raw != "" { + if raw := os.Getenv("CMENCTOOL_PASSPHRASE"); raw != "" { return []byte(raw) } tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) @@ -90,8 +87,7 @@ func readPasswd(prompt string) (passwd []byte) { return } -func readPrv(pth string) (*cm.AV, error) { - data := mustReadFile(pth) +func parsePrv(data []byte) (av cm.AV, tail []byte, err error) { var magic keks.Magic magic, data = keks.StripMagic(data) switch magic { @@ -100,31 +96,35 @@ func readPrv(pth string) (*cm.AV, error) { var encrypted cmenc.Encrypted { d := keks.NewDecoderFromBytes(data, nil) - if err := d.DecodeStruct(&encrypted); err != nil { - return nil, err + err = d.DecodeStruct(&encrypted) + if err != nil { + return } } if encrypted.DEM.A != cmenc.ChaCha20Poly1305 { - return nil, errors.New("unsupported prv encryption DEM") + err = errors.New("unsupported prv encryption DEM") + return } if len(encrypted.KEM) != 1 || encrypted.KEM[0].A != cmballoon.BalloonBLAKE2bHKDF || len(encrypted.Payload) == 0 { - return nil, errors.New("wrong prv encryption KEM") + err = errors.New("wrong prv encryption KEM") + return } - passwd := readPasswd("Passphrase for " + pth + ":") - cek, err := cmballoon.Decapsulate( + passwd := readPasswd("Passphrase for private key:") + var cek []byte + cek, err = cmballoon.Decapsulate( encrypted.KEM[0], encrypted.Salt[:], passwd, ) if err != nil { - return nil, err + return } var buf bytes.Buffer _, err = chaPoly.Open(&buf, bytes.NewReader(encrypted.Payload), cek, 1) if err != nil { - return nil, err + return } data = buf.Bytes() magic, data = keks.StripMagic(data) @@ -133,11 +133,13 @@ func readPrv(pth string) (*cm.AV, error) { } fallthrough default: - return nil, errors.New("wrong magic") + err = errors.New("wrong magic") + return } - var av cm.AV d := keks.NewDecoderFromBytes(data, &keks.DecodeOpts{MaxStrLen: 1 << 16}) - return &av, d.DecodeStruct(&av) + err = d.DecodeStruct(&av) + tail = d.B + return } func main() { @@ -152,37 +154,51 @@ func main() { doDecrypt := flag.Bool("d", false, "Decrypt") parallel := flag.Int("parallel", runtime.NumCPU(), "Parallel cryptors") noblob := flag.Bool("no-stream", false, "Include payload into container") + flag.Parse() + + fdPubR := os.NewFile(FdPubR, "pub-in") var pubs []cm.AV var pubIds []uuid.UUID - flag.Func("pub", "Path to public key to encrypt to", func(v string) error { - signed, _, err := sign.PubParse(mustReadFile(v)) - if err != nil { - return err - } - load := signed.PubLoad() - if load.KU == nil { - log.Println(v, "does not have key usages") - } else { - if _, ok := (*load.KU)[sign.KUKEM]; !ok { - log.Println(v, "does not have", sign.KUKEM, "key usage") + if data, err := io.ReadAll(fdPubR); err == nil { + for len(data) > 0 { + var signed *sign.Signed + signed, data, err = sign.PubParse(data) + if err != nil { + log.Fatalln("public key:", len(pubs), ":", err) } + load := signed.PubLoad() + if load.KU == nil { + log.Println("public key:", len(pubs), ": does not have key usages") + } else { + if _, ok := (*load.KU)[sign.KUKEM]; !ok { + log.Println( + "public key:", len(pubs), ": does not have", + sign.KUKEM, "key usage", + ) + } + } + if len(load.Pub) != 1 { + log.Fatalln("public key:", len(pubs), ": expected single public key") + } + pubs = append(pubs, load.Pub[0]) + pubIds = append(pubIds, load.Id) } - if len(load.Pub) != 1 { - return errors.New("expected single public key") - } - pubs = append(pubs, load.Pub[0]) - pubIds = append(pubIds, load.Id) - return err - }) + } + fdPubR.Close() + + fdPrvR := os.NewFile(FdPrvR, "prv-in") var prvs []*cm.AV - flag.Func("prv", "Our private keys for decryption", func(v string) error { - av, err := readPrv(v) - if err == nil { - prvs = append(prvs, av) + if data, err := io.ReadAll(fdPrvR); err == nil { + for len(data) > 0 { + var av cm.AV + av, data, err = parsePrv(data) + if err != nil { + log.Fatalln("private key:", len(prvs), ":", err) + } + prvs = append(prvs, &av) } - return err - }) - flag.Parse() + } + fdPrvR.Close() var err error var cek []byte diff --git a/go/cm/cmd/enctool/passphrase.t b/go/cm/cmd/enctool/passphrase.t index 66506de..f738873 100755 --- a/go/cm/cmd/enctool/passphrase.t +++ b/go/cm/cmd/enctool/passphrase.t @@ -6,10 +6,11 @@ test_description="Check passphrase encryption" TMPDIR=${TMPDIR:-/tmp} dd if=/dev/urandom of=$TMPDIR/enc.data bs=300K count=1 2>/dev/null -export ENCTOOL_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p) -test_expect_success "encrypting" "cmenctool -p \ +export CMENCTOOL_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p) +balloonparams="-balloon-s 123 -balloon-t 2" +test_expect_success "encrypting" "cmenctool $balloonparams -p \ <$TMPDIR/enc.data >$TMPDIR/enc.enc" -test_expect_success "decrypting" "cmenctool -d -p \ +test_expect_success "decrypting" "cmenctool $balloonparams -d -p \ <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" test_expect_success "comparing" \ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got" diff --git a/go/cm/cmd/enctool/prv-encrypted.t b/go/cm/cmd/enctool/prv-encrypted.t index a621ec7..f7912e8 100755 --- a/go/cm/cmd/enctool/prv-encrypted.t +++ b/go/cm/cmd/enctool/prv-encrypted.t @@ -5,15 +5,15 @@ test_description="Check passphrase-encrypted key decryption" TMPDIR=${TMPDIR:-/tmp} -cmkeytool -algo sntrup4591761-x25519 -ku kem -subj A=KEY \ - -prv $TMPDIR/enc.prv -pub $TMPDIR/enc.pub +cmkeytool -algo sntrup4591761-x25519 -ku kem -subj A=KEY 5>$TMPDIR/enc.pub 9>$TMPDIR/enc.prv dd if=/dev/urandom of=$TMPDIR/enc.data bs=12K count=1 2>/dev/null -export ENCTOOL_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p) -test_expect_success "key encrypting" "cmenctool -p -no-stream \ +export CMENCTOOL_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p) +balloonparams="-balloon-s 123 -balloon-t 2" +test_expect_success "key encrypting" "cmenctool -p -no-stream $balloonparams \ <$TMPDIR/enc.prv >$TMPDIR/enc.prv.enc" -test_expect_success "data encrypting" "cmenctool -pub $TMPDIR/enc.pub \ +test_expect_success "data encrypting" "cmenctool 4<$TMPDIR/enc.pub \ <$TMPDIR/enc.data >$TMPDIR/enc.enc" -test_expect_success "decrypting" "cmenctool -d -prv $TMPDIR/enc.prv.enc \ +test_expect_success "decrypting" "cmenctool -d 8<$TMPDIR/enc.prv.enc \ <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" test_expect_success "comparing" \ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got" diff --git a/go/cm/cmd/enctool/pub.t b/go/cm/cmd/enctool/pub.t index 5d7065d..25560c2 100755 --- a/go/cm/cmd/enctool/pub.t +++ b/go/cm/cmd/enctool/pub.t @@ -6,47 +6,46 @@ test_description="Check public-key encryption" TMPDIR=${TMPDIR:-/tmp} dd if=/dev/urandom of=$TMPDIR/enc.data bs=300K count=1 2>/dev/null +balloonparams="-balloon-s 123 -balloon-t 2" algo=mceliece6960119-x25519 algo0=$algo test_expect_success "$algo: pub generation" "cmkeytool \ -algo $algo -ku kem -subj A=$algo \ - -prv $TMPDIR/enc.$algo.prv -pub $TMPDIR/enc.$algo.pub" + 5>$TMPDIR/enc.$algo.pub 9>$TMPDIR/enc.$algo.prv" algo=sntrup4591761-x25519 algo1=$algo test_expect_success "$algo: pub generation" "cmkeytool \ -algo $algo -ku kem -subj A=$algo \ - -prv $TMPDIR/enc.$algo.prv -pub $TMPDIR/enc.$algo.pub" + 5>$TMPDIR/enc.$algo.pub 9>$TMPDIR/enc.$algo.prv" -test_expect_success "encrypting" "cmenctool \ - -pub $TMPDIR/enc.$algo0.pub -pub $TMPDIR/enc.$algo1.pub \ - <$TMPDIR/enc.data >$TMPDIR/enc.enc" +test_expect_success "encrypting" " + cat $TMPDIR/enc.$algo0.pub $TMPDIR/enc.$algo1.pub | + cmenctool 4<&0 <$TMPDIR/enc.data >$TMPDIR/enc.enc" -test_expect_success "any: decrypting" "cmenctool -d \ - -prv $TMPDIR/enc.$algo0.prv -prv $TMPDIR/enc.$algo1.prv \ - <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" +test_expect_success "any: decrypting" " + cat $TMPDIR/enc.$algo0.prv $TMPDIR/enc.$algo1.prv | + cmenctool -d 8<&0 <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" test_expect_success "comparing" \ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got" test_expect_success "$algo0: decrypting" "cmenctool -d \ - -prv $TMPDIR/enc.$algo0.prv \ - <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" + 8<$TMPDIR/enc.$algo0.prv <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" test_expect_success "$algo0: comparing" \ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got" test_expect_success "$algo1: decrypting" "cmenctool -d \ - -prv $TMPDIR/enc.$algo1.prv \ - <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" + 8<$TMPDIR/enc.$algo1.prv <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" test_expect_success "$algo1: comparing" \ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got" -export ENCTOOL_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p) -test_expect_success "encrypting also with passphrase" "cmenctool \ - -pub $TMPDIR/enc.$algo0.pub -pub $TMPDIR/enc.$algo1.pub -p \ - <$TMPDIR/enc.data >$TMPDIR/enc.enc" -test_expect_success "any: decrypting" "cmenctool -d \ - -prv $TMPDIR/enc.$algo0.prv -prv $TMPDIR/enc.$algo1.prv \ - <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" +export CMENCTOOL_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p) +test_expect_success "encrypting also with passphrase" " + cat $TMPDIR/enc.$algo0.pub $TMPDIR/enc.$algo1.pub | + cmenctool $balloonparams -p 4<&0 <$TMPDIR/enc.data >$TMPDIR/enc.enc" +test_expect_success "any: decrypting" " + cat $TMPDIR/enc.$algo0.prv $TMPDIR/enc.$algo1.prv | + cmenctool -d 8<&0 <$TMPDIR/enc.enc >$TMPDIR/enc.data.got" test_expect_success "comparing" \ "test_cmp $TMPDIR/enc.data $TMPDIR/enc.data.got" test_expect_success "passphrase: decrypting" "cmenctool -d -p \ diff --git a/go/cm/cmd/enctool/usage.go b/go/cm/cmd/enctool/usage.go index 655cf38..91aaec4 100644 --- a/go/cm/cmd/enctool/usage.go +++ b/go/cm/cmd/enctool/usage.go @@ -24,11 +24,11 @@ import ( func usage() { fmt.Fprintf(os.Stderr, `Usage: Encrypt to recipient(s): - enctool -pub PUB [-pub ...] [-include-to] DATA.encrypted + cmenctool [-include-to] 4DATA.encrypted Encrypt on passphrase: - enctool -p [-balloon-s X] [-balloon-t X] [-balloon-p X] DATA.encrypted - Decrypt by providing possible KEMs: - enctool -d [-p] [-prv PRV ...] DATA + cmenctool -p [-balloon-s X] [-balloon-t X] [-balloon-p X] DATA.encrypted + Decrypt by providing possible KEMs and/or passphrase(s): + cmenctool -d [-p] 8DATA `) flag.PrintDefaults() diff --git a/go/cm/cmd/keytool/certification.t b/go/cm/cmd/keytool/certification.t index 30f68e9..a97e8b3 100755 --- a/go/cm/cmd/keytool/certification.t +++ b/go/cm/cmd/keytool/certification.t @@ -10,45 +10,49 @@ ed25519-blake2b ed25519-blake2b" | while read caAlgo eeAlgo ; do subj="-subj CN=CA -subj C=RU" test_expect_success "$caAlgo: CA load generation" "cmkeytool \ - -algo $caAlgo \ - -ku sig $subj \ - -prv $TMPDIR/ca.$caAlgo.prv -pub $TMPDIR/ca.$caAlgo.pub" + -algo $caAlgo -ku sig $subj \ + 5>$TMPDIR/ca.$caAlgo.pub 9>$TMPDIR/ca.$caAlgo.prv" test_expect_success "$caAlgo: CA generation" "cmkeytool \ - -pub $TMPDIR/ca.$caAlgo.pub \ - -ca-prv $TMPDIR/ca.$caAlgo.prv -ca-pub $TMPDIR/ca.$caAlgo.pub" + 4<$TMPDIR/ca.$caAlgo.pub \ + 8<$TMPDIR/ca.$caAlgo.prv \ + <$TMPDIR/ca.$caAlgo.pub \ + 5>$TMPDIR/ca.$caAlgo.pub.certified" +mv $TMPDIR/ca.$caAlgo.pub.certified $TMPDIR/ca.$caAlgo.pub test_expect_success "$caAlgo: CA regeneration" "cmkeytool \ - -pub $TMPDIR/ca.$caAlgo.pub \ - -ca-prv $TMPDIR/ca.$caAlgo.prv -ca-pub $TMPDIR/ca.$caAlgo.pub" -test_expect_success "$caAlgo: CA self-signature" "cmkeytool \ - -ca-pub $TMPDIR/ca.$caAlgo.pub \ - -pub $TMPDIR/ca.$caAlgo.pub \ - -verify" + 4<$TMPDIR/ca.$caAlgo.pub \ + 8<$TMPDIR/ca.$caAlgo.prv \ + <$TMPDIR/ca.$caAlgo.pub \ + 5>$TMPDIR/ca.$caAlgo.pub.certified" +mv $TMPDIR/ca.$caAlgo.pub.certified $TMPDIR/ca.$caAlgo.pub +test_expect_success "$caAlgo: CA self-signature" "cmkeytool -verify \ + 4<$TMPDIR/ca.$caAlgo.pub <$TMPDIR/ca.$caAlgo.pub" subj="-subj CN=SubCA -subj C=RU" test_expect_success "$eeAlgo: SubCA load generation" "cmkeytool \ - -algo $eeAlgo \ - -ku sig $subj \ - -prv $TMPDIR/subca.$eeAlgo.prv -pub $TMPDIR/subca.$eeAlgo.pub" + -algo $eeAlgo -ku sig $subj \ + 5>$TMPDIR/subca.$eeAlgo.pub 9>$TMPDIR/subca.$eeAlgo.prv" test_expect_success "$eeAlgo: SubCA generation" "cmkeytool \ - -pub $TMPDIR/subca.$eeAlgo.pub \ - -ca-pub $TMPDIR/ca.$caAlgo.pub -ca-prv $TMPDIR/ca.$caAlgo.prv" -test_expect_success "$eeAlgo: SubCA signature" "cmkeytool \ - -ca-pub $TMPDIR/ca.$caAlgo.pub \ - -pub $TMPDIR/subca.$eeAlgo.pub \ - -verify" + 4<$TMPDIR/ca.$caAlgo.pub \ + 8<$TMPDIR/ca.$caAlgo.prv \ + <$TMPDIR/subca.$eeAlgo.pub \ + 5>$TMPDIR/subca.$eeAlgo.pub.certified" +mv $TMPDIR/subca.$eeAlgo.pub.certified $TMPDIR/subca.$eeAlgo.pub +test_expect_success "$eeAlgo: SubCA signature" "cmkeytool -verify \ + 4<$TMPDIR/ca.$caAlgo.pub <$TMPDIR/subca.$eeAlgo.pub" subj="-subj CN=EE -subj C=RU" test_expect_success "$eeAlgo: EE load generation" "cmkeytool \ -algo $eeAlgo $subj \ - -prv $TMPDIR/ee.$eeAlgo.prv -pub $TMPDIR/ee.$eeAlgo.pub" + 5>$TMPDIR/ee.$eeAlgo.pub 9>$TMPDIR/ee.$eeAlgo.prv" test_expect_success "$eeAlgo: EE generation" "cmkeytool \ - -ca-prv $TMPDIR/subca.$eeAlgo.prv -ca-pub $TMPDIR/subca.$eeAlgo.pub \ - -pub $TMPDIR/ee.$eeAlgo.pub" -test_expect_success "$eeAlgo: EE chain" "cmkeytool \ - -ca-pub $TMPDIR/ca.$caAlgo.pub \ - -ca-pub $TMPDIR/subca.$eeAlgo.pub \ - -pub $TMPDIR/ee.$eeAlgo.pub \ - -verify" + 4<$TMPDIR/subca.$eeAlgo.pub \ + 8<$TMPDIR/subca.$eeAlgo.prv \ + <$TMPDIR/ee.$eeAlgo.pub \ + 5>$TMPDIR/ee.$eeAlgo.pub.certified" +mv $TMPDIR/ee.$eeAlgo.pub.certified $TMPDIR/ee.$eeAlgo.pub +test_expect_success "$eeAlgo: EE chain" " + cat $TMPDIR/ca.$caAlgo.pub $TMPDIR/subca.$eeAlgo.pub | + cmkeytool -verify 4<&0 <$TMPDIR/ee.$eeAlgo.pub" done diff --git a/go/cm/cmd/keytool/kem-generation.t b/go/cm/cmd/keytool/kem-generation.t index 0b18e9c..61c7b3f 100755 --- a/go/cm/cmd/keytool/kem-generation.t +++ b/go/cm/cmd/keytool/kem-generation.t @@ -10,8 +10,7 @@ sntrup4591761-x25519" | while read algo ; do test_expect_success "$algo: generation" "cmkeytool \ -algo $algo \ - -ku kem -subj CN=DH \ - -prv $TMPDIR/kem.$algo.prv -pub $TMPDIR/kem.$algo.pub" + -ku kem -subj CN=DH 5>$TMPDIR/kem.$algo.pub 9>$TMPDIR/kem.$algo.prv" done diff --git a/go/cm/cmd/keytool/main.go b/go/cm/cmd/keytool/main.go index 45acf8c..41a471a 100644 --- a/go/cm/cmd/keytool/main.go +++ b/go/cm/cmd/keytool/main.go @@ -21,6 +21,7 @@ import ( "flag" "fmt" "hash" + "io" "log" "os" "sort" @@ -38,11 +39,19 @@ import ( "go.cypherpunks.su/keks/cm/sign/gost" ) -func mustReadFile(p string) []byte { - data, err := os.ReadFile(p) +const ( + FdPubR = 4 + FdPubW = 5 + FdPrvR = 8 + FdPrvW = 9 +) + +func mustReadAll(r io.ReadCloser) []byte { + data, err := io.ReadAll(r) if err != nil { - log.Fatalln("read:", p, err) + log.Fatal(err) } + r.Close() return data } @@ -70,25 +79,12 @@ func main() { return nil }, ) - var issuingPubs []string - flag.Func( - "ca-pub", - "Add certification public key to the chain", - func(v string) error { - issuingPubs = append(issuingPubs, v) - return nil - }, - ) sinceRaw := flag.String("since", "", "Optional notBefore, \"2006-01-02 15:04:05\" format") lifetime := flag.Uint("lifetime", 365, "Lifetime of the certification, days") algo := flag.String("algo", ed25519blake2b.Ed25519BLAKE2b, "Public key algorithm") - issuingPrv := flag.String("ca-prv", "", - "Path to private key file for issuing with") - prvPath := flag.String("prv", "", "Path to private key file") - pubPath := flag.String("pub", "", "Path to public key file") verify := flag.Bool("verify", false, "Verify provided -pub with -ca-pub") doList := flag.Bool("list-algo", false, "List available algorithms") @@ -110,8 +106,14 @@ func main() { return } - if *pubPath == "" { - log.Fatal("no -pub is set") + fdPubR := os.NewFile(FdPubR, "pub-in") + fdPubW := os.NewFile(FdPubW, "pub-out") + fdPrvR := os.NewFile(FdPrvR, "prv-in") + fdPrvW := os.NewFile(FdPrvW, "prv-out") + + var doCertify bool + if len(subj) == 0 && !*verify { + doCertify = true } var err error @@ -128,30 +130,33 @@ func main() { var caPrv sign.Iface var caPubs []*sign.Signed - for _, issuingPub := range issuingPubs { - var signed *sign.Signed - signed, _, err = sign.PubParse(mustReadFile(issuingPub)) - if err != nil { - log.Fatal(err) + if doCertify || *verify { + data := mustReadAll(fdPubR) + for len(data) > 0 { + var signed *sign.Signed + signed, data, err = sign.PubParse(data) + if err != nil { + log.Fatal(err) + } + caPubs = append(caPubs, signed) } - caPubs = append(caPubs, signed) } - if len(caPubs) > 0 && !*verify { - if *issuingPrv == "" { - log.Fatal("no -ca-prv is set") - } - caPrv, _, err = sign.PrvParse(mustReadFile(*issuingPrv)) + if doCertify { + caPrv, _, err = sign.PrvParse(mustReadAll(fdPrvR)) if err != nil { log.Fatal(err) } } - if *verify { - var signed *sign.Signed - signed, _, err = sign.PubParse(mustReadFile(*pubPath)) + var signed *sign.Signed + if doCertify || *verify { + signed, _, err = sign.PubParse(mustReadAll(os.Stdin)) if err != nil { log.Fatal(err) } + } + + if *verify { err = signed.CertificationVerify(caPubs, time.Now().UTC()) if err != nil { log.Fatal(err) @@ -161,21 +166,10 @@ func main() { var prvRaw []byte var pubLoad *sign.PubLoad - var signed *sign.Signed - if caPrv != nil { - signed, _, err = sign.PubParse(mustReadFile(*pubPath)) - if err != nil { - log.Fatal(err) - } + if doCertify { pubLoad = signed.PubLoad() } else { - if len(subj) == 0 { - log.Fatal("no -subj is set") - } var pub []byte - if *prvPath == "" { - log.Fatal("no -prv is set") - } switch *algo { case ed25519blake2b.Ed25519BLAKE2b: _, prvRaw, pub, err = ed25519blake2b.NewKeypair() @@ -199,8 +193,7 @@ func main() { if _, err = keks.Encode(&buf, cm.AV{A: *algo, V: prvRaw}, nil); err != nil { log.Fatal(err) } - err = os.WriteFile(*prvPath, buf.Bytes(), 0o600) - if err != nil { + if _, err = io.Copy(fdPrvW, &buf); err != nil { log.Fatal(err) } } @@ -236,7 +229,7 @@ func main() { signed = &sign.Signed{Load: sign.SignedLoad{T: "pub", V: &pubLoadAny}} } - if caPrv != nil { + if doCertify { if err = signed.CertifyWith( caPubs[0].PubLoad(), caPrv, since, till, ); err != nil { @@ -252,7 +245,7 @@ func main() { if _, err = keks.Encode(&buf, signed, nil); err != nil { log.Fatal(err) } - if err = os.WriteFile(*pubPath, buf.Bytes(), 0o666); err != nil { + if _, err = io.Copy(fdPubW, &buf); err != nil { log.Fatal(err) } } diff --git a/go/cm/cmd/keytool/usage.go b/go/cm/cmd/keytool/usage.go index fb72ddf..d93be5a 100644 --- a/go/cm/cmd/keytool/usage.go +++ b/go/cm/cmd/keytool/usage.go @@ -24,13 +24,11 @@ import ( func usage() { fmt.Fprintf(os.Stderr, `Usage: Generate public key load: - keytool -prv PRV -pub PUB [-algo ALGO] [-ku KU ...] \ - -subj K=V [-subj K=V ...] - Sign certificate: - keytool -pub PUB -ca-prv CA-PRV -ca-pub CA-pub \ - [-lifetime DAYS] [-since DATE] - Verify certificate: - keytool -verify -pub PUB CA-PRV -ca-pub CA-pub0 [-ca-pub CA-pub1 ...] + cmkeytool -subj K=V [-subj K=V ...] [-algo ALGO] [-ku KU ...] 5>PUB 9>PRV + Certify public key: + cmkeytool [-lifetime DAYS] [-since DATE] 4$TMPDIR/sign.$keyalgo.pub 9>$TMPDIR/sign.$keyalgo.prv" dd if=/dev/urandom of=$TMPDIR/sign.$keyalgo.data bs=300K count=1 2>/dev/null encTo="-encrypted-to $(uuidgen)" badEncTo="-encrypted-to $(uuidgen)" @@ -22,32 +22,33 @@ for merkle in "" "-merkle" ; do algo=${keyalgo}${merkle} test_expect_success "$algo: signing" "cmsigtool $merkle \ - -prv $TMPDIR/sign.$keyalgo.prv -pub $TMPDIR/sign.$keyalgo.pub -type $typ \ - $encTo <$TMPDIR/sign.$keyalgo.data >$TMPDIR/sign.$algo.sig" + -type $typ $encTo \ + 4<$TMPDIR/sign.$keyalgo.pub 8<$TMPDIR/sign.$keyalgo.prv \ + <$TMPDIR/sign.$keyalgo.data >$TMPDIR/sign.$algo.sig" test_expect_success "$algo: verifying" "cmsigtool \ - -verify -pub $TMPDIR/sign.$keyalgo.pub -type $typ \ - <$TMPDIR/sign.$algo.sig >$TMPDIR/sign.data.got" + -verify -type $typ 4<$TMPDIR/sign.$keyalgo.pub \ + <$TMPDIR/sign.$algo.sig >$TMPDIR/sign.data.got" test_expect_success "$algo: comparing" \ "test_cmp $TMPDIR/sign.$keyalgo.data $TMPDIR/sign.data.got" test_expect_success "$algo: differing type" "! cmsigtool \ - -verify -pub $TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null" + -verify 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null" test_expect_success "$algo: good encTo" "! cmsigtool \ - -verify -pub $TMPDIR/sign.$keyalgo.pub $encTo <$TMPDIR/sign.$algo.sig >/dev/null" + -verify $encTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null" test_expect_success "$algo: bad encTo" "! cmsigtool \ - -verify -pub $TMPDIR/sign.$keyalgo.pub $badEncTo <$TMPDIR/sign.$algo.sig >/dev/null" + -verify $badEncTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.sig >/dev/null" test_expect_success "$algo: detached signing" "cmsigtool -detached $merkle \ - -prv $TMPDIR/sign.$keyalgo.prv -pub $TMPDIR/sign.$keyalgo.pub -type $typ \ - <$TMPDIR/sign.$keyalgo.data >$TMPDIR/sign.$algo.detached.sig" + -type $typ 4<$TMPDIR/sign.$keyalgo.pub 8<$TMPDIR/sign.$keyalgo.prv \ + <$TMPDIR/sign.$keyalgo.data >$TMPDIR/sign.$algo.detached.sig" test_expect_success "$algo: detached verifying" \ "cat $TMPDIR/sign.$algo.detached.sig $TMPDIR/sign.$keyalgo.data | - cmsigtool -detached -verify -pub $TMPDIR/sign.$keyalgo.pub -type $typ" + cmsigtool -detached -verify -type $typ 4<$TMPDIR/sign.$keyalgo.pub" test_expect_success "$algo: differing type" "! cmsigtool -detached \ - -verify -pub $TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null" + -verify -pub 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null" test_expect_success "$algo: good encTo" "! cmsigtool -detached \ - -verify -pub $TMPDIR/sign.$keyalgo.pub $encTo <$TMPDIR/sign.$algo.detached.sig >/dev/null" + -verify -pub $encTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null" test_expect_success "$algo: bad encTo" "! cmsigtool -detached \ - -verify -pub $TMPDIR/sign.$keyalgo.pub $badEncTo <$TMPDIR/sign.$algo.detached.sig >/dev/null" + -verify -pub $badEncTo 4<$TMPDIR/sign.$keyalgo.pub <$TMPDIR/sign.$algo.detached.sig >/dev/null" done diff --git a/go/cm/cmd/sigtool/main.go b/go/cm/cmd/sigtool/main.go index 585f3f0..defdcb2 100644 --- a/go/cm/cmd/sigtool/main.go +++ b/go/cm/cmd/sigtool/main.go @@ -35,12 +35,17 @@ import ( "go.cypherpunks.su/keks/types" ) +const ( + FdPubR = 4 + FdPrvR = 8 +) + const BlobChunkLen = 128 * 1024 -func mustReadFile(p string) []byte { - data, err := os.ReadFile(p) +func mustReadAll(r io.Reader) []byte { + data, err := io.ReadAll(r) if err != nil { - log.Fatalln("read:", p, err) + log.Fatal(err) } return data } @@ -48,8 +53,6 @@ func mustReadFile(p string) []byte { func main() { log.SetFlags(log.Lshortfile) flag.Usage = usage - prvPath := flag.String("prv", "", "Path to private key file") - pubPath := flag.String("pub", "", "Path to public key file") typ := flag.String("type", "data", "Set/check the load type") verify := flag.Bool("verify", false, "Do verification") var encryptedTo []uuid.UUID @@ -66,13 +69,14 @@ func main() { doMerkle := flag.Bool("merkle", false, "Use Merkle-tree based hasher") flag.Parse() - if *pubPath == "" { - log.Fatal("no -pub is set") - } - pub, _, err := sign.PubParse(mustReadFile(*pubPath)) + fdPubR := os.NewFile(FdPubR, "pub-in") + fdPrvR := os.NewFile(FdPrvR, "prv-in") + + pub, _, err := sign.PubParse(mustReadAll(fdPubR)) if err != nil { log.Fatal(err) } + fdPubR.Close() stdin := bufio.NewReaderSize(os.Stdin, BlobChunkLen) if *verify { @@ -172,11 +176,9 @@ func main() { log.Fatal(err) } } else { - if *prvPath == "" { - log.Fatal("no -prv is set") - } var signer sign.Iface - signer, _, err = sign.PrvParse(mustReadFile(*prvPath)) + signer, _, err = sign.PrvParse(mustReadAll(fdPrvR)) + fdPrvR.Close() if err != nil { log.Fatal(err) } diff --git a/go/cm/cmd/sigtool/usage.go b/go/cm/cmd/sigtool/usage.go index cad6ab1..7510370 100644 --- a/go/cm/cmd/sigtool/usage.go +++ b/go/cm/cmd/sigtool/usage.go @@ -23,10 +23,10 @@ import ( func usage() { fmt.Fprintf(os.Stderr, `Usage: - sigtool -prv PRV -pub PUB [-type TYPE] DATA.signed - sigtool -verify -pub PUB [-type TYPE] DATA - sigtool -detached -prv PRV -pub PUB [-type TYPE] DATA.signature - sigtool -detached -verify -pub PUB [-type TYPE] <(cat DATA.signature DATA) + cmsigtool [-type TYPE] 4DATA.signed + cmsigtool -verify [-type TYPE] 4DATA + cmsigtool -detached [-type TYPE] 4DATA.signature + cmsigtool -detached -verify [-type TYPE] 4