]> Cypherpunks repositories - keks.git/commitdiff
Sender authentication implementation
authorSergey Matveev <stargrave@stargrave.org>
Sun, 5 Oct 2025 12:16:15 +0000 (15:16 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sun, 5 Oct 2025 14:54:55 +0000 (17:54 +0300)
13 files changed:
go/cm/cmd/cmenctool/main.go
go/cm/cmd/cmenctool/missing-from.t [new file with mode: 0755]
go/cm/cmd/cmenctool/missing-to.t [new file with mode: 0755]
go/cm/cmd/cmenctool/multirecipient.t
go/cm/cmd/cmenctool/prv-encrypted.t
go/cm/cmd/cmenctool/pub.t
go/cm/cmd/cmenctool/sender-auth.t [new file with mode: 0755]
go/cm/cmd/cmenctool/usage.go
go/cm/enc/kem.go
spec/cm/encrypted/authcrypt
spec/cm/encrypted/index
spec/cm/kem/mceliece6960119-x25519-hkdf-shake256
spec/cm/kem/sntrup761-x25519-hkdf-blake2b

index e0e55761c5b30268e9a7d054bbe0bd58c67c0fe06576aa0b9cbc0a8cdbbbc921..7efd191e72bd444b58a65c2fc8385add498db9bdea319c949a58ab36bf39862b 100644 (file)
@@ -22,13 +22,18 @@ import (
        "crypto/hkdf"
        "crypto/rand"
        "crypto/sha3"
+       "encoding/hex"
        "errors"
        "flag"
+       "fmt"
        "hash"
        "io"
+       "io/fs"
        "log"
        "os"
+       "path"
        "strconv"
+       "strings"
 
        "github.com/google/uuid"
        "go.cypherpunks.su/balloon/v3"
@@ -59,6 +64,11 @@ const (
        X25519KeyLen = 32
 )
 
+var (
+       PrvDir = flag.String("prvs", "prvs", "Path to directory with private keys")
+       PubDir = flag.String("pubs", "pubs", "Path to directory with public keys")
+)
+
 func blake2bHash() hash.Hash {
        h, err := blake2b.New512(nil)
        if err != nil {
@@ -67,7 +77,51 @@ func blake2bHash() hash.Hash {
        return h
 }
 
-func parsePrv(data []byte) (av cm.AV, tail []byte, err error) {
+func pubParse(pth string) (pubData *sign.PubData, err error) {
+       var data []byte
+       data, err = os.ReadFile(pth)
+       if err != nil {
+               return
+       }
+       var signed *sign.Signed
+       signed, _, err = sign.PubParse(data)
+       if err != nil {
+               return
+       }
+       pubData = signed.PubData()
+       if !pubData.Can(sign.KUKEM) {
+               err = fmt.Errorf("does not have %s key usage", sign.KUKEM)
+               return
+       }
+       if len(pubData.Pub) != 1 {
+               err = errors.New("single public key expected")
+       }
+       return
+}
+
+func findPub(id []byte) (pub *sign.PubData, err error) {
+       pth := path.Join(
+               *PubDir, strings.ToUpper(hex.EncodeToString(id)),
+       )
+       if _, err = os.Stat(pth); err != nil {
+               if errors.Is(err, fs.ErrNotExist) {
+                       err = nil
+               }
+               return
+       }
+       return pubParse(pth)
+}
+
+func findPrv(id []byte) (av *cm.AV, err error) {
+       data, err := os.ReadFile(path.Join(
+               *PrvDir, strings.ToUpper(hex.EncodeToString(id)),
+       ))
+       if err != nil {
+               if errors.Is(err, fs.ErrNotExist) {
+                       err = nil
+               }
+               return
+       }
        data, err = cmballoon.PossibleInteractiveDecrypt(data)
        if err != nil {
                return
@@ -91,10 +145,10 @@ func parsePrv(data []byte) (av cm.AV, tail []byte, err error) {
                        return
                }
        }
-       if err = d.UnmarshalStruct(&av); err != nil {
-               return
+       var v cm.AV
+       if err = d.UnmarshalStruct(&v); err == nil {
+               av = &v
        }
-       tail = d.B
        return
 }
 
@@ -102,7 +156,12 @@ func main() {
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
        setId := flag.String("id", "", "Set that /id instead of autogeneration")
-       includeTo := flag.Bool("include-to", false, `Include "to" field in KEMs`)
+       assumeToHex := flag.String("assume-to", "",
+               `Assume that hexadecimal "to" value if missing`)
+       assumeFromHex := flag.String("assume-from", "",
+               `Assume that hexadecimal "from" value if missing`)
+       noFrom := flag.Bool("no-from", false, `Do not include "from" field in KEMs`)
+       noTo := flag.Bool("no-to", false, `Do not include "to" field in KEMs`)
        passphrase := flag.Bool("p", false, "Use passphrase")
        balloonS := flag.Int("balloon-s", 1<<17, "Balloon's space cost")
        balloonT := flag.Int("balloon-t", 4, "Balloon's time cost")
@@ -110,49 +169,67 @@ func main() {
        doDecrypt := flag.Bool("d", false, "Decrypt")
        parallel := flag.Int("parallel", cmhash.DefaultNumCPU, "Parallel cryptors")
        noblob := flag.Bool("embed", false, "Include payload into container")
-       flag.Parse()
-
-       fdPubR := os.NewFile(FdPubR, "pub-in")
+       fromPth := flag.String("from", "", "Path to sender's public key for authentication")
        var pubs []cm.AV
        var pubIds [][]byte
-       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)
-                       }
-                       pubData := signed.PubData()
-                       if !pubData.Can(sign.KUKEM) {
-                               log.Println(
-                                       "public key:", len(pubs), ": does not have",
-                                       sign.KUKEM, "key usage",
-                               )
-                       }
-                       if len(pubData.Pub) != 1 {
-                               log.Fatalln("public key:", len(pubs), ": expected single public key")
-                       }
-                       pubs = append(pubs, pubData.Pub[0])
-                       pubIds = append(pubIds, pubData.Id)
+       flag.Func("to", "Path to recipient's public key", func(v string) error {
+               pubData, err := pubParse(v)
+               if err != nil {
+                       log.Fatalln(v, ":", err)
+               }
+               pubs = append(pubs, pubData.Pub[0])
+               pubIds = append(pubIds, pubData.Id)
+               return nil
+       })
+       flag.Parse()
+
+       var err error
+       var assumeTo []byte
+       if *assumeToHex != "" {
+               assumeTo, err = hex.DecodeString(*assumeToHex)
+               if err != nil {
+                       log.Fatal(err)
+               }
+       }
+       var assumeFrom []byte
+       if *assumeFromHex != "" {
+               assumeFrom, err = hex.DecodeString(*assumeFromHex)
+               if err != nil {
+                       log.Fatal(err)
                }
        }
-       fdPubR.Close()
 
-       fdPrvR := os.NewFile(FdPrvR, "prv-in")
-       var prvs []*cm.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)
+       var fromA string
+       var fromPrv, fromPub, fromId []byte
+       if *fromPth != "" {
+               var pubData *sign.PubData
+               pubData, err = pubParse(*fromPth)
+               if err != nil {
+                       log.Fatalln("from:", err)
+               }
+               if len(pubData.Pub) != 1 {
+                       log.Fatal("from: expected single public key")
+               }
+               fromA = pubData.Pub[0].A
+               fromId = pubData.Id
+               switch fromA {
+               case sntrup761x25519.SNTRUP761X25519, mceliece6960119x25519.ClassicMcEliece6960119X25519:
+                       fromPub = pubData.Pub[0].V
+                       fromPub = fromPub[len(fromPub)-X25519KeyLen:]
+               default:
+                       log.Fatal("from: unsupported algorithm")
                }
+               var prv *cm.AV
+               prv, err = findPrv(pubData.Id)
+               if err != nil {
+                       log.Fatalln("from:", err)
+               }
+               if prv == nil {
+                       log.Fatal("from: can not find corresponding private key")
+               }
+               fromPrv = prv.V[len(prv.V)-X25519KeyLen:]
        }
-       fdPrvR.Close()
 
-       var err error
        var cek []byte
        if *doDecrypt {
                {
@@ -228,10 +305,6 @@ func main() {
                                        continue
                                }
                        case sntrup761x25519.SNTRUP761X25519HKDFBLAKE2b:
-                               if len(prvs) == 0 {
-                                       log.Println(kemIdx, kem.A, "skipping because no private key specified")
-                                       continue
-                               }
                                if kem.Encap == nil {
                                        log.Fatalln("missing encap")
                                }
@@ -239,217 +312,321 @@ func main() {
                                if len(kem.Encap) != scheme.CiphertextSize()+X25519KeyLen {
                                        log.Fatalln("invalid encap len")
                                }
-                               for _, prv := range prvs {
-                                       if prv.A != sntrup761x25519.SNTRUP761X25519 {
+                               if len(kem.To) == 0 {
+                                       if assumeTo == nil {
+                                               log.Println(kemIdx, kem.A,
+                                                       `skipping because no "to" specified`)
                                                continue
                                        }
-                                       if len(prv.V) != scheme.PrivateKeySize()+X25519KeyLen {
-                                               log.Fatalln("invalid private keys len")
-                                       }
-                                       var ourSNTRUP sntrup761kem.PrivateKey
-                                       ourSNTRUP, err = scheme.UnmarshalBinaryPrivateKey(
-                                               prv.V[:scheme.PrivateKeySize()],
-                                       )
-                                       if err != nil {
-                                               log.Fatal(err)
+                                       kem.To = assumeTo
+                               }
+                               var prv *cm.AV
+                               prv, err = findPrv(kem.To)
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               if prv == nil {
+                                       log.Println(kemIdx, kem.A,
+                                               "skipping because no private key found")
+                                       continue
+                               }
+                               if prv.A != sntrup761x25519.SNTRUP761X25519 {
+                                       log.Fatalln(kemIdx, kem.A, "differing algorithm")
+                               }
+                               if len(prv.V) != scheme.PrivateKeySize()+X25519KeyLen {
+                                       log.Fatalln("invalid private keys len")
+                               }
+                               var from *sign.PubData
+                               if kem.From != nil {
+                                       if bytes.Equal(kem.From, bytes.Repeat([]byte{0}, 32)) {
+                                               kem.From = assumeFrom
                                        }
-                                       x25519 := ecdh.X25519()
-                                       var ourX25519 *ecdh.PrivateKey
-                                       ourX25519, err = x25519.NewPrivateKey(
-                                               prv.V[scheme.PrivateKeySize():],
-                                       )
+                                       from, err = findPub(kem.From)
                                        if err != nil {
-                                               log.Fatal(err)
+                                               log.Fatalln("from:", err)
                                        }
-                                       theirSNTRUP := kem.Encap[:scheme.CiphertextSize()]
-                                       var keySNTRUP []byte
-                                       keySNTRUP, err = scheme.Decapsulate(ourSNTRUP, theirSNTRUP)
-                                       if err != nil {
-                                               continue
+                                       if from == nil {
+                                               log.Fatalln(kemIdx, kem.A, "can not find public key")
                                        }
-                                       var theirX25519 *ecdh.PublicKey
-                                       theirX25519, err = x25519.NewPublicKey(
-                                               kem.Encap[scheme.CiphertextSize():],
-                                       )
+                               }
+                               var ourSNTRUP sntrup761kem.PrivateKey
+                               ourSNTRUP, err = scheme.UnmarshalBinaryPrivateKey(
+                                       prv.V[:scheme.PrivateKeySize()],
+                               )
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               x25519 := ecdh.X25519()
+                               var ourX25519 *ecdh.PrivateKey
+                               ourX25519, err = x25519.NewPrivateKey(
+                                       prv.V[scheme.PrivateKeySize():],
+                               )
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               theirSNTRUP := kem.Encap[:scheme.CiphertextSize()]
+                               var keySNTRUP []byte
+                               keySNTRUP, err = scheme.Decapsulate(ourSNTRUP, theirSNTRUP)
+                               if err != nil {
+                                       log.Fatalln(kemIdx, kem.A, "decapsulate:", err)
+                               }
+                               var theirX25519 *ecdh.PublicKey
+                               theirX25519, err = x25519.NewPublicKey(
+                                       kem.Encap[scheme.CiphertextSize():],
+                               )
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               var keyX25519 []byte
+                               keyX25519, err = ourX25519.ECDH(theirX25519)
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               {
+                                       var ourSNTRUPPub []byte
+                                       ourSNTRUPPub, err = ourSNTRUP.Public().MarshalBinary()
                                        if err != nil {
                                                log.Fatal(err)
                                        }
-                                       var keyX25519 []byte
-                                       keyX25519, err = ourX25519.ECDH(theirX25519)
+                                       ctHash := blake2b.Sum512(kem.Encap)
+                                       pkHash := blake2b.Sum512(append(
+                                               ourSNTRUPPub,
+                                               ourX25519.PublicKey().Bytes()...,
+                                       ))
+                                       ikm := bytes.Join([][]byte{
+                                               keySNTRUP[:], keyX25519, ctHash[:], pkHash[:],
+                                       }, []byte{})
+                                       var prk []byte
+                                       prk, err = hkdf.Extract(blake2bHash, ikm, nil)
                                        if err != nil {
                                                log.Fatal(err)
                                        }
-                                       {
-
-                                               var ourSNTRUPPub []byte
-                                               ourSNTRUPPub, err = ourSNTRUP.Public().MarshalBinary()
+                                       if from != nil {
+                                               fromPub = from.Pub[0].V
+                                               fromPub = fromPub[len(fromPub)-X25519KeyLen:]
+                                               theirX25519, err = x25519.NewPublicKey(fromPub)
                                                if err != nil {
                                                        log.Fatal(err)
                                                }
-                                               ctHash := blake2b.Sum512(kem.Encap)
-                                               pkHash := blake2b.Sum512(append(
-                                                       ourSNTRUPPub,
-                                                       ourX25519.PublicKey().Bytes()...,
-                                               ))
-                                               ikm := bytes.Join([][]byte{
-                                                       keySNTRUP[:], keyX25519, ctHash[:], pkHash[:],
-                                               }, []byte{})
-                                               var prk []byte
-                                               prk, err = hkdf.Extract(blake2bHash, ikm, nil)
+                                               keyX25519, err = ourX25519.ECDH(theirX25519)
                                                if err != nil {
                                                        log.Fatal(err)
                                                }
-                                               var kek []byte
-                                               kek, err = hkdf.Expand(
+                                               prk, err = hkdf.Expand(
                                                        blake2bHash,
                                                        prk,
-                                                       string(append(
-                                                               []byte(cmenc.SNTRUP761X25519Info),
-                                                               encrypted.Id[:]...)),
-                                                       chacha20poly1305.KeySize,
+                                                       cmenc.SNTRUP761X25519AuthInfo,
+                                                       blake2b.Size,
                                                )
                                                if err != nil {
                                                        log.Fatal(err)
                                                }
-                                               var cekp []byte
-                                               cekp, err = chapoly.Unwrap(kek, kem.CEK)
+                                               ikm = bytes.Join([][]byte{
+                                                       keyX25519, fromPub, ourX25519.PublicKey().Bytes(),
+                                               }, []byte{})
+                                               prk, err = hkdf.Extract(blake2bHash, ikm, prk)
                                                if err != nil {
-                                                       log.Println(kemIdx, kem.A, err, ", skipping")
-                                                       continue
-                                               }
-                                               if len(cekp) != chapoly.CEKLen {
-                                                       log.Println(kemIdx, kem.A, "wrong key len, skipping")
-                                                       continue
+                                                       log.Fatal(err)
                                                }
-                                               cek = cekp
-                                               break
                                        }
+                                       var kek []byte
+                                       kek, err = hkdf.Expand(
+                                               blake2bHash,
+                                               prk,
+                                               string(append(
+                                                       []byte(cmenc.SNTRUP761X25519Info),
+                                                       encrypted.Id[:]...)),
+                                               chacha20poly1305.KeySize)
+                                       if err != nil {
+                                               log.Fatal(err)
+                                       }
+                                       var cekp []byte
+                                       cekp, err = chapoly.Unwrap(kek, kem.CEK)
+                                       if err != nil {
+                                               log.Fatalln(kemIdx, kem.A, "unwrap:", err)
+                                       }
+                                       if len(cekp) != chapoly.CEKLen {
+                                               log.Fatalln(kemIdx, kem.A, "wrong key len, skipping")
+                                       }
+                                       cek = cekp
+                                       break
                                }
                        case mceliece6960119x25519.ClassicMcEliece6960119X25519HKDFSHAKE256:
-                               if len(prvs) == 0 {
-                                       log.Println(kemIdx, kem.A, "skipping because no private key specified")
-                                       continue
-                               }
                                if kem.Encap == nil {
                                        log.Fatalln("missing encap")
                                }
                                if len(kem.Encap) != mceliece6960119.CiphertextSize+X25519KeyLen+chacha20poly1305.Overhead {
                                        log.Fatalln("invalid encap len")
                                }
-                               for _, prv := range prvs {
-                                       if prv.A != mceliece6960119x25519.ClassicMcEliece6960119X25519 {
+                               if len(kem.To) == 0 {
+                                       if assumeTo == nil {
+                                               log.Println(kemIdx, kem.A,
+                                                       `skipping because no "to" specified`)
                                                continue
                                        }
-                                       if len(prv.V) != mceliece6960119.PrivateKeySize+X25519KeyLen {
-                                               log.Fatalln("invalid private keys len")
+                                       kem.To = assumeTo
+                               }
+                               var prv *cm.AV
+                               prv, err = findPrv(kem.To)
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               if prv == nil {
+                                       log.Println(kemIdx, kem.A,
+                                               "skipping because no private key found")
+                                       continue
+                               }
+                               if prv.A != mceliece6960119x25519.ClassicMcEliece6960119X25519 {
+                                       continue
+                               }
+                               if len(prv.V) != mceliece6960119.PrivateKeySize+X25519KeyLen {
+                                       log.Fatalln("invalid private keys len")
+                               }
+                               var from *sign.PubData
+                               if kem.From != nil {
+                                       if bytes.Equal(kem.From, bytes.Repeat([]byte{0}, 32)) {
+                                               kem.From = assumeFrom
+                                       }
+                                       from, err = findPub(kem.From)
+                                       if err != nil {
+                                               log.Fatalln("from:", err)
+                                       }
+                                       if from == nil {
+                                               log.Fatalln(kemIdx, kem.A, "can not find public key")
                                        }
-                                       var ourMcEliece *mceliece6960119.PrivateKey
-                                       ourMcEliece, err = mceliece6960119.UnmarshalBinaryPrivateKey(
-                                               prv.V[:len(prv.V)-X25519KeyLen],
+                               }
+                               var ourMcEliece *mceliece6960119.PrivateKey
+                               ourMcEliece, err = mceliece6960119.UnmarshalBinaryPrivateKey(
+                                       prv.V[:len(prv.V)-X25519KeyLen],
+                               )
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               x25519 := ecdh.X25519()
+                               var ourX25519 *ecdh.PrivateKey
+                               ourX25519, err = x25519.NewPrivateKey(prv.V[len(prv.V)-X25519KeyLen:])
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               theirMcEliece := (kem.Encap)[:len(kem.Encap)-X25519KeyLen-chacha20poly1305.Overhead]
+                               theirX2559Encap := (kem.Encap)[len(kem.Encap)-X25519KeyLen-chacha20poly1305.Overhead:]
+                               var keyMcEliece []byte
+                               keyMcEliece, err = mceliece6960119.Decapsulate(
+                                       ourMcEliece, theirMcEliece,
+                               )
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               var theirX25519 *ecdh.PublicKey
+                               {
+                                       var decapKeymat []byte
+                                       decapKeymat, err = hkdf.Expand(
+                                               cmhash.NewSHAKE256,
+                                               keyMcEliece,
+                                               string(append(
+                                                       []byte(cmenc.ClassicMcEliece6960119X25519DecapInfo),
+                                                       encrypted.Id[:]...)),
+                                               chacha20poly1305.KeySize+chacha20poly1305.NonceSizeX,
                                        )
                                        if err != nil {
                                                log.Fatal(err)
                                        }
-                                       x25519 := ecdh.X25519()
-                                       var ourX25519 *ecdh.PrivateKey
-                                       ourX25519, err = x25519.NewPrivateKey(prv.V[len(prv.V)-X25519KeyLen:])
+                                       decapKey := decapKeymat[:chacha20poly1305.KeySize]
+                                       decapNonce := decapKeymat[chacha20poly1305.KeySize:]
+                                       var aead cipher.AEAD
+                                       aead, err = chacha20poly1305.NewX(decapKey)
                                        if err != nil {
                                                log.Fatal(err)
                                        }
-                                       theirMcEliece := (kem.Encap)[:len(kem.Encap)-X25519KeyLen-chacha20poly1305.Overhead]
-                                       theirX2559Encap := (kem.Encap)[len(kem.Encap)-X25519KeyLen-chacha20poly1305.Overhead:]
-                                       var keyMcEliece []byte
-                                       keyMcEliece, err = mceliece6960119.Decapsulate(
-                                               ourMcEliece, theirMcEliece,
-                                       )
+                                       var theirX25519Raw []byte
+                                       theirX25519Raw, err = aead.Open(
+                                               nil,
+                                               decapNonce,
+                                               theirX2559Encap,
+                                               theirMcEliece)
                                        if err != nil {
                                                log.Fatal(err)
                                        }
-                                       var theirX25519 *ecdh.PublicKey
-                                       {
-                                               var decapKeymat []byte
-                                               decapKeymat, err = hkdf.Expand(
-                                                       cmhash.NewSHAKE256,
-                                                       keyMcEliece,
-                                                       string(append(
-                                                               []byte(cmenc.ClassicMcEliece6960119X25519DecapInfo),
-                                                               encrypted.Id[:]...)),
-                                                       chacha20poly1305.KeySize+chacha20poly1305.NonceSizeX,
-                                               )
-                                               if err != nil {
-                                                       log.Fatal(err)
-                                               }
-                                               decapKey := decapKeymat[:chacha20poly1305.KeySize]
-                                               decapNonce := decapKeymat[chacha20poly1305.KeySize:]
-                                               var aead cipher.AEAD
-                                               aead, err = chacha20poly1305.NewX(decapKey)
-                                               if err != nil {
-                                                       log.Fatal(err)
-                                               }
-                                               var theirX25519Raw []byte
-                                               theirX25519Raw, err = aead.Open(
-                                                       nil,
-                                                       decapNonce,
-                                                       theirX2559Encap,
-                                                       theirMcEliece)
-                                               if err != nil {
-                                                       log.Fatal(err)
-                                               }
-                                               theirX25519, err = x25519.NewPublicKey(theirX25519Raw)
-                                               if err != nil {
-                                                       log.Fatal(err)
-                                               }
+                                       theirX25519, err = x25519.NewPublicKey(theirX25519Raw)
+                                       if err != nil {
+                                               log.Fatal(err)
                                        }
-                                       var keyX25519 []byte
-                                       keyX25519, err = ourX25519.ECDH(theirX25519)
+                               }
+                               var keyX25519 []byte
+                               keyX25519, err = ourX25519.ECDH(theirX25519)
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               {
+                                       ourMcEliecePub := ourMcEliece.Public()
+                                       var ourMcEliecePubRaw []byte
+                                       ourMcEliecePubRaw, err = ourMcEliecePub.MarshalBinary()
                                        if err != nil {
                                                log.Fatal(err)
                                        }
-                                       {
-                                               ourMcEliecePub := ourMcEliece.Public()
-                                               var ourMcEliecePubRaw []byte
-                                               ourMcEliecePubRaw, err = ourMcEliecePub.MarshalBinary()
+                                       pkHash := cmhash.NewSHAKE256()
+                                       pkHash.Write(ourMcEliecePubRaw)
+                                       pkHash.Write(ourX25519.PublicKey().Bytes())
+                                       ikm := bytes.Join([][]byte{
+                                               keyMcEliece, keyX25519,
+                                               sha3.SumSHAKE256(kem.Encap, 64),
+                                               pkHash.Sum(nil),
+                                       }, []byte{})
+                                       var prk []byte
+                                       prk, err = hkdf.Extract(cmhash.NewSHAKE256, ikm, nil)
+                                       if err != nil {
+                                               log.Fatal(err)
+                                       }
+                                       if from != nil {
+                                               fromPub = from.Pub[0].V
+                                               fromPub = fromPub[len(fromPub)-X25519KeyLen:]
+                                               theirX25519, err = x25519.NewPublicKey(fromPub)
                                                if err != nil {
                                                        log.Fatal(err)
                                                }
-                                               pkHash := cmhash.NewSHAKE256()
-                                               pkHash.Write(ourMcEliecePubRaw)
-                                               pkHash.Write(ourX25519.PublicKey().Bytes())
-                                               ikm := bytes.Join([][]byte{
-                                                       keyMcEliece, keyX25519,
-                                                       sha3.SumSHAKE256(kem.Encap, 64),
-                                                       pkHash.Sum(nil),
-                                               }, []byte{})
-                                               var prk []byte
-                                               prk, err = hkdf.Extract(cmhash.NewSHAKE256, ikm, nil)
+                                               keyX25519, err = ourX25519.ECDH(theirX25519)
                                                if err != nil {
                                                        log.Fatal(err)
                                                }
-                                               var kek []byte
-                                               kek, err = hkdf.Expand(
+                                               prk, err = hkdf.Expand(
                                                        cmhash.NewSHAKE256,
                                                        prk,
-                                                       string(append(
-                                                               []byte(cmenc.ClassicMcEliece6960119X25519Info),
-                                                               encrypted.Id[:]...)),
-                                                       chacha20poly1305.KeySize,
+                                                       cmenc.ClassicMcEliece6960119X25519AuthInfo,
+                                                       64,
                                                )
                                                if err != nil {
                                                        log.Fatal(err)
                                                }
-                                               var cekp []byte
-                                               cekp, err = chapoly.Unwrap(kek, kem.CEK)
+                                               ikm = bytes.Join([][]byte{
+                                                       keyX25519, fromPub, ourX25519.PublicKey().Bytes(),
+                                               }, []byte{})
+                                               prk, err = hkdf.Extract(cmhash.NewSHAKE256, ikm, prk)
                                                if err != nil {
-                                                       log.Println(kemIdx, kem.A, err, ", skipping")
-                                                       continue
-                                               }
-                                               if len(cekp) != chapoly.CEKLen {
-                                                       log.Println(kemIdx, kem.A, "wrong key len, skipping")
-                                                       continue
+                                                       log.Fatal(err)
                                                }
-                                               cek = cekp
-                                               break
                                        }
+                                       var kek []byte
+                                       kek, err = hkdf.Expand(
+                                               cmhash.NewSHAKE256,
+                                               prk,
+                                               string(append(
+                                                       []byte(cmenc.ClassicMcEliece6960119X25519Info),
+                                                       encrypted.Id[:]...)),
+                                               chacha20poly1305.KeySize,
+                                       )
+                                       if err != nil {
+                                               log.Fatal(err)
+                                       }
+                                       var cekp []byte
+                                       cekp, err = chapoly.Unwrap(kek, kem.CEK)
+                                       if err != nil {
+                                               log.Fatalln(kemIdx, kem.A, "unwrap:", err)
+                                       }
+                                       if len(cekp) != chapoly.CEKLen {
+                                               log.Fatalln(kemIdx, kem.A, "wrong key len, skipping")
+                                       }
+                                       cek = cekp
+                                       break
                                }
                        default:
                                log.Println("unsupported KEM:", kem.A)
@@ -559,7 +736,7 @@ func main() {
                                        log.Fatal(err)
                                }
                                var ourPrvX25519 *ecdh.PrivateKey
-                               ourPrvX25519, err = ecdh.X25519().GenerateKey(rand.Reader)
+                               ourPrvX25519, err = x25519.GenerateKey(rand.Reader)
                                if err != nil {
                                        log.Fatal(err)
                                }
@@ -584,6 +761,40 @@ func main() {
                                        if err != nil {
                                                log.Fatal(err)
                                        }
+                                       if fromPrv != nil {
+                                               if fromA != sntrup761x25519.SNTRUP761X25519 {
+                                                       log.Fatal("differing sender/recipient algorithms")
+                                               }
+                                               ourPrvX25519, err = x25519.NewPrivateKey(fromPrv)
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               keyX25519, err = ourPrvX25519.ECDH(theirX25519)
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               prk, err = hkdf.Expand(
+                                                       blake2bHash,
+                                                       prk,
+                                                       cmenc.SNTRUP761X25519AuthInfo,
+                                                       blake2b.Size,
+                                               )
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               ikm = bytes.Join([][]byte{
+                                                       keyX25519, fromPub, theirX25519.Bytes(),
+                                               }, []byte{})
+                                               prk, err = hkdf.Extract(blake2bHash, ikm, prk)
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               if *noFrom {
+                                                       kem.From = bytes.Repeat([]byte{0}, 32)
+                                               } else {
+                                                       kem.From = fromId
+                                               }
+                                       }
                                        var kek []byte
                                        kek, err = hkdf.Expand(
                                                blake2bHash,
@@ -601,7 +812,7 @@ func main() {
                                        }
                                        kem.CEK = cekp
                                }
-                               if *includeTo {
+                               if !*noTo {
                                        kem.To = pubIds[pubId]
                                }
                                kems = append(kems, kem)
@@ -679,6 +890,40 @@ func main() {
                                        if err != nil {
                                                log.Fatal(err)
                                        }
+                                       if fromPrv != nil {
+                                               if fromA != mceliece6960119x25519.ClassicMcEliece6960119X25519 {
+                                                       log.Fatal("differing sender/recipient algorithms")
+                                               }
+                                               ourPrvX25519, err = x25519.NewPrivateKey(fromPrv)
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               keyX25519, err = ourPrvX25519.ECDH(theirX25519)
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               prk, err = hkdf.Expand(
+                                                       cmhash.NewSHAKE256,
+                                                       prk,
+                                                       cmenc.ClassicMcEliece6960119X25519AuthInfo,
+                                                       64,
+                                               )
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               ikm = bytes.Join([][]byte{
+                                                       keyX25519, fromPub, theirX25519.Bytes(),
+                                               }, []byte{})
+                                               prk, err = hkdf.Extract(cmhash.NewSHAKE256, ikm, prk)
+                                               if err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               if *noFrom {
+                                                       kem.From = bytes.Repeat([]byte{0}, 32)
+                                               } else {
+                                                       kem.From = fromId
+                                               }
+                                       }
                                        var kek []byte
                                        kek, err = hkdf.Expand(
                                                cmhash.NewSHAKE256,
@@ -698,7 +943,7 @@ func main() {
                                        }
                                        kem.CEK = cekp
                                }
-                               if *includeTo {
+                               if !*noTo {
                                        kem.To = pubIds[pubId]
                                }
                                kems = append(kems, kem)
diff --git a/go/cm/cmd/cmenctool/missing-from.t b/go/cm/cmd/cmenctool/missing-from.t
new file mode 100755 (executable)
index 0000000..d0fa9c7
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description="Check workability with missing \"from\""
+. $SHARNESS_TEST_SRCDIR/sharness.sh
+
+dd if=/dev/urandom of=enc.data bs=300K count=1 2>/dev/null
+mkdir prvs pubs
+
+for algo in sntrup761-x25519 mceliece6960119-x25519 ; do
+
+test_expect_success "$algo: sender pub generation" "cmkeytool \
+    -algo $algo -ku kem -sub N=S 5>s.pub 9>s.prv"
+test_expect_success "$algo: recipient pub generation" "cmkeytool \
+    -algo $algo -ku kem -sub N=R 5>r.pub 9>r.prv"
+senderId=$(kekspp -v -p /data/id <s.pub)
+ln -fs ../s.prv prvs/$senderId
+ln -fs ../r.prv prvs/$(kekspp -v -p /data/id <r.pub)
+ln -fs ../s.pub pubs/$senderId
+ln -fs ../r.pub pubs/$(kekspp -v -p /data/id <r.pub)
+test_expect_success "$algo: encrypting" "cmenctool \
+    -from s.pub -prvs prvs -no-from -to r.pub <enc.data >enc.enc"
+test_expect_success "$algo: decrypting fails" "
+    ! cmenctool -d -prvs prvs -pubs pubs <enc.enc >enc.data.got"
+test_expect_success "$algo: decrypting" "
+    cmenctool -d -prvs prvs -pubs pubs -assume-from $senderId <enc.enc >enc.data.got"
+test_expect_success "$algo: comparing" "test_cmp enc.data enc.data.got"
+
+done
+
+test_done
diff --git a/go/cm/cmd/cmenctool/missing-to.t b/go/cm/cmd/cmenctool/missing-to.t
new file mode 100755 (executable)
index 0000000..38a27f1
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description="Check workability with missing \"to\""
+. $SHARNESS_TEST_SRCDIR/sharness.sh
+
+dd if=/dev/urandom of=enc.data bs=300K count=1 2>/dev/null
+
+for algo in sntrup761-x25519 mceliece6960119-x25519 ; do
+
+test_expect_success "$algo: pub generation" "cmkeytool \
+    -algo sntrup761-x25519 -ku kem -sub N=0 5>enc.pub 9>enc.prv"
+test_expect_success "$algo: encrypting" "cmenctool -no-to -to enc.pub <enc.data >enc.enc"
+pubId=$(kekspp -v -p /data/id <enc.pub)
+ln -s enc.prv $pubId
+test_expect_success "$algo: decrypting fails" "
+    ! cmenctool -d -prvs . <enc.enc >enc.data.got"
+test_expect_success "$algo: decrypting" "
+    cmenctool -assume-to $pubId -d -prvs . <enc.enc >enc.data.got"
+test_expect_success "$algo: comparing" "test_cmp enc.data enc.data.got"
+
+done
+
+test_done
index a63e6e7af7b0847f3123d716959f7f20e6246e238cfaecb71f0fa9ae4dd2f8bc..560da9ced5511577ef49cc92f479d2ce217ebe76666969661c8aedb9ffe8be28 100755 (executable)
@@ -11,14 +11,19 @@ test_expect_success "1: pub generation" "cmkeytool \
     -algo sntrup761-x25519 -ku kem -sub N=1 5>enc.1.pub 9>enc.1.prv"
 
 test_expect_success "encrypting" "
-    cat enc.0.pub enc.1.pub | cmenctool 4<&0 <enc.data >enc.enc"
+    cmenctool -to enc.0.pub -to enc.1.pub <enc.data >enc.enc"
 
+pubId=$(kekspp -v -p /data/id <enc.0.pub)
+ln -s enc.0.prv $pubId
 test_expect_success "0: decrypting" "
-    cmenctool -d 8<enc.0.prv <enc.enc >enc.data.got"
+    cmenctool -d -prvs . <enc.enc >enc.data.got"
 test_expect_success "0: comparing" "test_cmp enc.data enc.data.got"
+rm $pubId
 
+pubId=$(kekspp -v -p /data/id <enc.1.pub)
+ln -s enc.1.prv $(kekspp -v -p /data/id <enc.1.pub)
 test_expect_success "1: decrypting" "
-    cmenctool -d 8<enc.1.prv <enc.enc >enc.data.got"
+    cmenctool -d -prvs . <enc.enc >enc.data.got"
 test_expect_success "1: comparing" "test_cmp enc.data enc.data.got"
 
 test_done
index 8743185190230bdd88810618346c4eb93a75bcf3d8a76ec76e4be848d5b91194..f7c852b7e9ce13d708ef644c8f57326b434b86b76fabdf68b1d09f9e3c8e0fad 100755 (executable)
@@ -3,16 +3,23 @@
 test_description="Check passphrase-encrypted key decryption"
 . $SHARNESS_TEST_SRCDIR/sharness.sh
 
-cmkeytool -algo sntrup761-x25519 -ku kem -sub A=KEY 5>enc.pub 9>enc.prv
-dd if=/dev/urandom of=enc.data bs=12K count=1 2>/dev/null
 export CM_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p)
+dd if=/dev/urandom of=enc.data bs=12K count=1 2>/dev/null
 balloonparams="-balloon-s 123 -balloon-t 2"
-test_expect_success "key encrypting" "
+
+for algo in sntrup761-x25519 mceliece6960119-x25519 ; do
+
+test_expect_success "$algo: key generation" "
+    cmkeytool -algo $algo -ku kem -sub A=KEY 5>enc.pub 9>enc.prv"
+test_expect_success "$algo: key encrypting" "
     cmenctool -p -embed $balloonparams <enc.prv >enc.prv.enc"
-test_expect_success "data encrypting" "
-    cmenctool 4<enc.pub <enc.data >enc.enc"
-test_expect_success "decrypting" "
-    cmenctool -d 8<enc.prv.enc <enc.enc >enc.data.got"
-test_expect_success "comparing" "test_cmp enc.data enc.data.got"
+test_expect_success "$algo: data encrypting" "
+    cmenctool -to enc.pub <enc.data >enc.enc"
+ln -s enc.prv.enc $(kekspp -v -p /data/id <enc.pub)
+test_expect_success "$algo: decrypting" "
+    cmenctool -d -prvs . <enc.enc >enc.data.got"
+test_expect_success "$algo: comparing" "test_cmp enc.data enc.data.got"
+
+done
 
 test_done
index 4471ebfb60d9460a93a5f9300f67a8f75a1b452c15039efa24415044199ef33e..ab24e3bb19a37726fea4e6735b2a994f75c5f009608a6832df9ec61c3a5e9589 100755 (executable)
@@ -10,35 +10,39 @@ algo=mceliece6960119-x25519
 algo0=$algo
 test_expect_success "$algo: pub generation" "
     cmkeytool -algo $algo -ku kem -sub A=$algo 5>enc.$algo.pub 9>enc.$algo.prv"
+id0=$(kekspp -v -p /data/id <enc.$algo.pub)
 algo=sntrup761-x25519
 algo1=$algo
 test_expect_success "$algo: pub generation" "
     cmkeytool -algo $algo -ku kem -sub A=$algo 5>enc.$algo.pub 9>enc.$algo.prv"
+id1=$(kekspp -v -p /data/id <enc.$algo.pub)
 
 test_expect_success "encrypting" "
-    cat enc.$algo0.pub enc.$algo1.pub |
-    cmenctool 4<&0 <enc.data >enc.enc"
+    cmenctool -to enc.$algo0.pub -to enc.$algo1.pub <enc.data >enc.enc"
 
+ln -s enc.$algo0.prv $id0
+ln -s enc.$algo1.prv $id1
 test_expect_success "any: decrypting" "
-    cat enc.$algo0.prv enc.$algo1.prv |
-    cmenctool -d 8<&0 <enc.enc >enc.data.got"
+    cmenctool -d -prvs . <enc.enc >enc.data.got"
 test_expect_success "comparing" "test_cmp enc.data enc.data.got"
 
+rm $id1
 test_expect_success "$algo0: decrypting" "
-    cmenctool -d 8<enc.$algo0.prv <enc.enc >enc.data.got"
+    cmenctool -d -prvs . <enc.enc >enc.data.got"
 test_expect_success "$algo0: comparing" "test_cmp enc.data enc.data.got"
 
+rm $id0
+ln -s enc.$algo1.prv $id1
 test_expect_success "$algo1: decrypting" "
-    cmenctool -d 8<enc.$algo1.prv <enc.enc >enc.data.got"
+    cmenctool -d -prvs . <enc.enc >enc.data.got"
+ln -s enc.$algo0.prv $id0
 test_expect_success "$algo1: comparing" "test_cmp enc.data enc.data.got"
 
 export CM_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p)
 test_expect_success "encrypting also with passphrase" "
-    cat enc.$algo0.pub enc.$algo1.pub |
-    cmenctool $balloonparams -p 4<&0 <enc.data >enc.enc"
+    cmenctool $balloonparams -p -to enc.$algo0.pub -to enc.$algo1.pub <enc.data >enc.enc"
 test_expect_success "any: decrypting" "
-    cat enc.$algo0.prv enc.$algo1.prv |
-    cmenctool -d 8<&0 <enc.enc >enc.data.got"
+    cmenctool -d -prvs . <enc.enc >enc.data.got"
 test_expect_success "comparing" "test_cmp enc.data enc.data.got"
 test_expect_success "passphrase: decrypting" "
     cmenctool -d -p <enc.enc >enc.data.got"
diff --git a/go/cm/cmd/cmenctool/sender-auth.t b/go/cm/cmd/cmenctool/sender-auth.t
new file mode 100755 (executable)
index 0000000..c9079b3
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description="Sender authentication"
+. $SHARNESS_TEST_SRCDIR/sharness.sh
+
+dd if=/dev/urandom of=enc.data bs=300K count=1 2>/dev/null
+mkdir prvs pubs
+
+for algo in sntrup761-x25519 mceliece6960119-x25519 ; do
+
+test_expect_success "$algo: sender pub generation" "cmkeytool \
+    -algo $algo -ku kem -sub N=S 5>s.pub 9>s.prv"
+test_expect_success "$algo: recipient pub generation" "cmkeytool \
+    -algo $algo -ku kem -sub N=R 5>r.pub 9>r.prv"
+ln -fs ../s.prv prvs/$(kekspp -v -p /data/id <s.pub)
+ln -fs ../r.prv prvs/$(kekspp -v -p /data/id <r.pub)
+ln -fs ../s.pub pubs/$(kekspp -v -p /data/id <s.pub)
+ln -fs ../r.pub pubs/$(kekspp -v -p /data/id <r.pub)
+test_expect_success "$algo: encrypting" "cmenctool \
+    -from s.pub -prvs prvs -to r.pub <enc.data >enc.enc"
+test_expect_success "$algo: decrypting" "
+    cmenctool -d -prvs prvs -pubs pubs <enc.enc >enc.data.got"
+test_expect_success "$algo: comparing" "test_cmp enc.data enc.data.got"
+ln -fs ../r.pub pubs/$(kekspp -v -p /data/id <s.pub)
+test_expect_success "$algo: bad auth" "
+    ! cmenctool -d -prvs prvs -pubs pubs <enc.enc >enc.data.got"
+
+done
+
+test_done
index 937e5d5c9f4b6ee17d39b696cb1b9be1fee3c0a79ca15385f0ac0093c5f2e006..c2d43d9a3bfa30b0b49f476118c063c2152b4542df72cc06cfe9f2e75f568b50 100644 (file)
@@ -24,12 +24,17 @@ import (
 func usage() {
        fmt.Fprintf(os.Stderr, `Usage:
   Encrypt to recipient(s):
-    cmenctool [-include-to] 4<PUB[,PUB1...] <DATA >DATA.encrypted
+    cmenctool [-no-to] -to PUB0 [-to PUB1 ...] <DATA >DATA.encrypted
   Encrypt on passphrase:
     cmenctool -p [-balloon-s X] [-balloon-t X] [-balloon-p X] <DATA >DATA.encrypted
   Decrypt by providing possible KEMs and/or passphrase(s):
-    cmenctool -d [-p] 8<PRV0[,PRV1...] <DATA.encrypted >DATA
+    cmenctool -d [-p] -prvs prvs/dir <DATA.encrypted >DATA
+  With sender authentication:
+    cmenctool [...] -from PUB -prvs prvs/dir [...]
+    cmenctool [...] -d -pubs pubs/dir [...]
 
+{prvs,pubs}/dir must contain key files with uppercase hexadecimal
+corresponding public key's id used as the filename.
 `)
        flag.PrintDefaults()
 }
index 1d1521ba93d3f9addeb37dc9e0d79b49f0b9851c10a1ba322b840ca2c6cd61c9..1a421451e1564d08c2afb55ef927cc1ed09ada95d446a11bc4e2fde87dd7a0e7 100644 (file)
@@ -5,16 +5,19 @@ import (
 )
 
 const (
-       SNTRUP761X25519Info = "cm/encrypted/sntrup761-x25519-hkdf-blake2b"
+       SNTRUP761X25519Info     = "cm/encrypted/sntrup761-x25519-hkdf-blake2b"
+       SNTRUP761X25519AuthInfo = "cm/encrypted/sntrup761-x25519-hkdf-blake2b/auth"
 
        ClassicMcEliece6960119X25519Info      = "cm/encrypted/mceliece6960119-x25519-hkdf-shake256"
+       ClassicMcEliece6960119X25519AuthInfo  = "cm/encrypted/mceliece6960119-x25519-hkdf-shake256/auth"
        ClassicMcEliece6960119X25519DecapInfo = "cm/encrypted/mceliece6960119-x25519-hkdf-shake256/decap"
 )
 
 type KEM struct {
-       A   string `keks:"a"`
-       CEK []byte `keks:"cek"`
-       To  []byte `keks:"to,omitempty"`
+       A    string `keks:"a"`
+       CEK  []byte `keks:"cek"`
+       To   []byte `keks:"to,omitempty"`
+       From []byte `keks:"from,omitempty"`
 
        // balloon-blake2b-hkdf related
        BalloonCost *balloon.Cost `keks:"cost,omitempty"`
index 67034d82fbbd413b5d3b1a73f39a23fbc91d24b14f4e2780f083027921b860e1..b7d7ceb9f5b47ee53ea45f81eee408bb85712334e6573c75e31ffafdb938ce67 100644 (file)
@@ -8,8 +8,3 @@ sender's key that way -- implementation/protocol specific.
 Optional "/pubs" is a list public keys, which may be used to supply
 sender's public key(s). Public keys may be encrypted, to hide the actual
 deanonymisation contents.
-
-It is *highly* recommended to use multi-recipient safe DEM when
-encrypting to multiple recipients. For example [cm/dem/xchacha-krmr]
-instead of [cm/dem/xchapoly-krkc], but unfortunately with the price of
-more expensive double pass authentication scheme.
index d5bd6cfbfba4f06397430b39c95f3829f8491ceed7557fff0c436e7c61d528e9..d7319762c2ff449fb023a4e399fcd2353592bb8bdc54875c1f046c9fb48358a2 100644 (file)
@@ -40,6 +40,11 @@ Optional "/id" is used in KEMs for domain separation and envelope
 identification. UUIDv4 is recommended.
 If absent, then null UUID is used in KDF.
 
+It is *highly* recommended to use multi-recipient safe DEM when
+encrypting to multiple recipients. For example [cm/dem/xchacha-krmr]
+instead of [cm/dem/xchapoly-krkc], but unfortunately with the price of
+more expensive double pass authentication scheme.
+
 [cm/encrypted/authcrypt] -- authenticated public-key encryption
 [cm/keywrap/] | key wrapping mechanisms
 [cm/dem/]     | data encapsulation mechanisms
index c0a2e90e437a90dff6f7d11804b059ee61174af186ab677f70b9c94e24b24c2e..86e05d6822a5e3992f189c79111daa7a762780199232aae933f33aa666f70f39 100644 (file)
@@ -23,11 +23,11 @@ Classic McEliece 6960-119 ciphertext, with XChaCha20-Poly1305-encrypted
 Recipient performs Classic McEliece decapsulation, decrypts ephemeral
 X25519 public key, computes shared secrets, combines them and derives KEK.
 
-          ====================================================
+            ================================================
                                 WARNING
-          ====================================================
-          Sender authentication uses only *NON*-PQ crypto!
-          ====================================================
+            ================================================
+            Sender authentication uses only *NON*-PQ crypto!
+            ================================================
 
     H = SHAKE256
     mceliece-ciphertext, mceliece-shared-key = KEM-Encap(mceliece-recipient-public-key)
@@ -46,8 +46,8 @@ X25519 public key, computes shared secrets, combines them and derives KEK.
                                       s-x25519-recipient-public-key)
         PRK = HKDF-Expand(H, prk=PRK,
             info="cm/encrypted/mceliece6960119-x25519-hkdf-shake256/auth")
-        PRK = HKDF-Extract(H, salt=PRK, ikm=
-            ss-x25519-shared-key || s-x25519-sender-public-key)
+        PRK = HKDF-Extract(H, salt=PRK, ikm= ss-x25519-shared-key ||
+            s-x25519-sender-public-key || s-x25519-recipient-public-key)
     KEK = HKDF-Expand(H, prk=PRK,
         info="cm/encrypted/mceliece6960119-x25519-hkdf-shake256" || /id)
 
index f9fc4c9880a329a3c10807a0004f0782240d690ee9769a82145b2b80d4fef4ff..af4d837f26bfd0ea470b2e010fa86bd987bb18c3b96e80b1a2b6d4c8032a95b5 100644 (file)
@@ -18,11 +18,11 @@ Recipient performs X25519 and SNTRUP computations to derive/decapsulate
 two 32-byte shared keys. Then it combines them to get the KEK decryption
 key of the CEK.
 
-          ====================================================
+            ================================================
                                 WARNING
-          ====================================================
-          Sender authentication uses only *NON*-PQ crypto!
-          ====================================================
+            ================================================
+            Sender authentication uses only *NON*-PQ crypto!
+            ================================================
 
     H = BLAKE2b
     PRK = HKDF-Extract(H, salt="", ikm=
@@ -30,12 +30,12 @@ key of the CEK.
         H(sntrup761-sender-ciphertext || e-x25519-sender-public-key) ||
         H(sntrup761-recipient-public-key || s-x25519-recipient-public-key))
     if {specified sender}
+        ss-x25519-shared-key = X25519(s-x25519-sender-private-key,
+                                      s-x25519-recipient-public-key)
         PRK = HKDF-Expand(H, prk=PRK,
             info="cm/encrypted/sntrup761-x25519-hkdf-blake2b/auth")
-        PRK = HKDF-Extract(H, salt=PRK, ikm=
-            ss-x25519-shared-key ||
-            s-x25519-sender-public-key ||
-            s-x25519-recipient-public-key)
+        PRK = HKDF-Extract(H, salt=PRK, ikm= ss-x25519-shared-key ||
+            s-x25519-sender-public-key || s-x25519-recipient-public-key)
     KEK = HKDF-Expand(H, prk=PRK,
         info="cm/encrypted/sntrup761-x25519-hkdf-blake2b" || /id)