40 lines
1.4 KiB
Go
40 lines
1.4 KiB
Go
package primitives
|
|
|
|
import (
|
|
"golang.org/x/crypto/ed25519"
|
|
"golang.org/x/crypto/sha3"
|
|
)
|
|
|
|
// Perform3DH encapsulates a triple-diffie-hellman key exchange.
|
|
// In this exchange Alice and Bob both hold longterm identity keypairs
|
|
// Both Alice and Bob generate an additional ephemeral key pair:
|
|
// Three Diffie Hellman exchanges are then performed:
|
|
// Alice Long Term <-> Bob Ephemeral
|
|
// Alice Ephemeral <-> Bob Long Term
|
|
// Alice Ephemeral <-> Bob Ephemeral
|
|
//
|
|
// Through this, a unique session key is derived. The exchange is offline-deniable (in the context of Tapir and Onion Service)
|
|
func Perform3DH(longtermIdentity *Identity, ephemeralIdentity *Identity, remoteLongTermPublicKey ed25519.PublicKey, remoteEphemeralPublicKey ed25519.PublicKey, outbound bool) ([32]byte, error) {
|
|
// 3DH Handshake
|
|
l2e, err1 := longtermIdentity.EDH(remoteEphemeralPublicKey)
|
|
e2l, err2 := ephemeralIdentity.EDH(remoteLongTermPublicKey)
|
|
e2e, err3 := ephemeralIdentity.EDH(remoteEphemeralPublicKey)
|
|
|
|
if err1 != nil || err2 != nil || err3 != nil {
|
|
return [32]byte{}, err1
|
|
}
|
|
|
|
// We need to define an order for the result concatenation so that both sides derive the same key.
|
|
var result [96]byte
|
|
if outbound {
|
|
copy(result[0:32], l2e)
|
|
copy(result[32:64], e2l)
|
|
copy(result[64:96], e2e)
|
|
} else {
|
|
copy(result[0:32], e2l)
|
|
copy(result[32:64], l2e)
|
|
copy(result[64:96], e2e)
|
|
}
|
|
return sha3.Sum256(result[:]), nil
|
|
}
|