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 }