github.com/igoogolx/clash@v1.19.8/transport/vmess/header.go (about) 1 package vmess 2 3 import ( 4 "crypto/aes" 5 "crypto/cipher" 6 "crypto/hmac" 7 "crypto/rand" 8 "crypto/sha256" 9 "encoding/binary" 10 "hash" 11 "hash/crc32" 12 "time" 13 14 "github.com/Dreamacro/protobytes" 15 ) 16 17 const ( 18 kdfSaltConstAuthIDEncryptionKey = "AES Auth ID Encryption" 19 kdfSaltConstAEADRespHeaderLenKey = "AEAD Resp Header Len Key" 20 kdfSaltConstAEADRespHeaderLenIV = "AEAD Resp Header Len IV" 21 kdfSaltConstAEADRespHeaderPayloadKey = "AEAD Resp Header Key" 22 kdfSaltConstAEADRespHeaderPayloadIV = "AEAD Resp Header IV" 23 kdfSaltConstVMessAEADKDF = "VMess AEAD KDF" 24 kdfSaltConstVMessHeaderPayloadAEADKey = "VMess Header AEAD Key" 25 kdfSaltConstVMessHeaderPayloadAEADIV = "VMess Header AEAD Nonce" 26 kdfSaltConstVMessHeaderPayloadLengthAEADKey = "VMess Header AEAD Key_Length" 27 kdfSaltConstVMessHeaderPayloadLengthAEADIV = "VMess Header AEAD Nonce_Length" 28 ) 29 30 func kdf(key []byte, path ...string) []byte { 31 hmacCreator := &hMacCreator{value: []byte(kdfSaltConstVMessAEADKDF)} 32 for _, v := range path { 33 hmacCreator = &hMacCreator{value: []byte(v), parent: hmacCreator} 34 } 35 hmacf := hmacCreator.Create() 36 hmacf.Write(key) 37 return hmacf.Sum(nil) 38 } 39 40 type hMacCreator struct { 41 parent *hMacCreator 42 value []byte 43 } 44 45 func (h *hMacCreator) Create() hash.Hash { 46 if h.parent == nil { 47 return hmac.New(sha256.New, h.value) 48 } 49 return hmac.New(h.parent.Create, h.value) 50 } 51 52 func createAuthID(cmdKey []byte, time int64) [16]byte { 53 buf := protobytes.BytesWriter{} 54 buf.PutUint64be(uint64(time)) 55 buf.ReadFull(rand.Reader, 4) 56 zero := crc32.ChecksumIEEE(buf.Bytes()) 57 buf.PutUint32be(zero) 58 59 aesBlock, _ := aes.NewCipher(kdf(cmdKey[:], kdfSaltConstAuthIDEncryptionKey)[:16]) 60 var result [16]byte 61 aesBlock.Encrypt(result[:], buf.Bytes()) 62 return result 63 } 64 65 func sealVMessAEADHeader(key [16]byte, data []byte, t time.Time) []byte { 66 generatedAuthID := createAuthID(key[:], t.Unix()) 67 connectionNonce := make([]byte, 8) 68 rand.Read(connectionNonce) 69 70 aeadPayloadLengthSerializedByte := make([]byte, 2) 71 binary.BigEndian.PutUint16(aeadPayloadLengthSerializedByte, uint16(len(data))) 72 73 var payloadHeaderLengthAEADEncrypted []byte 74 75 { 76 payloadHeaderLengthAEADKey := kdf(key[:], kdfSaltConstVMessHeaderPayloadLengthAEADKey, string(generatedAuthID[:]), string(connectionNonce))[:16] 77 payloadHeaderLengthAEADNonce := kdf(key[:], kdfSaltConstVMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12] 78 payloadHeaderLengthAEADAESBlock, _ := aes.NewCipher(payloadHeaderLengthAEADKey) 79 payloadHeaderAEAD, _ := cipher.NewGCM(payloadHeaderLengthAEADAESBlock) 80 payloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:]) 81 } 82 83 var payloadHeaderAEADEncrypted []byte 84 85 { 86 payloadHeaderAEADKey := kdf(key[:], kdfSaltConstVMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce))[:16] 87 payloadHeaderAEADNonce := kdf(key[:], kdfSaltConstVMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12] 88 payloadHeaderAEADAESBlock, _ := aes.NewCipher(payloadHeaderAEADKey) 89 payloadHeaderAEAD, _ := cipher.NewGCM(payloadHeaderAEADAESBlock) 90 payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:]) 91 } 92 93 outputBuffer := protobytes.BytesWriter{} 94 95 outputBuffer.PutSlice(generatedAuthID[:]) 96 outputBuffer.PutSlice(payloadHeaderLengthAEADEncrypted) 97 outputBuffer.PutSlice(connectionNonce) 98 outputBuffer.PutSlice(payloadHeaderAEADEncrypted) 99 100 return outputBuffer.Bytes() 101 }