github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/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  	"github.com/danielpfeifer02/quic-go-prio-packs/crypto_turnoff"
    11  	"golang.org/x/crypto/chacha20poly1305"
    12  )
    13  
    14  // These cipher suite implementations are copied from the standard library crypto/tls package.
    15  
    16  const aeadNonceLength = 12
    17  
    18  type cipherSuite struct {
    19  	ID     uint16
    20  	Hash   crypto.Hash
    21  	KeyLen int
    22  	AEAD   func(key, nonceMask []byte) *xorNonceAEAD
    23  }
    24  
    25  func (s cipherSuite) IVLen() int { return aeadNonceLength }
    26  
    27  func getCipherSuite(id uint16) *cipherSuite {
    28  	switch id {
    29  	case tls.TLS_AES_128_GCM_SHA256:
    30  		return &cipherSuite{ID: tls.TLS_AES_128_GCM_SHA256, Hash: crypto.SHA256, KeyLen: 16, AEAD: aeadAESGCMTLS13}
    31  	case tls.TLS_CHACHA20_POLY1305_SHA256:
    32  		return &cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
    33  	case tls.TLS_AES_256_GCM_SHA384:
    34  		return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
    35  
    36  	// NO_CRYPTO_TAG
    37  	// based on https://pkg.go.dev/crypto/tls#pkg-constants 0x0000 is not used for any other cipher suite
    38  	case 0x0000:
    39  		// everything except ID is not used and thus arbitrary
    40  		return &cipherSuite{ID: 0x0000, Hash: 0, KeyLen: 0, AEAD: func(key, nonceMask []byte) *xorNonceAEAD {
    41  			return nil
    42  		}}
    43  
    44  	default:
    45  		panic(fmt.Sprintf("unknown cypher suite: %d", id))
    46  	}
    47  }
    48  
    49  func aeadAESGCMTLS13(key, nonceMask []byte) *xorNonceAEAD {
    50  	if len(nonceMask) != aeadNonceLength {
    51  		panic("tls: internal error: wrong nonce length")
    52  	}
    53  	aes, err := aes.NewCipher(key)
    54  	if err != nil {
    55  		panic(err)
    56  	}
    57  	aead, err := cipher.NewGCM(aes)
    58  	if err != nil {
    59  		panic(err)
    60  	}
    61  
    62  	ret := &xorNonceAEAD{aead: aead}
    63  	copy(ret.nonceMask[:], nonceMask)
    64  	return ret
    65  }
    66  
    67  func aeadChaCha20Poly1305(key, nonceMask []byte) *xorNonceAEAD {
    68  	if len(nonceMask) != aeadNonceLength {
    69  		panic("tls: internal error: wrong nonce length")
    70  	}
    71  	aead, err := chacha20poly1305.New(key)
    72  	if err != nil {
    73  		panic(err)
    74  	}
    75  
    76  	ret := &xorNonceAEAD{aead: aead}
    77  	copy(ret.nonceMask[:], nonceMask)
    78  	return ret
    79  }
    80  
    81  // xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
    82  // before each call.
    83  type xorNonceAEAD struct {
    84  	nonceMask [aeadNonceLength]byte
    85  	aead      cipher.AEAD
    86  }
    87  
    88  func (f *xorNonceAEAD) NonceSize() int        { return 8 } // 64-bit sequence number
    89  func (f *xorNonceAEAD) Overhead() int         { return f.aead.Overhead() }
    90  func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
    91  
    92  func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
    93  
    94  	// NO_CRYPTO_TAG
    95  	if crypto_turnoff.CRYPTO_TURNED_OFF {
    96  		return plaintext
    97  	}
    98  
    99  	for i, b := range nonce {
   100  		f.nonceMask[4+i] ^= b
   101  	}
   102  	result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
   103  	for i, b := range nonce {
   104  		f.nonceMask[4+i] ^= b
   105  	}
   106  
   107  	return result
   108  }
   109  
   110  func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
   111  
   112  	// NO_CRYPTO_TAG
   113  	if crypto_turnoff.CRYPTO_TURNED_OFF {
   114  		return ciphertext, nil
   115  	}
   116  
   117  	for i, b := range nonce {
   118  		f.nonceMask[4+i] ^= b
   119  	}
   120  	result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
   121  	for i, b := range nonce {
   122  		f.nonceMask[4+i] ^= b
   123  	}
   124  
   125  	return result, err
   126  }