github.com/MerlinKodo/quic-go@v0.39.2/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) cipher.AEAD 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) cipher.AEAD { 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) cipher.AEAD { 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 }