github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/internal/handshake/cipher_suite.go (about)

     1  package handshake
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"crypto/tls"
     8  	"fmt"
     9  
    10  	"golang.org/x/crypto/chacha20poly1305"
    11  )
    12  
    13  // These cipher suite implementations are copied from the standard library crypto/tls package.
    14  
    15  const aeadNonceLength = 12
    16  
    17  type cipherSuite struct {
    18  	ID     uint16
    19  	Hash   crypto.Hash
    20  	KeyLen int
    21  	AEAD   func(key, nonceMask []byte) *xorNonceAEAD
    22  }
    23  
    24  func (s cipherSuite) IVLen() int { return aeadNonceLength }
    25  
    26  func getCipherSuite(id uint16) *cipherSuite {
    27  	switch id {
    28  	case tls.TLS_AES_128_GCM_SHA256:
    29  		return &cipherSuite{ID: tls.TLS_AES_128_GCM_SHA256, Hash: crypto.SHA256, KeyLen: 16, AEAD: aeadAESGCMTLS13}
    30  	case tls.TLS_CHACHA20_POLY1305_SHA256:
    31  		return &cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
    32  	case tls.TLS_AES_256_GCM_SHA384:
    33  		return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
    34  	default:
    35  		panic(fmt.Sprintf("unknown cypher suite: %d", id))
    36  	}
    37  }
    38  
    39  func aeadAESGCMTLS13(key, nonceMask []byte) *xorNonceAEAD {
    40  	if len(nonceMask) != aeadNonceLength {
    41  		panic("tls: internal error: wrong nonce length")
    42  	}
    43  	aes, err := aes.NewCipher(key)
    44  	if err != nil {
    45  		panic(err)
    46  	}
    47  	aead, err := cipher.NewGCM(aes)
    48  	if err != nil {
    49  		panic(err)
    50  	}
    51  
    52  	ret := &xorNonceAEAD{aead: aead}
    53  	copy(ret.nonceMask[:], nonceMask)
    54  	return ret
    55  }
    56  
    57  func aeadChaCha20Poly1305(key, nonceMask []byte) *xorNonceAEAD {
    58  	if len(nonceMask) != aeadNonceLength {
    59  		panic("tls: internal error: wrong nonce length")
    60  	}
    61  	aead, err := chacha20poly1305.New(key)
    62  	if err != nil {
    63  		panic(err)
    64  	}
    65  
    66  	ret := &xorNonceAEAD{aead: aead}
    67  	copy(ret.nonceMask[:], nonceMask)
    68  	return ret
    69  }
    70  
    71  // xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
    72  // before each call.
    73  type xorNonceAEAD struct {
    74  	nonceMask [aeadNonceLength]byte
    75  	aead      cipher.AEAD
    76  }
    77  
    78  func (f *xorNonceAEAD) NonceSize() int        { return 8 } // 64-bit sequence number
    79  func (f *xorNonceAEAD) Overhead() int         { return f.aead.Overhead() }
    80  func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
    81  
    82  func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
    83  	for i, b := range nonce {
    84  		f.nonceMask[4+i] ^= b
    85  	}
    86  	result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
    87  	for i, b := range nonce {
    88  		f.nonceMask[4+i] ^= b
    89  	}
    90  
    91  	return result
    92  }
    93  
    94  func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
    95  	for i, b := range nonce {
    96  		f.nonceMask[4+i] ^= b
    97  	}
    98  	result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
    99  	for i, b := range nonce {
   100  		f.nonceMask[4+i] ^= b
   101  	}
   102  
   103  	return result, err
   104  }