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