Restructured MAC/cookie calculation
Added copy-right headers accidentally removed
This commit is contained in:
		
							parent
							
								
									86707cbc88
								
							
						
					
					
						commit
						8393cbff52
					
				@ -18,8 +18,8 @@ func (tun *DummyTUN) Name() string {
 | 
			
		||||
	return tun.name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *DummyTUN) MTU() int {
 | 
			
		||||
	return tun.mtu
 | 
			
		||||
func (tun *DummyTUN) MTU() (int, error) {
 | 
			
		||||
	return tun.mtu, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *DummyTUN) Write(d []byte) (int, error) {
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,9 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/hmac"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"github.com/aead/chacha20poly1305" // Needed for XChaCha20Poly1305, TODO:
 | 
			
		||||
	"errors"
 | 
			
		||||
	"golang.org/x/crypto/blake2s"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync"
 | 
			
		||||
@ -17,9 +16,22 @@ type MACStateDevice struct {
 | 
			
		||||
	secret    [blake2s.Size]byte
 | 
			
		||||
	keyMAC1   [blake2s.Size]byte
 | 
			
		||||
	keyMAC2   [blake2s.Size]byte
 | 
			
		||||
	xaead     cipher.AEAD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MACStatePeer struct {
 | 
			
		||||
	mutex     sync.RWMutex
 | 
			
		||||
	cookieSet time.Time
 | 
			
		||||
	cookie    [blake2s.Size128]byte
 | 
			
		||||
	lastMAC1  [blake2s.Size128]byte
 | 
			
		||||
	keyMAC1   [blake2s.Size]byte
 | 
			
		||||
	keyMAC2   [blake2s.Size]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Methods for verifing MAC fields
 | 
			
		||||
 * and creating/consuming cookies replies
 | 
			
		||||
 * (per device)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
func (state *MACStateDevice) Init(pk NoisePublicKey) {
 | 
			
		||||
	state.mutex.Lock()
 | 
			
		||||
	defer state.mutex.Unlock()
 | 
			
		||||
@ -38,7 +50,6 @@ func (state *MACStateDevice) Init(pk NoisePublicKey) {
 | 
			
		||||
		hsh.Sum(state.keyMAC2[:0])
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	state.xaead, _ = chacha20poly1305.NewXCipher(state.keyMAC2[:])
 | 
			
		||||
	state.refreshed = time.Time{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -90,7 +101,10 @@ func (state *MACStateDevice) CheckMAC2(msg []byte, addr *net.UDPAddr) bool {
 | 
			
		||||
	return hmac.Equal(mac2[:], msg[start:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (device *Device) CreateMessageCookieReply(msg []byte, receiver uint32, addr *net.UDPAddr) (*MessageCookieReply, error) {
 | 
			
		||||
func (device *Device) CreateMessageCookieReply(
 | 
			
		||||
	msg []byte, receiver uint32, addr *net.UDPAddr,
 | 
			
		||||
) (*MessageCookieReply, error) {
 | 
			
		||||
 | 
			
		||||
	state := &device.mac
 | 
			
		||||
	state.mutex.RLock()
 | 
			
		||||
 | 
			
		||||
@ -137,7 +151,15 @@ func (device *Device) CreateMessageCookieReply(msg []byte, receiver uint32, addr
 | 
			
		||||
		state.mutex.RUnlock()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	state.xaead.Seal(reply.Cookie[:0], reply.Nonce[:], cookie[:], mac1)
 | 
			
		||||
 | 
			
		||||
	XChaCha20Poly1305Encrypt(
 | 
			
		||||
		reply.Cookie[:0],
 | 
			
		||||
		&reply.Nonce,
 | 
			
		||||
		cookie[:],
 | 
			
		||||
		mac1,
 | 
			
		||||
		&state.keyMAC2,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	state.mutex.RUnlock()
 | 
			
		||||
	return reply, nil
 | 
			
		||||
}
 | 
			
		||||
@ -163,7 +185,14 @@ func (device *Device) ConsumeMessageCookieReply(msg *MessageCookieReply) bool {
 | 
			
		||||
	state.mutex.Lock()
 | 
			
		||||
	defer state.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	_, err := state.xaead.Open(cookie[:0], msg.Nonce[:], msg.Cookie[:], state.lastMAC1[:])
 | 
			
		||||
	_, err := XChaCha20Poly1305Decrypt(
 | 
			
		||||
		cookie[:0],
 | 
			
		||||
		&msg.Nonce,
 | 
			
		||||
		msg.Cookie[:],
 | 
			
		||||
		state.lastMAC1[:],
 | 
			
		||||
		&state.keyMAC2,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
@ -171,3 +200,69 @@ func (device *Device) ConsumeMessageCookieReply(msg *MessageCookieReply) bool {
 | 
			
		||||
	state.cookie = cookie
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Methods for generating the MAC fields
 | 
			
		||||
 * (per peer)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
func (state *MACStatePeer) Init(pk NoisePublicKey) {
 | 
			
		||||
	state.mutex.Lock()
 | 
			
		||||
	defer state.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	func() {
 | 
			
		||||
		hsh, _ := blake2s.New256(nil)
 | 
			
		||||
		hsh.Write([]byte(WGLabelMAC1))
 | 
			
		||||
		hsh.Write(pk[:])
 | 
			
		||||
		hsh.Sum(state.keyMAC1[:0])
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	func() {
 | 
			
		||||
		hsh, _ := blake2s.New256(nil)
 | 
			
		||||
		hsh.Write([]byte(WGLabelCookie))
 | 
			
		||||
		hsh.Write(pk[:])
 | 
			
		||||
		hsh.Sum(state.keyMAC2[:0])
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	state.cookieSet = time.Time{} // never
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (state *MACStatePeer) AddMacs(msg []byte) {
 | 
			
		||||
	size := len(msg)
 | 
			
		||||
 | 
			
		||||
	if size < blake2s.Size128*2 {
 | 
			
		||||
		panic(errors.New("bug: message too short"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	startMac1 := size - (blake2s.Size128 * 2)
 | 
			
		||||
	startMac2 := size - blake2s.Size128
 | 
			
		||||
 | 
			
		||||
	mac1 := msg[startMac1 : startMac1+blake2s.Size128]
 | 
			
		||||
	mac2 := msg[startMac2 : startMac2+blake2s.Size128]
 | 
			
		||||
 | 
			
		||||
	state.mutex.Lock()
 | 
			
		||||
	defer state.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	// set mac1
 | 
			
		||||
 | 
			
		||||
	func() {
 | 
			
		||||
		mac, _ := blake2s.New128(state.keyMAC1[:])
 | 
			
		||||
		mac.Write(msg[:startMac1])
 | 
			
		||||
		mac.Sum(mac1[:0])
 | 
			
		||||
	}()
 | 
			
		||||
	copy(state.lastMAC1[:], mac1)
 | 
			
		||||
 | 
			
		||||
	// set mac2
 | 
			
		||||
 | 
			
		||||
	if state.cookieSet.IsZero() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if time.Now().Sub(state.cookieSet) > CookieRefreshTime {
 | 
			
		||||
		state.cookieSet = time.Time{}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	func() {
 | 
			
		||||
		mac, _ := blake2s.New128(state.cookie[:])
 | 
			
		||||
		mac.Write(msg[:startMac2])
 | 
			
		||||
		mac.Sum(mac2[:0])
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
@ -1,83 +0,0 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/aead/chacha20poly1305" // Needed for XChaCha20Poly1305, TODO:
 | 
			
		||||
	"golang.org/x/crypto/blake2s"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MACStatePeer struct {
 | 
			
		||||
	mutex     sync.RWMutex
 | 
			
		||||
	cookieSet time.Time
 | 
			
		||||
	cookie    [blake2s.Size128]byte
 | 
			
		||||
	lastMAC1  [blake2s.Size128]byte
 | 
			
		||||
	keyMAC1   [blake2s.Size]byte
 | 
			
		||||
	keyMAC2   [blake2s.Size]byte
 | 
			
		||||
	xaead     cipher.AEAD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (state *MACStatePeer) Init(pk NoisePublicKey) {
 | 
			
		||||
	state.mutex.Lock()
 | 
			
		||||
	defer state.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	func() {
 | 
			
		||||
		hsh, _ := blake2s.New256(nil)
 | 
			
		||||
		hsh.Write([]byte(WGLabelMAC1))
 | 
			
		||||
		hsh.Write(pk[:])
 | 
			
		||||
		hsh.Sum(state.keyMAC1[:0])
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	func() {
 | 
			
		||||
		hsh, _ := blake2s.New256(nil)
 | 
			
		||||
		hsh.Write([]byte(WGLabelCookie))
 | 
			
		||||
		hsh.Write(pk[:])
 | 
			
		||||
		hsh.Sum(state.keyMAC2[:0])
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	state.xaead, _ = chacha20poly1305.NewXCipher(state.keyMAC2[:])
 | 
			
		||||
	state.cookieSet = time.Time{} // never
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (state *MACStatePeer) AddMacs(msg []byte) {
 | 
			
		||||
	size := len(msg)
 | 
			
		||||
 | 
			
		||||
	if size < blake2s.Size128*2 {
 | 
			
		||||
		panic(errors.New("bug: message too short"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	startMac1 := size - (blake2s.Size128 * 2)
 | 
			
		||||
	startMac2 := size - blake2s.Size128
 | 
			
		||||
 | 
			
		||||
	mac1 := msg[startMac1 : startMac1+blake2s.Size128]
 | 
			
		||||
	mac2 := msg[startMac2 : startMac2+blake2s.Size128]
 | 
			
		||||
 | 
			
		||||
	state.mutex.Lock()
 | 
			
		||||
	defer state.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	// set mac1
 | 
			
		||||
 | 
			
		||||
	func() {
 | 
			
		||||
		mac, _ := blake2s.New128(state.keyMAC1[:])
 | 
			
		||||
		mac.Write(msg[:startMac1])
 | 
			
		||||
		mac.Sum(state.lastMAC1[:0])
 | 
			
		||||
	}()
 | 
			
		||||
	copy(mac1, state.lastMAC1[:])
 | 
			
		||||
 | 
			
		||||
	// set mac2
 | 
			
		||||
 | 
			
		||||
	if state.cookieSet.IsZero() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if time.Now().Sub(state.cookieSet) > CookieRefreshTime {
 | 
			
		||||
		state.cookieSet = time.Time{}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	func() {
 | 
			
		||||
		mac, _ := blake2s.New128(state.cookie[:])
 | 
			
		||||
		mac.Write(msg[:startMac2])
 | 
			
		||||
		mac.Sum(mac2[:0])
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +1,8 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
/* Implementation of the ratelimited form the linux kernel version
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
 | 
			
		||||
 | 
			
		||||
/* This file contains a port of the ratelimited from the linux kernel version
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
 | 
			
		||||
 | 
			
		||||
/* Implementation of RFC6479
 | 
			
		||||
 * https://tools.ietf.org/html/rfc6479
 | 
			
		||||
 *
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										169
									
								
								src/xchacha20.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/xchacha20.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,169 @@
 | 
			
		||||
// Copyright (c) 2016 Andreas Auernhammer. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a license that can be
 | 
			
		||||
// found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"golang.org/x/crypto/chacha20poly1305"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func HChaCha20(out *[32]byte, nonce []byte, key *[32]byte) {
 | 
			
		||||
 | 
			
		||||
	v00 := uint32(0x61707865)
 | 
			
		||||
	v01 := uint32(0x3320646e)
 | 
			
		||||
	v02 := uint32(0x79622d32)
 | 
			
		||||
	v03 := uint32(0x6b206574)
 | 
			
		||||
 | 
			
		||||
	v04 := binary.LittleEndian.Uint32(key[0:])
 | 
			
		||||
	v05 := binary.LittleEndian.Uint32(key[4:])
 | 
			
		||||
	v06 := binary.LittleEndian.Uint32(key[8:])
 | 
			
		||||
	v07 := binary.LittleEndian.Uint32(key[12:])
 | 
			
		||||
	v08 := binary.LittleEndian.Uint32(key[16:])
 | 
			
		||||
	v09 := binary.LittleEndian.Uint32(key[20:])
 | 
			
		||||
	v10 := binary.LittleEndian.Uint32(key[24:])
 | 
			
		||||
	v11 := binary.LittleEndian.Uint32(key[28:])
 | 
			
		||||
	v12 := binary.LittleEndian.Uint32(nonce[0:])
 | 
			
		||||
	v13 := binary.LittleEndian.Uint32(nonce[4:])
 | 
			
		||||
	v14 := binary.LittleEndian.Uint32(nonce[8:])
 | 
			
		||||
	v15 := binary.LittleEndian.Uint32(nonce[12:])
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < 20; i += 2 {
 | 
			
		||||
		v00 += v04
 | 
			
		||||
		v12 ^= v00
 | 
			
		||||
		v12 = (v12 << 16) | (v12 >> 16)
 | 
			
		||||
		v08 += v12
 | 
			
		||||
		v04 ^= v08
 | 
			
		||||
		v04 = (v04 << 12) | (v04 >> 20)
 | 
			
		||||
		v00 += v04
 | 
			
		||||
		v12 ^= v00
 | 
			
		||||
		v12 = (v12 << 8) | (v12 >> 24)
 | 
			
		||||
		v08 += v12
 | 
			
		||||
		v04 ^= v08
 | 
			
		||||
		v04 = (v04 << 7) | (v04 >> 25)
 | 
			
		||||
		v01 += v05
 | 
			
		||||
		v13 ^= v01
 | 
			
		||||
		v13 = (v13 << 16) | (v13 >> 16)
 | 
			
		||||
		v09 += v13
 | 
			
		||||
		v05 ^= v09
 | 
			
		||||
		v05 = (v05 << 12) | (v05 >> 20)
 | 
			
		||||
		v01 += v05
 | 
			
		||||
		v13 ^= v01
 | 
			
		||||
		v13 = (v13 << 8) | (v13 >> 24)
 | 
			
		||||
		v09 += v13
 | 
			
		||||
		v05 ^= v09
 | 
			
		||||
		v05 = (v05 << 7) | (v05 >> 25)
 | 
			
		||||
		v02 += v06
 | 
			
		||||
		v14 ^= v02
 | 
			
		||||
		v14 = (v14 << 16) | (v14 >> 16)
 | 
			
		||||
		v10 += v14
 | 
			
		||||
		v06 ^= v10
 | 
			
		||||
		v06 = (v06 << 12) | (v06 >> 20)
 | 
			
		||||
		v02 += v06
 | 
			
		||||
		v14 ^= v02
 | 
			
		||||
		v14 = (v14 << 8) | (v14 >> 24)
 | 
			
		||||
		v10 += v14
 | 
			
		||||
		v06 ^= v10
 | 
			
		||||
		v06 = (v06 << 7) | (v06 >> 25)
 | 
			
		||||
		v03 += v07
 | 
			
		||||
		v15 ^= v03
 | 
			
		||||
		v15 = (v15 << 16) | (v15 >> 16)
 | 
			
		||||
		v11 += v15
 | 
			
		||||
		v07 ^= v11
 | 
			
		||||
		v07 = (v07 << 12) | (v07 >> 20)
 | 
			
		||||
		v03 += v07
 | 
			
		||||
		v15 ^= v03
 | 
			
		||||
		v15 = (v15 << 8) | (v15 >> 24)
 | 
			
		||||
		v11 += v15
 | 
			
		||||
		v07 ^= v11
 | 
			
		||||
		v07 = (v07 << 7) | (v07 >> 25)
 | 
			
		||||
		v00 += v05
 | 
			
		||||
		v15 ^= v00
 | 
			
		||||
		v15 = (v15 << 16) | (v15 >> 16)
 | 
			
		||||
		v10 += v15
 | 
			
		||||
		v05 ^= v10
 | 
			
		||||
		v05 = (v05 << 12) | (v05 >> 20)
 | 
			
		||||
		v00 += v05
 | 
			
		||||
		v15 ^= v00
 | 
			
		||||
		v15 = (v15 << 8) | (v15 >> 24)
 | 
			
		||||
		v10 += v15
 | 
			
		||||
		v05 ^= v10
 | 
			
		||||
		v05 = (v05 << 7) | (v05 >> 25)
 | 
			
		||||
		v01 += v06
 | 
			
		||||
		v12 ^= v01
 | 
			
		||||
		v12 = (v12 << 16) | (v12 >> 16)
 | 
			
		||||
		v11 += v12
 | 
			
		||||
		v06 ^= v11
 | 
			
		||||
		v06 = (v06 << 12) | (v06 >> 20)
 | 
			
		||||
		v01 += v06
 | 
			
		||||
		v12 ^= v01
 | 
			
		||||
		v12 = (v12 << 8) | (v12 >> 24)
 | 
			
		||||
		v11 += v12
 | 
			
		||||
		v06 ^= v11
 | 
			
		||||
		v06 = (v06 << 7) | (v06 >> 25)
 | 
			
		||||
		v02 += v07
 | 
			
		||||
		v13 ^= v02
 | 
			
		||||
		v13 = (v13 << 16) | (v13 >> 16)
 | 
			
		||||
		v08 += v13
 | 
			
		||||
		v07 ^= v08
 | 
			
		||||
		v07 = (v07 << 12) | (v07 >> 20)
 | 
			
		||||
		v02 += v07
 | 
			
		||||
		v13 ^= v02
 | 
			
		||||
		v13 = (v13 << 8) | (v13 >> 24)
 | 
			
		||||
		v08 += v13
 | 
			
		||||
		v07 ^= v08
 | 
			
		||||
		v07 = (v07 << 7) | (v07 >> 25)
 | 
			
		||||
		v03 += v04
 | 
			
		||||
		v14 ^= v03
 | 
			
		||||
		v14 = (v14 << 16) | (v14 >> 16)
 | 
			
		||||
		v09 += v14
 | 
			
		||||
		v04 ^= v09
 | 
			
		||||
		v04 = (v04 << 12) | (v04 >> 20)
 | 
			
		||||
		v03 += v04
 | 
			
		||||
		v14 ^= v03
 | 
			
		||||
		v14 = (v14 << 8) | (v14 >> 24)
 | 
			
		||||
		v09 += v14
 | 
			
		||||
		v04 ^= v09
 | 
			
		||||
		v04 = (v04 << 7) | (v04 >> 25)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[0:], v00)
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[4:], v01)
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[8:], v02)
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[12:], v03)
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[16:], v12)
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[20:], v13)
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[24:], v14)
 | 
			
		||||
	binary.LittleEndian.PutUint32(out[28:], v15)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func XChaCha20Poly1305Encrypt(
 | 
			
		||||
	dst []byte,
 | 
			
		||||
	nonceFull *[24]byte,
 | 
			
		||||
	plaintext []byte,
 | 
			
		||||
	additionalData []byte,
 | 
			
		||||
	key *[chacha20poly1305.KeySize]byte,
 | 
			
		||||
) []byte {
 | 
			
		||||
	var nonce [chacha20poly1305.NonceSize]byte
 | 
			
		||||
	var derivedKey [chacha20poly1305.KeySize]byte
 | 
			
		||||
	HChaCha20(&derivedKey, nonceFull[:16], key)
 | 
			
		||||
	aead, _ := chacha20poly1305.New(derivedKey[:])
 | 
			
		||||
	copy(nonce[4:], nonceFull[16:])
 | 
			
		||||
	return aead.Seal(dst, nonce[:], plaintext, additionalData)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func XChaCha20Poly1305Decrypt(
 | 
			
		||||
	dst []byte,
 | 
			
		||||
	nonceFull *[24]byte,
 | 
			
		||||
	plaintext []byte,
 | 
			
		||||
	additionalData []byte,
 | 
			
		||||
	key *[chacha20poly1305.KeySize]byte,
 | 
			
		||||
) ([]byte, error) {
 | 
			
		||||
	var nonce [chacha20poly1305.NonceSize]byte
 | 
			
		||||
	var derivedKey [chacha20poly1305.KeySize]byte
 | 
			
		||||
	HChaCha20(&derivedKey, nonceFull[:16], key)
 | 
			
		||||
	aead, _ := chacha20poly1305.New(derivedKey[:])
 | 
			
		||||
	copy(nonce[4:], nonceFull[16:])
 | 
			
		||||
	return aead.Open(dst, nonce[:], plaintext, additionalData)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								src/xchacha20_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/xchacha20_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type XChaCha20Test struct {
 | 
			
		||||
	Nonce string
 | 
			
		||||
	Key   string
 | 
			
		||||
	PT    string
 | 
			
		||||
	CT    string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestXChaCha20(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	tests := []XChaCha20Test{
 | 
			
		||||
		{
 | 
			
		||||
			Nonce: "000000000000000000000000000000000000000000000000",
 | 
			
		||||
			Key:   "0000000000000000000000000000000000000000000000000000000000000000",
 | 
			
		||||
			PT:    "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
 | 
			
		||||
			CT:    "789e9689e5208d7fd9e1f3c5b5341f48ef18a13e418998addadd97a3693a987f8e82ecd5c1433bfed1af49750c0f1ff29c4174a05b119aa3a9e8333812e0c0feb1299c5949d895ee01dbf50f8395dd84",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Nonce: "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f",
 | 
			
		||||
			Key:   "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f",
 | 
			
		||||
			PT:    "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f",
 | 
			
		||||
			CT:    "e1a046aa7f71e2af8b80b6408b2fd8d3a350278cde79c94d9efaa475e1339b3dd490127b",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Nonce: "d9a8213e8a697508805c2c171ad54487ead9e3e02d82d5bc",
 | 
			
		||||
			Key:   "979196dbd78526f2f584f7534db3f5824d8ccfa858ca7e09bdd3656ecd36033c",
 | 
			
		||||
			PT:    "43cc6d624e451bbed952c3e071dc6c03392ce11eb14316a94b2fdc98b22fedea",
 | 
			
		||||
			CT:    "53c1e8bef2dbb8f2505ec010a7afe21d5a8e6dd8f987e4ea1a2ed5dfbc844ea400db34496fd2153526c6e87c36694200",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
 | 
			
		||||
		nonce, err := hex.DecodeString(test.Nonce)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		key, err := hex.DecodeString(test.Key)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pt, err := hex.DecodeString(test.PT)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		func() {
 | 
			
		||||
			var nonceArray [24]byte
 | 
			
		||||
			var keyArray [32]byte
 | 
			
		||||
			copy(nonceArray[:], nonce)
 | 
			
		||||
			copy(keyArray[:], key)
 | 
			
		||||
 | 
			
		||||
			// test encryption
 | 
			
		||||
 | 
			
		||||
			ct := XChaCha20Poly1305Encrypt(
 | 
			
		||||
				nil,
 | 
			
		||||
				&nonceArray,
 | 
			
		||||
				pt,
 | 
			
		||||
				nil,
 | 
			
		||||
				&keyArray,
 | 
			
		||||
			)
 | 
			
		||||
			ctHex := hex.EncodeToString(ct)
 | 
			
		||||
			if ctHex != test.CT {
 | 
			
		||||
				t.Fatal("encryption failed, expected:", test.CT, "got", ctHex)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// test decryption
 | 
			
		||||
 | 
			
		||||
			ptp, err := XChaCha20Poly1305Decrypt(
 | 
			
		||||
				nil,
 | 
			
		||||
				&nonceArray,
 | 
			
		||||
				ct,
 | 
			
		||||
				nil,
 | 
			
		||||
				&keyArray,
 | 
			
		||||
			)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ptHex := hex.EncodeToString(ptp)
 | 
			
		||||
			if ptHex != test.PT {
 | 
			
		||||
				t.Fatal("decryption failed, expected:", test.PT, "got", ptHex)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user