aboutsummaryrefslogtreecommitdiffstats
path: root/src/noise_protocol.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/noise_protocol.go179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/noise_protocol.go b/src/noise_protocol.go
new file mode 100644
index 0000000..e7c8774
--- /dev/null
+++ b/src/noise_protocol.go
@@ -0,0 +1,179 @@
+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
+}