client.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. package encryption
  2. import (
  3. "crypto/cipher"
  4. "crypto/ecdh"
  5. "crypto/mlkem"
  6. "crypto/rand"
  7. "io"
  8. "net"
  9. "sync"
  10. "time"
  11. "github.com/xtls/xray-core/common/crypto"
  12. "github.com/xtls/xray-core/common/errors"
  13. "github.com/xtls/xray-core/common/protocol"
  14. "lukechampine.com/blake3"
  15. )
  16. type ClientInstance struct {
  17. NfsPKeys []any
  18. NfsPKeysBytes [][]byte
  19. Hash32s [][32]byte
  20. RelaysLength int
  21. XorMode uint32
  22. Seconds uint32
  23. RWLock sync.RWMutex
  24. Expire time.Time
  25. PfsKey []byte
  26. Ticket []byte
  27. }
  28. func (i *ClientInstance) Init(nfsPKeysBytes [][]byte, xorMode, seconds uint32) (err error) {
  29. if i.NfsPKeys != nil {
  30. err = errors.New("already initialized")
  31. return
  32. }
  33. l := len(nfsPKeysBytes)
  34. if l == 0 {
  35. err = errors.New("empty nfsPKeysBytes")
  36. return
  37. }
  38. i.NfsPKeys = make([]any, l)
  39. i.NfsPKeysBytes = nfsPKeysBytes
  40. i.Hash32s = make([][32]byte, l)
  41. for j, k := range nfsPKeysBytes {
  42. if len(k) == 32 {
  43. if i.NfsPKeys[j], err = ecdh.X25519().NewPublicKey(k); err != nil {
  44. return
  45. }
  46. i.RelaysLength += 32 + 32
  47. } else {
  48. if i.NfsPKeys[j], err = mlkem.NewEncapsulationKey768(k); err != nil {
  49. return
  50. }
  51. i.RelaysLength += 1088 + 32
  52. }
  53. i.Hash32s[j] = blake3.Sum256(k)
  54. }
  55. i.RelaysLength -= 32
  56. i.XorMode = xorMode
  57. i.Seconds = seconds
  58. return
  59. }
  60. func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
  61. if i.NfsPKeys == nil {
  62. return nil, errors.New("uninitialized")
  63. }
  64. c := NewCommonConn(conn, protocol.HasAESGCMHardwareSupport)
  65. ivAndRealysLength := 16 + i.RelaysLength
  66. pfsKeyExchangeLength := 18 + 1184 + 32 + 16
  67. paddingLength := int(crypto.RandBetween(100, 1000))
  68. clientHello := make([]byte, ivAndRealysLength+pfsKeyExchangeLength+paddingLength)
  69. iv := clientHello[:16]
  70. rand.Read(iv)
  71. relays := clientHello[16:ivAndRealysLength]
  72. var nfsKey []byte
  73. var lastCTR cipher.Stream
  74. for j, k := range i.NfsPKeys {
  75. var index = 32
  76. if k, ok := k.(*ecdh.PublicKey); ok {
  77. privateKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
  78. copy(relays, privateKey.PublicKey().Bytes())
  79. var err error
  80. nfsKey, err = privateKey.ECDH(k)
  81. if err != nil {
  82. return nil, err
  83. }
  84. }
  85. if k, ok := k.(*mlkem.EncapsulationKey768); ok {
  86. var ciphertext []byte
  87. nfsKey, ciphertext = k.Encapsulate()
  88. copy(relays, ciphertext)
  89. index = 1088
  90. }
  91. if i.XorMode > 0 { // this xor can (others can't) be recovered by client's config, revealing an X25519 public key / ML-KEM-768 ciphertext, that's why "native" values
  92. NewCTR(i.NfsPKeysBytes[j], iv).XORKeyStream(relays, relays[:index]) // make X25519 public key / ML-KEM-768 ciphertext distinguishable from random bytes
  93. }
  94. if lastCTR != nil {
  95. lastCTR.XORKeyStream(relays, relays[:32]) // make this relay irreplaceable
  96. }
  97. if j == len(i.NfsPKeys)-1 {
  98. break
  99. }
  100. lastCTR = NewCTR(nfsKey, iv)
  101. lastCTR.XORKeyStream(relays[index:], i.Hash32s[j+1][:])
  102. relays = relays[index+32:]
  103. }
  104. nfsAEAD := NewAEAD(iv, nfsKey, c.UseAES)
  105. if i.Seconds > 0 {
  106. i.RWLock.RLock()
  107. if time.Now().Before(i.Expire) {
  108. c.Client = i
  109. c.UnitedKey = append(i.PfsKey, nfsKey...) // different unitedKey for each connection
  110. nfsAEAD.Seal(clientHello[:ivAndRealysLength], nil, EncodeLength(32), nil)
  111. nfsAEAD.Seal(clientHello[:ivAndRealysLength+18], nil, i.Ticket, nil)
  112. i.RWLock.RUnlock()
  113. c.PreWrite = clientHello[:ivAndRealysLength+18+32]
  114. c.AEAD = NewAEAD(clientHello[ivAndRealysLength+18:ivAndRealysLength+18+32], c.UnitedKey, c.UseAES)
  115. if i.XorMode == 2 {
  116. c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, iv), nil, len(c.PreWrite), 16)
  117. }
  118. return c, nil
  119. }
  120. i.RWLock.RUnlock()
  121. }
  122. pfsKeyExchange := clientHello[ivAndRealysLength : ivAndRealysLength+pfsKeyExchangeLength]
  123. nfsAEAD.Seal(pfsKeyExchange[:0], nil, EncodeLength(pfsKeyExchangeLength-18), nil)
  124. mlkem768DKey, _ := mlkem.GenerateKey768()
  125. x25519SKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
  126. pfsPublicKey := append(mlkem768DKey.EncapsulationKey().Bytes(), x25519SKey.PublicKey().Bytes()...)
  127. nfsAEAD.Seal(pfsKeyExchange[:18], nil, pfsPublicKey, nil)
  128. padding := clientHello[ivAndRealysLength+pfsKeyExchangeLength:]
  129. nfsAEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
  130. nfsAEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
  131. if _, err := conn.Write(clientHello); err != nil {
  132. return nil, err
  133. }
  134. // padding can be sent in a fragmented way, to create variable traffic pattern, before inner VLESS flow takes control
  135. encryptedPfsPublicKey := make([]byte, 1088+32+16)
  136. if _, err := io.ReadFull(conn, encryptedPfsPublicKey); err != nil {
  137. return nil, err
  138. }
  139. nfsAEAD.Open(encryptedPfsPublicKey[:0], MaxNonce, encryptedPfsPublicKey, nil)
  140. mlkem768Key, err := mlkem768DKey.Decapsulate(encryptedPfsPublicKey[:1088])
  141. if err != nil {
  142. return nil, err
  143. }
  144. peerX25519PKey, err := ecdh.X25519().NewPublicKey(encryptedPfsPublicKey[1088 : 1088+32])
  145. if err != nil {
  146. return nil, err
  147. }
  148. x25519Key, err := x25519SKey.ECDH(peerX25519PKey)
  149. if err != nil {
  150. return nil, err
  151. }
  152. pfsKey := make([]byte, 32+32) // no more capacity
  153. copy(pfsKey, mlkem768Key)
  154. copy(pfsKey[32:], x25519Key)
  155. c.UnitedKey = append(pfsKey, nfsKey...)
  156. c.AEAD = NewAEAD(pfsPublicKey, c.UnitedKey, c.UseAES)
  157. c.PeerAEAD = NewAEAD(encryptedPfsPublicKey[:1088+32], c.UnitedKey, c.UseAES)
  158. encryptedTicket := make([]byte, 32)
  159. if _, err := io.ReadFull(conn, encryptedTicket); err != nil {
  160. return nil, err
  161. }
  162. if _, err := c.PeerAEAD.Open(encryptedTicket[:0], nil, encryptedTicket, nil); err != nil {
  163. return nil, err
  164. }
  165. seconds := DecodeLength(encryptedTicket)
  166. if i.Seconds > 0 && seconds > 0 {
  167. i.RWLock.Lock()
  168. i.Expire = time.Now().Add(time.Duration(seconds) * time.Second)
  169. i.PfsKey = pfsKey
  170. i.Ticket = encryptedTicket[:16]
  171. i.RWLock.Unlock()
  172. }
  173. encryptedLength := make([]byte, 18)
  174. if _, err := io.ReadFull(conn, encryptedLength); err != nil {
  175. return nil, err
  176. }
  177. if _, err := c.PeerAEAD.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
  178. return nil, err
  179. }
  180. length := DecodeLength(encryptedLength[:2])
  181. c.PeerPadding = make([]byte, length) // important: allows server sends padding slowly, eliminating 1-RTT's traffic pattern
  182. if i.XorMode == 2 {
  183. c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, iv), NewCTR(c.UnitedKey, encryptedTicket[:16]), 0, length)
  184. }
  185. return c, nil
  186. }