From f09d6bbfef00243c918d882f066c8f56796f7c94 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Mon, 8 Apr 2019 21:58:33 -0700 Subject: [PATCH] Added NEWHOPE and NEWHOPE_SIMPLE KEM algs Fixed some -h typos, missing H_SHA512 option randReader seed time.Now().UnixNano() Signed-off-by: Russ Magee --- consts.go | 2 +- hkexnet/consts.go | 4 +- hkexnet/hkexnet.go | 213 +++++++++++++++++++++++++++++++++++++++++++-- hkexsh/hkexsh.go | 6 +- hkexshd/hkexshd.go | 2 +- 5 files changed, 213 insertions(+), 14 deletions(-) diff --git a/consts.go b/consts.go index 7dd9828..b65c4a9 100644 --- a/consts.go +++ b/consts.go @@ -10,4 +10,4 @@ package hkexsh // common constants for the HKExSh // Version string returned by tools -const Version = "0.8.0 (NO WARRANTY)" +const Version = "0.8.1 (NO WARRANTY)" diff --git a/hkexnet/consts.go b/hkexnet/consts.go index 38b67e8..7ed1c3b 100644 --- a/hkexnet/consts.go +++ b/hkexnet/consts.go @@ -20,8 +20,8 @@ const ( KEX_KYBER768 KEX_KYBER1024 KEX_resvd11 - KEX_resvd12 - KEX_resvd13 + KEX_NEWHOPE + KEX_NEWHOPE_SIMPLE // 'NewHopeLP-Simple' - https://eprint.iacr.org/2016/1157 KEX_resvd14 KEX_resvd15 ) diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index 4d86971..caa834b 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -49,6 +49,7 @@ import ( "blitter.com/go/herradurakex" "blitter.com/go/hkexsh/logger" kyber "git.schwanenlied.me/yawning/kyber.git" + newhope "git.schwanenlied.me/yawning/newhope.git" ) /*---------------------------------------------------------------------*/ @@ -197,6 +198,12 @@ func getkexalgnum(extensions ...string) (k KEXAlg) { case "KEX_KYBER1024": k = KEX_KYBER1024 break //out of for + case "KEX_NEWHOPE": + k = KEX_NEWHOPE + break //out of for + case "KEX_NEWHOPE_SIMPLE": + k = KEX_NEWHOPE_SIMPLE + break //out of for } } return @@ -227,12 +234,16 @@ func _new(kexAlg KEXAlg, conn *net.Conn) (hc *Conn, e error) { case KEX_HERRADURA1024: fallthrough case KEX_HERRADURA2048: - log.Printf("[KEx alg %d accepted]\n", kexAlg) + fallthrough case KEX_KYBER512: fallthrough case KEX_KYBER768: fallthrough case KEX_KYBER1024: + fallthrough + case KEX_NEWHOPE: + fallthrough + case KEX_NEWHOPE_SIMPLE: log.Printf("[KEx alg %d accepted]\n", kexAlg) default: // UNREACHABLE: _getkexalgnum() guarantees a valid KEX value @@ -276,7 +287,7 @@ func (hc *Conn) applyConnExtensions(extensions ...string) { } // randReader wraps rand.Read() in a struct that implements io.Reader -// for use by the Kyber KEM methods. +// for use by the Kyber and NEWHOPE/NEWHOPE_SIMPLE KEM methods. type randReader struct { } @@ -285,11 +296,101 @@ func (r randReader) Read(b []byte) (n int, e error) { return } +func NewHopeDialSetup(c io.ReadWriter, hc *Conn) (err error) { + // Send hkexnet.Conn parameters to remote side + + // Alice, step 1: Generate a key pair. + r := new(randReader) + rand.Seed(time.Now().UnixNano()) + + privKeyAlice, pubKeyAlice, err := newhope.GenerateKeyPairAlice(r) + if err != nil { + panic(err) + } + + // Alice, step 2: Send the public key to Bob + fmt.Fprintf(c, "0x%x\n0x%x:0x%x\n", pubKeyAlice.Send, + hc.cipheropts, hc.opts) + + // [Bob does step 1-3], from which we read Bob's pubkey + publicKeyBob := big.NewInt(0) + fmt.Fscanf(c, "0x%x\n", publicKeyBob) + var pubKeyBob newhope.PublicKeyBob + for i := range(pubKeyBob.Send) { + pubKeyBob.Send[i] = publicKeyBob.Bytes()[i] + } + log.Printf("[Got server pubKey[]:%v]\n", pubKeyBob) + + // Read cipheropts, session opts + _, err = fmt.Fscanf(c, "0x%x:0x%x\n", + &hc.cipheropts, &hc.opts) + if err != nil { + return err + } + + // Alice, step 3: Derive shared secret + // (NOTE: actual over-wire exchange was already done above. This is + // the math voodoo 'exchange' done after receiving data from Bob.) + aliceSharedSecret, err := newhope.KeyExchangeAlice(&pubKeyBob, privKeyAlice) + if err != nil { + panic(err) + } + log.Printf("[Derived sharedSecret:0x%x]\n", aliceSharedSecret) + hc.r, hc.rm, err = hc.getStream(aliceSharedSecret) + hc.w, hc.wm, err = hc.getStream(aliceSharedSecret) + return +} + +func NewHopeSimpleDialSetup(c io.ReadWriter, hc *Conn) (err error) { + // Send hkexnet.Conn parameters to remote side + + // Alice, step 1: Generate a key pair. + r := new(randReader) + rand.Seed(time.Now().UnixNano()) + privKeyAlice, pubKeyAlice, err := newhope.GenerateKeyPairSimpleAlice(r) + if err != nil { + panic(err) + } + + // Alice, step 2: Send the public key to Bob + fmt.Fprintf(c, "0x%x\n0x%x:0x%x\n", pubKeyAlice.Send, + hc.cipheropts, hc.opts) + + // [Bob does step 1-3], from which we read Bob's pubkey + publicKeyBob := big.NewInt(0) + fmt.Fscanf(c, "0x%x\n", publicKeyBob) + var pubKeyBob newhope.PublicKeySimpleBob + for i := range(pubKeyBob.Send) { + pubKeyBob.Send[i] = publicKeyBob.Bytes()[i] + } + log.Printf("[Got server pubKey[]:%v]\n", pubKeyBob) + + // Read cipheropts, session opts + _, err = fmt.Fscanf(c, "0x%x:0x%x\n", + &hc.cipheropts, &hc.opts) + if err != nil { + return err + } + + // Alice, step 3: Derive shared secret + // (NOTE: actual over-wire exchange was already done above. This is + // the math voodoo 'exchange' done after receiving data from Bob.) + aliceSharedSecret, err := newhope.KeyExchangeSimpleAlice(&pubKeyBob, privKeyAlice) + if err != nil { + panic(err) + } + log.Printf("[Derived sharedSecret:0x%x]\n", aliceSharedSecret) + hc.r, hc.rm, err = hc.getStream(aliceSharedSecret) + hc.w, hc.wm, err = hc.getStream(aliceSharedSecret) + return +} + func KyberDialSetup(c io.ReadWriter /*net.Conn*/, hc *Conn) (err error) { // Send hkexnet.Conn parameters to remote side // Alice, step 1: Generate a key pair. r := new(randReader) + rand.Seed(time.Now().UnixNano()) var alicePublicKey *kyber.PublicKey var alicePrivateKey *kyber.PrivateKey switch hc.kex { @@ -312,12 +413,12 @@ func KyberDialSetup(c io.ReadWriter /*net.Conn*/, hc *Conn) (err error) { hc.cipheropts, hc.opts) // [Bob, step 1-3], from which we read cipher text - cipherB := make([]byte, 4096) - fmt.Fscanf(c, "0x%x\n", &cipherB) + pubKeyB := make([]byte, 4096) + fmt.Fscanf(c, "0x%x\n", &pubKeyB) //if err != nil { // return err //} - log.Printf("[Got server ciphertext[]:%v]\n", cipherB) + log.Printf("[Got server pubKeyB[]:%v]\n", pubKeyB) // Read cipheropts, session opts _, err = fmt.Fscanf(c, "0x%x:0x%x\n", @@ -327,7 +428,7 @@ func KyberDialSetup(c io.ReadWriter /*net.Conn*/, hc *Conn) (err error) { } // Alice, step 3: Decrypt the KEM cipher text. - aliceSharedSecret := alicePrivateKey.KEMDecrypt(cipherB) + aliceSharedSecret := alicePrivateKey.KEMDecrypt(pubKeyB) log.Printf("[Derived sharedSecret:0x%x]\n", aliceSharedSecret) hc.r, hc.rm, err = hc.getStream(aliceSharedSecret) @@ -378,6 +479,84 @@ func HKExDialSetup(c io.ReadWriter /*net.Conn*/, hc *Conn) (err error) { return } +func NewHopeAcceptSetup(c *net.Conn, hc *Conn) (err error) { + r := new(randReader) + rand.Seed(time.Now().UnixNano()) + // Bob, step 1: Deserialize Alice's public key from the binary encoding. + alicePublicKey := big.NewInt(0) + _, err = fmt.Fscanln(*c, alicePublicKey) + log.Printf("[Got client pubKey:0x%x\n]", alicePublicKey) + if err != nil { + return err + } + + var pubKeyAlice newhope.PublicKeyAlice + for i := range(pubKeyAlice.Send) { + pubKeyAlice.Send[i] = alicePublicKey.Bytes()[i] + } + + _, err = fmt.Fscanf(*c, "0x%x:0x%x\n", + &hc.cipheropts, &hc.opts) + log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts) + if err != nil { + return err + } + + // Bob, step 2: Generate the KEM cipher text and shared secret. + pubKeyBob, bobSharedSecret, err := newhope.KeyExchangeBob(r, &pubKeyAlice) + if err != nil { + panic(err) + } + + // Bob, step 3: Send the cipher text to Alice. + fmt.Fprintf(*c, "0x%x\n0x%x:0x%x\n", pubKeyBob.Send, + hc.cipheropts, hc.opts) + + log.Printf("[Derived sharedSecret:0x%x]\n", bobSharedSecret) + hc.r, hc.rm, err = hc.getStream(bobSharedSecret) + hc.w, hc.wm, err = hc.getStream(bobSharedSecret) + return +} + +func NewHopeSimpleAcceptSetup(c *net.Conn, hc *Conn) (err error) { + r := new(randReader) + rand.Seed(time.Now().UnixNano()) + // Bob, step 1: Deserialize Alice's public key from the binary encoding. + alicePublicKey := big.NewInt(0) + _, err = fmt.Fscanln(*c, alicePublicKey) + log.Printf("[Got client pubKey:0x%x\n]", alicePublicKey) + if err != nil { + return err + } + + var pubKeyAlice newhope.PublicKeySimpleAlice + for i := range(pubKeyAlice.Send) { + pubKeyAlice.Send[i] = alicePublicKey.Bytes()[i] + } + + _, err = fmt.Fscanf(*c, "0x%x:0x%x\n", + &hc.cipheropts, &hc.opts) + log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts) + if err != nil { + return err + } + + // Bob, step 2: Generate the KEM cipher text and shared secret. + pubKeyBob, bobSharedSecret, err := newhope.KeyExchangeSimpleBob(r, &pubKeyAlice) + if err != nil { + panic(err) + } + + // Bob, step 3: Send the cipher text to Alice. + fmt.Fprintf(*c, "0x%x\n0x%x:0x%x\n", pubKeyBob.Send, + hc.cipheropts, hc.opts) + + log.Printf("[Derived sharedSecret:0x%x]\n", bobSharedSecret) + hc.r, hc.rm, err = hc.getStream(bobSharedSecret) + hc.w, hc.wm, err = hc.getStream(bobSharedSecret) + return +} + func KyberAcceptSetup(c *net.Conn, hc *Conn) (err error) { // Bob, step 1: Deserialize Alice's public key from the binary encoding. alicePublicKey := big.NewInt(0) @@ -411,13 +590,13 @@ func KyberAcceptSetup(c *net.Conn, hc *Conn) (err error) { // Bob, step 2: Generate the KEM cipher text and shared secret. r := new(randReader) + rand.Seed(time.Now().UnixNano()) cipherText, bobSharedSecret, err := peerPublicKey.KEMEncrypt(r) if err != nil { panic(err) } // Bob, step 3: Send the cipher text to Alice. - //fmt.Println("cipherText:",cipherText) fmt.Fprintf(*c, "0x%x\n0x%x:0x%x\n", cipherText, hc.cipheropts, hc.opts) @@ -525,6 +704,16 @@ func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err er if KyberDialSetup(c, &hc) != nil { return Conn{}, nil } + case KEX_NEWHOPE: + log.Printf("[Setting up for KEX_NEWHOPE %d]\n", hc.kex) + if NewHopeDialSetup(c, &hc) != nil { + return Conn{}, nil + } + case KEX_NEWHOPE_SIMPLE: + log.Printf("[Setting up for KEX_NEWHOPE_SIMPLE %d]\n", hc.kex) + if NewHopeSimpleDialSetup(c, &hc) != nil { + return Conn{}, nil + } default: return Conn{}, err } @@ -686,6 +875,16 @@ func (hl *HKExListener) Accept() (hc Conn, err error) { if KyberAcceptSetup(&c, &hc) != nil { return Conn{}, err } + case KEX_NEWHOPE: + log.Printf("[Setting up for KEX_NEWHOPE %d]\n", hc.kex) + if NewHopeAcceptSetup(&c, &hc) != nil { + return Conn{}, err + } + case KEX_NEWHOPE_SIMPLE: + log.Printf("[Setting up for KEX_NEWHOPE_SIMPLE %d]\n", hc.kex) + if NewHopeSimpleAcceptSetup(&c, &hc) != nil { + return Conn{}, err + } default: return Conn{}, err } diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index ac7d0cc..701446a 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -623,11 +623,11 @@ func main() { flag.BoolVar(&vopt, "v", false, "show version") flag.BoolVar(&dbg, "d", false, "debug logging") flag.StringVar(&cipherAlg, "c", "C_AES_256", "`cipher` [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\" | \"C_CRYPTMT1\"]") - flag.StringVar(&hmacAlg, "m", "H_SHA256", "`hmac` [\"H_SHA256\"]") - flag.StringVar(&kexAlg, "k", "KEX_HERRADURA256", "`kex` [\"KEX_HERRADURA{256/512/1024/2048}\" | \"KEX_KYBER{512/768/1024}\"]") + flag.StringVar(&hmacAlg, "m", "H_SHA256", "`hmac` [\"H_SHA256\" | \"H_SHA512\"]") + flag.StringVar(&kexAlg, "k", "KEX_HERRADURA256", "`kex` [\"KEX_HERRADURA{256/512/1024/2048}\" | \"KEX_KYBER{512/768/1024}\" | \"KEX_NEWHOPE\" | \"KEX_NEWHOPE_SIMPLE\"]") flag.UintVar(&port, "p", 2000, "`port`") //flag.StringVar(&authCookie, "a", "", "auth cookie") - flag.BoolVar(&chaffEnabled, "e", true, "enabled chaff pkts (default true)") + flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") flag.UintVar(&chaffFreqMin, "f", 100, "`msecs-min` chaff pkt freq min (msecs)") flag.UintVar(&chaffFreqMax, "F", 5000, "`msecs-max` chaff pkt freq max (msecs)") flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max (bytes)") diff --git a/hkexshd/hkexshd.go b/hkexshd/hkexshd.go index 473aab7..4ee07d8 100755 --- a/hkexshd/hkexshd.go +++ b/hkexshd/hkexshd.go @@ -387,7 +387,7 @@ func main() { flag.BoolVar(&vopt, "v", false, "show version") flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") - flag.BoolVar(&chaffEnabled, "e", true, "enabled chaff pkts") + flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min (msecs)") flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max (msecs)") flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max (bytes)")