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  }