github.com/pion/dtls/v2@v2.2.12/pkg/crypto/prf/prf.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  // Package prf implements TLS 1.2 Pseudorandom functions
     5  package prf
     6  
     7  import ( //nolint:gci
     8  	ellipticStdlib "crypto/elliptic"
     9  	"crypto/hmac"
    10  	"encoding/binary"
    11  	"errors"
    12  	"fmt"
    13  	"hash"
    14  	"math"
    15  
    16  	"github.com/pion/dtls/v2/pkg/crypto/elliptic"
    17  	"github.com/pion/dtls/v2/pkg/protocol"
    18  	"golang.org/x/crypto/curve25519"
    19  )
    20  
    21  const (
    22  	masterSecretLabel         = "master secret"
    23  	extendedMasterSecretLabel = "extended master secret"
    24  	keyExpansionLabel         = "key expansion"
    25  	verifyDataClientLabel     = "client finished"
    26  	verifyDataServerLabel     = "server finished"
    27  )
    28  
    29  // HashFunc allows callers to decide what hash is used in PRF
    30  type HashFunc func() hash.Hash
    31  
    32  // EncryptionKeys is all the state needed for a TLS CipherSuite
    33  type EncryptionKeys struct {
    34  	MasterSecret   []byte
    35  	ClientMACKey   []byte
    36  	ServerMACKey   []byte
    37  	ClientWriteKey []byte
    38  	ServerWriteKey []byte
    39  	ClientWriteIV  []byte
    40  	ServerWriteIV  []byte
    41  }
    42  
    43  var errInvalidNamedCurve = &protocol.FatalError{Err: errors.New("invalid named curve")} //nolint:goerr113
    44  
    45  func (e *EncryptionKeys) String() string {
    46  	return fmt.Sprintf(`encryptionKeys:
    47  - masterSecret: %#v
    48  - clientMACKey: %#v
    49  - serverMACKey: %#v
    50  - clientWriteKey: %#v
    51  - serverWriteKey: %#v
    52  - clientWriteIV: %#v
    53  - serverWriteIV: %#v
    54  `,
    55  		e.MasterSecret,
    56  		e.ClientMACKey,
    57  		e.ServerMACKey,
    58  		e.ClientWriteKey,
    59  		e.ServerWriteKey,
    60  		e.ClientWriteIV,
    61  		e.ServerWriteIV)
    62  }
    63  
    64  // PSKPreMasterSecret generates the PSK Premaster Secret
    65  // The premaster secret is formed as follows: if the PSK is N octets
    66  // long, concatenate a uint16 with the value N, N zero octets, a second
    67  // uint16 with the value N, and the PSK itself.
    68  //
    69  // https://tools.ietf.org/html/rfc4279#section-2
    70  func PSKPreMasterSecret(psk []byte) []byte {
    71  	pskLen := uint16(len(psk))
    72  
    73  	out := append(make([]byte, 2+pskLen+2), psk...)
    74  	binary.BigEndian.PutUint16(out, pskLen)
    75  	binary.BigEndian.PutUint16(out[2+pskLen:], pskLen)
    76  
    77  	return out
    78  }
    79  
    80  // EcdhePSKPreMasterSecret implements TLS 1.2 Premaster Secret generation given a psk, a keypair and a curve
    81  //
    82  // https://datatracker.ietf.org/doc/html/rfc5489#section-2
    83  func EcdhePSKPreMasterSecret(psk, publicKey, privateKey []byte, curve elliptic.Curve) ([]byte, error) {
    84  	preMasterSecret, err := PreMasterSecret(publicKey, privateKey, curve)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	out := make([]byte, 2+len(preMasterSecret)+2+len(psk))
    89  
    90  	// write preMasterSecret length
    91  	offset := 0
    92  	binary.BigEndian.PutUint16(out[offset:], uint16(len(preMasterSecret)))
    93  	offset += 2
    94  
    95  	// write preMasterSecret
    96  	copy(out[offset:], preMasterSecret)
    97  	offset += len(preMasterSecret)
    98  
    99  	// write psk length
   100  	binary.BigEndian.PutUint16(out[offset:], uint16(len(psk)))
   101  	offset += 2
   102  
   103  	// write psk
   104  	copy(out[offset:], psk)
   105  	return out, nil
   106  }
   107  
   108  // PreMasterSecret implements TLS 1.2 Premaster Secret generation given a keypair and a curve
   109  func PreMasterSecret(publicKey, privateKey []byte, curve elliptic.Curve) ([]byte, error) {
   110  	switch curve {
   111  	case elliptic.X25519:
   112  		return curve25519.X25519(privateKey, publicKey)
   113  	case elliptic.P256:
   114  		return ellipticCurvePreMasterSecret(publicKey, privateKey, ellipticStdlib.P256(), ellipticStdlib.P256())
   115  	case elliptic.P384:
   116  		return ellipticCurvePreMasterSecret(publicKey, privateKey, ellipticStdlib.P384(), ellipticStdlib.P384())
   117  	default:
   118  		return nil, errInvalidNamedCurve
   119  	}
   120  }
   121  
   122  func ellipticCurvePreMasterSecret(publicKey, privateKey []byte, c1, c2 ellipticStdlib.Curve) ([]byte, error) {
   123  	x, y := ellipticStdlib.Unmarshal(c1, publicKey)
   124  	if x == nil || y == nil {
   125  		return nil, errInvalidNamedCurve
   126  	}
   127  
   128  	result, _ := c2.ScalarMult(x, y, privateKey)
   129  	preMasterSecret := make([]byte, (c2.Params().BitSize+7)>>3)
   130  	resultBytes := result.Bytes()
   131  	copy(preMasterSecret[len(preMasterSecret)-len(resultBytes):], resultBytes)
   132  	return preMasterSecret, nil
   133  }
   134  
   135  // PHash is PRF is the SHA-256 hash function is used for all cipher suites
   136  // defined in this TLS 1.2 document and in TLS documents published prior to this
   137  // document when TLS 1.2 is negotiated.  New cipher suites MUST explicitly
   138  // specify a PRF and, in general, SHOULD use the TLS PRF with SHA-256 or a
   139  // stronger standard hash function.
   140  //
   141  //	P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
   142  //	                       HMAC_hash(secret, A(2) + seed) +
   143  //	                       HMAC_hash(secret, A(3) + seed) + ...
   144  //
   145  // A() is defined as:
   146  //
   147  //	A(0) = seed
   148  //	A(i) = HMAC_hash(secret, A(i-1))
   149  //
   150  // P_hash can be iterated as many times as necessary to produce the
   151  // required quantity of data.  For example, if P_SHA256 is being used to
   152  // create 80 bytes of data, it will have to be iterated three times
   153  // (through A(3)), creating 96 bytes of output data; the last 16 bytes
   154  // of the final iteration will then be discarded, leaving 80 bytes of
   155  // output data.
   156  //
   157  // https://tools.ietf.org/html/rfc4346w
   158  func PHash(secret, seed []byte, requestedLength int, h HashFunc) ([]byte, error) {
   159  	hmacSHA256 := func(key, data []byte) ([]byte, error) {
   160  		mac := hmac.New(h, key)
   161  		if _, err := mac.Write(data); err != nil {
   162  			return nil, err
   163  		}
   164  		return mac.Sum(nil), nil
   165  	}
   166  
   167  	var err error
   168  	lastRound := seed
   169  	out := []byte{}
   170  
   171  	iterations := int(math.Ceil(float64(requestedLength) / float64(h().Size())))
   172  	for i := 0; i < iterations; i++ {
   173  		lastRound, err = hmacSHA256(secret, lastRound)
   174  		if err != nil {
   175  			return nil, err
   176  		}
   177  		withSecret, err := hmacSHA256(secret, append(lastRound, seed...))
   178  		if err != nil {
   179  			return nil, err
   180  		}
   181  		out = append(out, withSecret...)
   182  	}
   183  
   184  	return out[:requestedLength], nil
   185  }
   186  
   187  // ExtendedMasterSecret generates a Extended MasterSecret as defined in
   188  // https://tools.ietf.org/html/rfc7627
   189  func ExtendedMasterSecret(preMasterSecret, sessionHash []byte, h HashFunc) ([]byte, error) {
   190  	seed := append([]byte(extendedMasterSecretLabel), sessionHash...)
   191  	return PHash(preMasterSecret, seed, 48, h)
   192  }
   193  
   194  // MasterSecret generates a TLS 1.2 MasterSecret
   195  func MasterSecret(preMasterSecret, clientRandom, serverRandom []byte, h HashFunc) ([]byte, error) {
   196  	seed := append(append([]byte(masterSecretLabel), clientRandom...), serverRandom...)
   197  	return PHash(preMasterSecret, seed, 48, h)
   198  }
   199  
   200  // GenerateEncryptionKeys is the final step TLS 1.2 PRF. Given all state generated so far generates
   201  // the final keys need for encryption
   202  func GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int, h HashFunc) (*EncryptionKeys, error) {
   203  	seed := append(append([]byte(keyExpansionLabel), serverRandom...), clientRandom...)
   204  	keyMaterial, err := PHash(masterSecret, seed, (2*macLen)+(2*keyLen)+(2*ivLen), h)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	clientMACKey := keyMaterial[:macLen]
   210  	keyMaterial = keyMaterial[macLen:]
   211  
   212  	serverMACKey := keyMaterial[:macLen]
   213  	keyMaterial = keyMaterial[macLen:]
   214  
   215  	clientWriteKey := keyMaterial[:keyLen]
   216  	keyMaterial = keyMaterial[keyLen:]
   217  
   218  	serverWriteKey := keyMaterial[:keyLen]
   219  	keyMaterial = keyMaterial[keyLen:]
   220  
   221  	clientWriteIV := keyMaterial[:ivLen]
   222  	keyMaterial = keyMaterial[ivLen:]
   223  
   224  	serverWriteIV := keyMaterial[:ivLen]
   225  
   226  	return &EncryptionKeys{
   227  		MasterSecret:   masterSecret,
   228  		ClientMACKey:   clientMACKey,
   229  		ServerMACKey:   serverMACKey,
   230  		ClientWriteKey: clientWriteKey,
   231  		ServerWriteKey: serverWriteKey,
   232  		ClientWriteIV:  clientWriteIV,
   233  		ServerWriteIV:  serverWriteIV,
   234  	}, nil
   235  }
   236  
   237  func prfVerifyData(masterSecret, handshakeBodies []byte, label string, hashFunc HashFunc) ([]byte, error) {
   238  	h := hashFunc()
   239  	if _, err := h.Write(handshakeBodies); err != nil {
   240  		return nil, err
   241  	}
   242  
   243  	seed := append([]byte(label), h.Sum(nil)...)
   244  	return PHash(masterSecret, seed, 12, hashFunc)
   245  }
   246  
   247  // VerifyDataClient is caled on the Client Side to either verify or generate the VerifyData message
   248  func VerifyDataClient(masterSecret, handshakeBodies []byte, h HashFunc) ([]byte, error) {
   249  	return prfVerifyData(masterSecret, handshakeBodies, verifyDataClientLabel, h)
   250  }
   251  
   252  // VerifyDataServer is caled on the Server Side to either verify or generate the VerifyData message
   253  func VerifyDataServer(masterSecret, handshakeBodies []byte, h HashFunc) ([]byte, error) {
   254  	return prfVerifyData(masterSecret, handshakeBodies, verifyDataServerLabel, h)
   255  }