Permalink
Browse files

tris: experimental X25519+SIDH hybrid key agreement

This uses the Go SIDH implementation to do a hybrid X25519+SIDH key agreement.
The SIDHP751AndX25519 key agreement (code 0xFE24, in the private use block)
uses the first 32 bytes of the keyshare to do X25519 and the remaining 564
bytes to do an SIDH P-751 key agreement.  The shared secrets are concatenated
together and fed into the TLS key derivation mechanism.

At the moment this branch won't build without manually vendoring the Go SIDH
implementation into the custom GOROOT.
  • Loading branch information...
hdevalence committed Aug 29, 2017
1 parent 9b08dfa commit e47a4e7e1a5e11d1a3adab392248399ae7426695
Showing with 100 additions and 17 deletions.
  1. +91 −10 13.go
  2. +3 −3 _dev/tris-client/client.go
  3. +1 −0 _dev/tris-localserver/server.go
  4. +5 −4 common.go
View
101 13.go
@@ -23,13 +23,22 @@ import (
"sync/atomic"
"time"
"github_com/cloudflare/p751sidh"
"golang_org/x/crypto/curve25519"
)
// numSessionTickets is the number of different session tickets the
// server sends to a TLS 1.3 client, who will use each only once.
const numSessionTickets = 2
// In SIDH, the computations done by Alice are different from Bob's.
type dhRole bool
const (
dhRoleServer dhRole = true
dhRoleClient dhRole = false
)
func (hs *serverHandshakeState) doTLS13Handshake() error {
config := hs.c.config
c := hs.c
@@ -61,7 +70,7 @@ CurvePreferenceLoop:
}
}
privateKey, serverKS, err := config.generateKeyShare(ks.group)
privateKey, serverKS, err := config.generateKeyShare(ks.group, dhRoleServer)
if err != nil {
c.sendAlert(alertInternalError)
return err
@@ -93,8 +102,8 @@ CurvePreferenceLoop:
handshakeCtx := hs.finishedHash13.Sum(nil)
earlyClientCipher, _ := hs.suite.prepareCipher(handshakeCtx, earlySecret, "client early traffic secret")
ecdheSecret := deriveECDHESecret(ks, privateKey)
if ecdheSecret == nil {
dheSecret := deriveDHESecret(ks, privateKey, dhRoleServer)
if dheSecret == nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: bad ECDHE client share")
}
@@ -104,7 +113,7 @@ CurvePreferenceLoop:
return err
}
handshakeSecret := hkdfExtract(hash, ecdheSecret, earlySecret)
handshakeSecret := hkdfExtract(hash, dheSecret, earlySecret)
handshakeCtx = hs.finishedHash13.Sum(nil)
clientCipher, cTrafficSecret := hs.suite.prepareCipher(handshakeCtx, handshakeSecret, "client handshake traffic secret")
hs.hsClientCipher = clientCipher
@@ -367,7 +376,38 @@ func prepareDigitallySigned(hash crypto.Hash, context string, data []byte) []byt
return h.Sum(nil)
}
func (c *Config) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
func (c *Config) generateKeyShare(curveID CurveID, role dhRole) ([]byte, keyShare, error) {
if curveID == SIDHP751AndX25519 {
var scalarX25519, publicX25519 [32]byte
if _, err := io.ReadFull(c.rand(), scalarX25519[:]); err != nil {
return nil, keyShare{}, err
}
curve25519.ScalarBaseMult(&publicX25519, &scalarX25519)
var secret [32 + p751sidh.SecretKeySize]byte
var public [32 + p751sidh.PublicKeySize]byte
copy(secret[:32], scalarX25519[:])
copy(public[:32], publicX25519[:])
// Alice's computations are slightly cheaper, so we use them on the server.
if role == dhRoleServer {
var publicSIDH, secretSIDH, err = p751sidh.GenerateAliceKeypair(c.rand())
if err != nil {
return nil, keyShare{}, err
}
copy(secret[32:], secretSIDH.Scalar[:])
publicSIDH.ToBytes(public[32:])
} else {
var publicSIDH, secretSIDH, err = p751sidh.GenerateBobKeypair(c.rand())
if err != nil {
return nil, keyShare{}, err
}
copy(secret[32:], secretSIDH.Scalar[:])
publicSIDH.ToBytes(public[32:])
}
return secret[:], keyShare{group: curveID, data: public[:]}, nil
}
if curveID == X25519 {
var scalar, public [32]byte
if _, err := io.ReadFull(c.rand(), scalar[:]); err != nil {
@@ -392,7 +432,48 @@ func (c *Config) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
return privateKey, keyShare{group: curveID, data: ecdhePublic}, nil
}
func deriveECDHESecret(ks keyShare, secretKey []byte) []byte {
func deriveDHESecret(ks keyShare, secretKey []byte, role dhRole) []byte {
if ks.group == SIDHP751AndX25519 {
if len(ks.data) != 32+p751sidh.PublicKeySize {
return nil
}
if len(secretKey) != 32+p751sidh.SecretKeySize {
return nil
}
var theirX25519Public, sharedX25519Secret, ourX25519Secret [32]byte
copy(theirX25519Public[:], ks.data[:32])
copy(ourX25519Secret[:], secretKey[:32])
curve25519.ScalarMult(&sharedX25519Secret, &ourX25519Secret, &theirX25519Public)
var sharedSIDHSecret [p751sidh.SharedSecretSize]byte
// Alice's computations are slightly cheaper, so we use them on the server.
if role == dhRoleServer {
var theirSIDHPublic p751sidh.SIDHPublicKeyBob
theirSIDHPublic.FromBytes(ks.data[32:])
var ourSIDHSecret p751sidh.SIDHSecretKeyAlice
copy(ourSIDHSecret.Scalar[:], secretKey[32:])
sharedSIDHSecret = ourSIDHSecret.SharedSecret(&theirSIDHPublic)
} else {
var theirSIDHPublic p751sidh.SIDHPublicKeyAlice
theirSIDHPublic.FromBytes(ks.data[32:])
var ourSIDHSecret p751sidh.SIDHSecretKeyBob
copy(ourSIDHSecret.Scalar[:], secretKey[32:])
sharedSIDHSecret = ourSIDHSecret.SharedSecret(&theirSIDHPublic)
}
var sharedSecret [32 + p751sidh.SharedSecretSize]byte
copy(sharedSecret[:32], sharedX25519Secret[:])
copy(sharedSecret[32:], sharedSIDHSecret[:])
return sharedSecret[:]
}
if ks.group == X25519 {
if len(ks.data) != 32 {
return nil
@@ -730,7 +811,7 @@ func (hs *clientHandshakeState) startTLS13ClientHandshake() error {
// forces handling the case of an extra round trip
var preferredCurve = hello.supportedCurves[0]
privateKey, clientKeyShare, err := config.generateKeyShare(preferredCurve)
privateKey, clientKeyShare, err := config.generateKeyShare(preferredCurve, dhRoleClient)
if err != nil {
return err
}
@@ -783,15 +864,15 @@ func (hs *clientHandshakeState) doTLS13ClientHandshake() error {
earlySecret := hkdfExtract(hash, nil, nil)
serverKeyShare := hs.serverHello13.keyShare
ecdheSecret := deriveECDHESecret(serverKeyShare, hs.keySharePrivateKey)
if ecdheSecret == nil {
dheSecret := deriveDHESecret(serverKeyShare, hs.keySharePrivateKey, dhRoleClient)
if dheSecret == nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: bad ECDHE client share")
}
hs.finishedHash13.Write(hs.serverHello13.marshal())
handshakeSecret := hkdfExtract(hash, ecdheSecret, earlySecret)
handshakeSecret := hkdfExtract(hash, dheSecret, earlySecret)
handshakeCtx := hs.finishedHash13.Sum(nil)
clientCipher, cTrafficSecret := suite.prepareCipher(handshakeCtx, handshakeSecret, "client handshake traffic secret")
serverCipher, sTrafficSecret := suite.prepareCipher(handshakeCtx, handshakeSecret, "server handshake traffic secret")
@@ -18,8 +18,8 @@ func main() {
config := &tls.Config{
MaxVersion: tls.VersionTLS13Draft18,
//MaxVersion: tls.VersionTLS12,
//InsecureSkipVerify: true,
CurvePreferences: []tls.CurveID{tls.SIDHP751AndX25519},
InsecureSkipVerify: true,
}
trans := &http.Transport{TLSClientConfig: config}
@@ -29,7 +29,7 @@ func main() {
if err != nil {
panic(err)
}
fmt.Println("RESPONSE:")
fmt.Println("%v", resp)
}
@@ -34,6 +34,7 @@ func startServer(addr string, rsa, offer0RTT, accept0RTT, shortHdr bool) {
s := &http.Server{
Addr: addr,
TLSConfig: &tls.Config{
CurvePreferences: []tls.CurveID{tls.SIDHP751AndX25519, tls.X25519},
Certificates: []tls.Certificate{cert},
Max0RTTDataSize: Max0RTTDataSize,
Accept0RTTData: accept0RTT,
View
@@ -114,10 +114,11 @@ const (
type CurveID uint16
const (
CurveP256 CurveID = 23
CurveP384 CurveID = 24
CurveP521 CurveID = 25
X25519 CurveID = 29
CurveP256 CurveID = 23
CurveP384 CurveID = 24
CurveP521 CurveID = 25
X25519 CurveID = 29
SIDHP751AndX25519 CurveID = 0xFE24 // 0xFE00-0xFEFF private use block; 24 is magic
)
// TLS 1.3 Key Share

0 comments on commit e47a4e7

Please sign in to comment.