Restructuring of noise impl.

This commit is contained in:
Mathias Hall-Andersen
2017-06-24 15:34:17 +02:00
parent 521e77fd54
commit 25190e4336
10 changed files with 420 additions and 128 deletions

View File

@@ -56,18 +56,22 @@ type MessageTransport struct {
}
type Handshake struct {
lock sync.Mutex
state int
chainKey [blake2s.Size]byte // chain key
hash [blake2s.Size]byte // hash value
staticStatic NoisePublicKey // precomputed DH(S_i, S_r)
ephemeral NoisePrivateKey // ephemeral secret key
remoteIndex uint32 // index for sending
device *Device
peer *Peer
state int
mutex sync.Mutex
hash [blake2s.Size]byte // hash value
chainKey [blake2s.Size]byte // chain key
presharedKey NoiseSymmetricKey // psk
localEphemeral NoisePrivateKey // ephemeral secret key
localIndex uint32 // used to clear hash-table
remoteIndex uint32 // index for sending
remoteStatic NoisePublicKey // long term key
remoteEphemeral NoisePublicKey // ephemeral public key
precomputedStaticStatic [NoisePublicKeySize]byte // precomputed shared secret
lastTimestamp TAI64N
}
var (
EmptyMessage []byte
ZeroNonce [chacha20poly1305.NonceSize]byte
InitalChainKey [blake2s.Size]byte
InitalHash [blake2s.Size]byte
@@ -78,102 +82,196 @@ func init() {
InitalHash = blake2s.Sum256(append(InitalChainKey[:], []byte(WGIdentifier)...))
}
func (h *Handshake) Precompute() {
h.staticStatic = h.device.privateKey.sharedSecret(h.peer.publicKey)
}
func (h *Handshake) ConsumeMessageResponse(msg *MessageResponse) {
}
func (h *Handshake) addHash(data []byte) {
func (h *Handshake) addToHash(data []byte) {
h.hash = addToHash(h.hash, data)
}
func (h *Handshake) addChain(data []byte) {
func (h *Handshake) addToChainKey(data []byte) {
h.chainKey = addToChainKey(h.chainKey, data)
}
func (h *Handshake) CreateMessageInital() (*MessageInital, error) {
h.lock.Lock()
defer h.lock.Unlock()
func (device *Device) Precompute(peer *Peer) {
h := &peer.handshake
h.precomputedStaticStatic = device.privateKey.sharedSecret(h.remoteStatic)
}
// reset handshake
var err error
h.ephemeral, err = newPrivateKey()
if err != nil {
return nil, err
}
h.chainKey = InitalChainKey
h.hash = addToHash(InitalHash, h.device.publicKey[:])
func (device *Device) CreateMessageInitial(peer *Peer) (*MessageInital, error) {
handshake := &peer.handshake
handshake.mutex.Lock()
defer handshake.mutex.Unlock()
// create ephemeral key
var err error
handshake.chainKey = InitalChainKey
handshake.hash = addToHash(InitalHash, handshake.remoteStatic[:])
handshake.localEphemeral, err = newPrivateKey()
if err != nil {
return nil, err
}
// assign index
var msg MessageInital
msg.Type = MessageInitalType
msg.Sender = h.device.NewID(h)
msg.Ephemeral = h.ephemeral.publicKey()
h.chainKey = addToChainKey(h.chainKey, msg.Ephemeral[:])
h.hash = addToHash(h.hash, msg.Ephemeral[:])
msg.Ephemeral = handshake.localEphemeral.publicKey()
msg.Sender, err = device.indices.NewIndex(handshake)
if err != nil {
return nil, err
}
handshake.addToChainKey(msg.Ephemeral[:])
handshake.addToHash(msg.Ephemeral[:])
// encrypt long-term "identity key"
func() {
var key [chacha20poly1305.KeySize]byte
ss := h.ephemeral.sharedSecret(h.peer.publicKey)
h.chainKey, key = KDF2(h.chainKey[:], ss[:])
ss := handshake.localEphemeral.sharedSecret(handshake.remoteStatic)
handshake.chainKey, key = KDF2(handshake.chainKey[:], ss[:])
aead, _ := chacha20poly1305.New(key[:])
aead.Seal(msg.Static[:0], ZeroNonce[:], h.device.publicKey[:], nil)
aead.Seal(msg.Static[:0], ZeroNonce[:], device.publicKey[:], handshake.hash[:])
}()
h.addHash(msg.Static[:])
handshake.addToHash(msg.Static[:])
// encrypt timestamp
timestamp := Timestamp()
func() {
var key [chacha20poly1305.KeySize]byte
h.chainKey, key = KDF2(h.chainKey[:], h.staticStatic[:])
handshake.chainKey, key = KDF2(
handshake.chainKey[:],
handshake.precomputedStaticStatic[:],
)
aead, _ := chacha20poly1305.New(key[:])
aead.Seal(msg.Timestamp[:0], ZeroNonce[:], timestamp[:], nil)
aead.Seal(msg.Timestamp[:0], ZeroNonce[:], timestamp[:], handshake.hash[:])
}()
h.addHash(msg.Timestamp[:])
h.state = HandshakeInitialCreated
handshake.addToHash(msg.Timestamp[:])
handshake.state = HandshakeInitialCreated
return &msg, nil
}
func (h *Handshake) ConsumeMessageInitial(msg *MessageInital) error {
func (device *Device) ConsumeMessageInitial(msg *MessageInital) *Peer {
if msg.Type != MessageInitalType {
panic(errors.New("bug: invalid inital message type"))
}
hash := addToHash(InitalHash, h.device.publicKey[:])
chainKey := addToChainKey(InitalChainKey, msg.Ephemeral[:])
hash := addToHash(InitalHash, device.publicKey[:])
hash = addToHash(hash, msg.Ephemeral[:])
chainKey := addToChainKey(InitalChainKey, msg.Ephemeral[:])
//
// decrypt identity key
ephemeral, err := newPrivateKey()
var err error
var peerPK NoisePublicKey
func() {
var key [chacha20poly1305.KeySize]byte
ss := device.privateKey.sharedSecret(msg.Ephemeral)
chainKey, key = KDF2(chainKey[:], ss[:])
aead, _ := chacha20poly1305.New(key[:])
_, err = aead.Open(peerPK[:0], ZeroNonce[:], msg.Static[:], hash[:])
}()
if err != nil {
return err
return nil
}
hash = addToHash(hash, msg.Static[:])
// find peer
peer := device.LookupPeer(peerPK)
if peer == nil {
return nil
}
handshake := &peer.handshake
handshake.mutex.Lock()
defer handshake.mutex.Unlock()
// decrypt timestamp
var timestamp TAI64N
func() {
var key [chacha20poly1305.KeySize]byte
chainKey, key = KDF2(
chainKey[:],
handshake.precomputedStaticStatic[:],
)
aead, _ := chacha20poly1305.New(key[:])
_, err = aead.Open(timestamp[:0], ZeroNonce[:], msg.Timestamp[:], hash[:])
}()
if err != nil {
return nil
}
hash = addToHash(hash, msg.Timestamp[:])
// check for replay attack
if !timestamp.After(handshake.lastTimestamp) {
return nil
}
// check for flood attack
// update handshake state
h.lock.Lock()
defer h.lock.Unlock()
h.hash = hash
h.chainKey = chainKey
h.remoteIndex = msg.Sender
h.ephemeral = ephemeral
h.state = HandshakeInitialConsumed
return nil
handshake.hash = hash
handshake.chainKey = chainKey
handshake.remoteIndex = msg.Sender
handshake.remoteEphemeral = msg.Ephemeral
handshake.state = HandshakeInitialConsumed
return peer
}
func (h *Handshake) CreateMessageResponse() []byte {
func (device *Device) CreateMessageResponse(peer *Peer) (*MessageResponse, error) {
handshake := &peer.handshake
handshake.mutex.Lock()
defer handshake.mutex.Unlock()
return nil
if handshake.state != HandshakeInitialConsumed {
panic(errors.New("bug: handshake initation must be consumed first"))
}
// assign index
var err error
var msg MessageResponse
msg.Type = MessageResponseType
msg.Sender, err = device.indices.NewIndex(handshake)
msg.Reciever = handshake.remoteIndex
if err != nil {
return nil, err
}
// create ephemeral key
handshake.localEphemeral, err = newPrivateKey()
if err != nil {
return nil, err
}
msg.Ephemeral = handshake.localEphemeral.publicKey()
func() {
ss := handshake.localEphemeral.sharedSecret(handshake.remoteEphemeral)
handshake.addToChainKey(ss[:])
ss = handshake.localEphemeral.sharedSecret(handshake.remoteStatic)
handshake.addToChainKey(ss[:])
}()
// add preshared key (psk)
var tau [blake2s.Size]byte
var key [chacha20poly1305.KeySize]byte
handshake.chainKey, tau, key = KDF3(handshake.chainKey[:], handshake.presharedKey[:])
handshake.addToHash(tau[:])
func() {
aead, _ := chacha20poly1305.New(key[:])
aead.Seal(msg.Empty[:0], ZeroNonce[:], EmptyMessage, handshake.hash[:])
handshake.addToHash(msg.Empty[:])
}()
return &msg, nil
}