github.com/koomox/wireguard-go@v0.0.0-20230722134753-17a50b2f22a3/device/noise-helpers.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package device
     7  
     8  import (
     9  	"crypto/hmac"
    10  	"crypto/rand"
    11  	"crypto/subtle"
    12  	"errors"
    13  	"hash"
    14  
    15  	"golang.org/x/crypto/blake2s"
    16  	"golang.org/x/crypto/curve25519"
    17  )
    18  
    19  /* KDF related functions.
    20   * HMAC-based Key Derivation Function (HKDF)
    21   * https://tools.ietf.org/html/rfc5869
    22   */
    23  
    24  func HMAC1(sum *[blake2s.Size]byte, key, in0 []byte) {
    25  	mac := hmac.New(func() hash.Hash {
    26  		h, _ := blake2s.New256(nil)
    27  		return h
    28  	}, key)
    29  	mac.Write(in0)
    30  	mac.Sum(sum[:0])
    31  }
    32  
    33  func HMAC2(sum *[blake2s.Size]byte, key, in0, in1 []byte) {
    34  	mac := hmac.New(func() hash.Hash {
    35  		h, _ := blake2s.New256(nil)
    36  		return h
    37  	}, key)
    38  	mac.Write(in0)
    39  	mac.Write(in1)
    40  	mac.Sum(sum[:0])
    41  }
    42  
    43  func KDF1(t0 *[blake2s.Size]byte, key, input []byte) {
    44  	HMAC1(t0, key, input)
    45  	HMAC1(t0, t0[:], []byte{0x1})
    46  }
    47  
    48  func KDF2(t0, t1 *[blake2s.Size]byte, key, input []byte) {
    49  	var prk [blake2s.Size]byte
    50  	HMAC1(&prk, key, input)
    51  	HMAC1(t0, prk[:], []byte{0x1})
    52  	HMAC2(t1, prk[:], t0[:], []byte{0x2})
    53  	setZero(prk[:])
    54  }
    55  
    56  func KDF3(t0, t1, t2 *[blake2s.Size]byte, key, input []byte) {
    57  	var prk [blake2s.Size]byte
    58  	HMAC1(&prk, key, input)
    59  	HMAC1(t0, prk[:], []byte{0x1})
    60  	HMAC2(t1, prk[:], t0[:], []byte{0x2})
    61  	HMAC2(t2, prk[:], t1[:], []byte{0x3})
    62  	setZero(prk[:])
    63  }
    64  
    65  func isZero(val []byte) bool {
    66  	acc := 1
    67  	for _, b := range val {
    68  		acc &= subtle.ConstantTimeByteEq(b, 0)
    69  	}
    70  	return acc == 1
    71  }
    72  
    73  /* This function is not used as pervasively as it should because this is mostly impossible in Go at the moment */
    74  func setZero(arr []byte) {
    75  	for i := range arr {
    76  		arr[i] = 0
    77  	}
    78  }
    79  
    80  func (sk *NoisePrivateKey) clamp() {
    81  	sk[0] &= 248
    82  	sk[31] = (sk[31] & 127) | 64
    83  }
    84  
    85  func newPrivateKey() (sk NoisePrivateKey, err error) {
    86  	_, err = rand.Read(sk[:])
    87  	sk.clamp()
    88  	return
    89  }
    90  
    91  func (sk *NoisePrivateKey) publicKey() (pk NoisePublicKey) {
    92  	apk := (*[NoisePublicKeySize]byte)(&pk)
    93  	ask := (*[NoisePrivateKeySize]byte)(sk)
    94  	curve25519.ScalarBaseMult(apk, ask)
    95  	return
    96  }
    97  
    98  var errInvalidPublicKey = errors.New("invalid public key")
    99  
   100  func (sk *NoisePrivateKey) sharedSecret(pk NoisePublicKey) (ss [NoisePublicKeySize]byte, err error) {
   101  	apk := (*[NoisePublicKeySize]byte)(&pk)
   102  	ask := (*[NoisePrivateKeySize]byte)(sk)
   103  	curve25519.ScalarMult(&ss, ask, apk)
   104  	if isZero(ss[:]) {
   105  		return ss, errInvalidPublicKey
   106  	}
   107  	return ss, nil
   108  }