wireguard-go/src/noise_protocol.go

180 lines
4 KiB
Go
Raw Normal View History

2017-06-23 11:41:59 +00:00
package main
import (
"errors"
"golang.org/x/crypto/blake2s"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/poly1305"
"sync"
)
const (
HandshakeInitialCreated = iota
HandshakeInitialConsumed
HandshakeResponseCreated
)
const (
NoiseConstruction = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
WGIdentifier = "WireGuard v1 zx2c4 Jason@zx2c4.com"
WGLabelMAC1 = "mac1----"
WGLabelCookie = "cookie--"
)
const (
MessageInitalType = 1
MessageResponseType = 2
MessageCookieResponseType = 3
MessageTransportType = 4
)
type MessageInital struct {
Type uint32
Sender uint32
Ephemeral NoisePublicKey
Static [NoisePublicKeySize + poly1305.TagSize]byte
Timestamp [TAI64NSize + poly1305.TagSize]byte
Mac1 [blake2s.Size128]byte
Mac2 [blake2s.Size128]byte
}
type MessageResponse struct {
Type uint32
Sender uint32
Reciever uint32
Ephemeral NoisePublicKey
Empty [poly1305.TagSize]byte
Mac1 [blake2s.Size128]byte
Mac2 [blake2s.Size128]byte
}
type MessageTransport struct {
Type uint32
Reciever uint32
Counter uint64
Content []byte
}
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
}
var (
ZeroNonce [chacha20poly1305.NonceSize]byte
InitalChainKey [blake2s.Size]byte
InitalHash [blake2s.Size]byte
)
func init() {
InitalChainKey = blake2s.Sum256([]byte(NoiseConstruction))
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) {
h.hash = addToHash(h.hash, data)
}
func (h *Handshake) addChain(data []byte) {
h.chainKey = addToChainKey(h.chainKey, data)
}
func (h *Handshake) CreateMessageInital() (*MessageInital, error) {
h.lock.Lock()
defer h.lock.Unlock()
// 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[:])
// create ephemeral key
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[:])
// 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[:])
aead, _ := chacha20poly1305.New(key[:])
aead.Seal(msg.Static[:0], ZeroNonce[:], h.device.publicKey[:], nil)
}()
h.addHash(msg.Static[:])
// encrypt timestamp
timestamp := Timestamp()
func() {
var key [chacha20poly1305.KeySize]byte
h.chainKey, key = KDF2(h.chainKey[:], h.staticStatic[:])
aead, _ := chacha20poly1305.New(key[:])
aead.Seal(msg.Timestamp[:0], ZeroNonce[:], timestamp[:], nil)
}()
h.addHash(msg.Timestamp[:])
h.state = HandshakeInitialCreated
return &msg, nil
}
func (h *Handshake) ConsumeMessageInitial(msg *MessageInital) error {
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(hash, msg.Ephemeral[:])
//
ephemeral, err := newPrivateKey()
if err != nil {
return err
}
// 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
}
func (h *Handshake) CreateMessageResponse() []byte {
return nil
}