github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/vmess/tools.go (about)

     1  package vmess
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"crypto/hmac"
     8  	rand3 "crypto/rand"
     9  	"crypto/sha256"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"hash"
    13  	"hash/crc32"
    14  	"io"
    15  	"net"
    16  	"time"
    17  
    18  	"github.com/Asutorufa/yuhaiin/pkg/utils/pool"
    19  	"github.com/Asutorufa/yuhaiin/pkg/utils/relay"
    20  )
    21  
    22  // copy from https://github.com/v2fly/v2ray-core/tree/054e6679830885c94cc37d27ab2aa96b5b37e019/proxy/vmess/aead
    23  const (
    24  	KDFSaltConstAuthIDEncryptionKey             = "AES Auth ID Encryption"
    25  	KDFSaltConstAEADRespHeaderLenKey            = "AEAD Resp Header Len Key"
    26  	KDFSaltConstAEADRespHeaderLenIV             = "AEAD Resp Header Len IV"
    27  	KDFSaltConstAEADRespHeaderPayloadKey        = "AEAD Resp Header Key"
    28  	KDFSaltConstAEADRespHeaderPayloadIV         = "AEAD Resp Header IV"
    29  	KDFSaltConstVMessAEADKDF                    = "VMess AEAD KDF"
    30  	KDFSaltConstVMessHeaderPayloadAEADKey       = "VMess Header AEAD Key"
    31  	KDFSaltConstVMessHeaderPayloadAEADIV        = "VMess Header AEAD Nonce"
    32  	KDFSaltConstVMessHeaderPayloadLengthAEADKey = "VMess Header AEAD Key_Length"
    33  	KDFSaltConstVMessHeaderPayloadLengthAEADIV  = "VMess Header AEAD Nonce_Length"
    34  )
    35  
    36  func KDF(key []byte, path ...string) []byte {
    37  	hmacCreator := &hMacCreator{value: []byte(KDFSaltConstVMessAEADKDF)}
    38  	for _, v := range path {
    39  		hmacCreator = &hMacCreator{value: []byte(v), parent: hmacCreator}
    40  	}
    41  	hmacf := hmacCreator.Create()
    42  	hmacf.Write(key)
    43  	return hmacf.Sum(nil)
    44  }
    45  
    46  type hMacCreator struct {
    47  	parent *hMacCreator
    48  	value  []byte
    49  }
    50  
    51  func (h *hMacCreator) Create() hash.Hash {
    52  	if h.parent == nil {
    53  		return hmac.New(sha256.New, h.value)
    54  	}
    55  	return hmac.New(h.parent.Create, h.value)
    56  }
    57  
    58  func KDF16(key []byte, path ...string) []byte {
    59  	r := KDF(key, path...)
    60  	return r[:16]
    61  }
    62  
    63  func CreateAuthID(cmdKey []byte, time int64) [16]byte {
    64  	buf := pool.GetBytesWriter(pool.DefaultSize)
    65  	defer buf.Free()
    66  
    67  	_ = binary.Write(buf, binary.BigEndian, time)
    68  	_, _ = relay.CopyN(buf, rand3.Reader, 4)
    69  	zero := crc32.ChecksumIEEE(buf.Bytes())
    70  	_ = binary.Write(buf, binary.BigEndian, zero)
    71  	aesBlock := NewCipherFromKey(cmdKey)
    72  	if buf.Len() != 16 {
    73  		panic("Size unexpected")
    74  	}
    75  	var result [16]byte
    76  	aesBlock.Encrypt(result[:], buf.Bytes())
    77  	return result
    78  }
    79  
    80  func NewCipherFromKey(cmdKey []byte) cipher.Block {
    81  	aesBlock, err := aes.NewCipher(KDF16(cmdKey, KDFSaltConstAuthIDEncryptionKey))
    82  	if err != nil {
    83  		panic(err)
    84  	}
    85  	return aesBlock
    86  }
    87  
    88  func SealVMessAEADHeader(key [16]byte, data []byte) []byte {
    89  	generatedAuthID := CreateAuthID(key[:], time.Now().Unix())
    90  
    91  	connectionNonce := pool.GetBytes(8)
    92  	defer pool.PutBytes(connectionNonce)
    93  
    94  	connectionNonce = connectionNonce[:8]
    95  	if _, err := io.ReadFull(rand3.Reader, connectionNonce); err != nil {
    96  		panic(err.Error())
    97  	}
    98  
    99  	aeadPayloadLengthSerializeBuffer := bytes.NewBuffer(nil)
   100  	headerPayloadDataLen := uint16(len(data))
   101  	_ = binary.Write(aeadPayloadLengthSerializeBuffer, binary.BigEndian, headerPayloadDataLen)
   102  	aeadPayloadLengthSerializedByte := aeadPayloadLengthSerializeBuffer.Bytes()
   103  
   104  	var payloadHeaderLengthAEADEncrypted []byte
   105  
   106  	{
   107  		payloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADKey, string(generatedAuthID[:]), string(connectionNonce))
   108  
   109  		payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
   110  
   111  		payloadHeaderLengthAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)
   112  		if err != nil {
   113  			panic(err.Error())
   114  		}
   115  
   116  		payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderLengthAEADAESBlock)
   117  		if err != nil {
   118  			panic(err.Error())
   119  		}
   120  
   121  		payloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:])
   122  	}
   123  
   124  	var payloadHeaderAEADEncrypted []byte
   125  
   126  	{
   127  		payloadHeaderAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce))
   128  
   129  		payloadHeaderAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
   130  
   131  		payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)
   132  		if err != nil {
   133  			panic(err.Error())
   134  		}
   135  
   136  		payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
   137  		if err != nil {
   138  			panic(err.Error())
   139  		}
   140  
   141  		payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
   142  	}
   143  
   144  	outputBuffer := bytes.NewBuffer(nil)
   145  
   146  	outputBuffer.Write(generatedAuthID[:])               // 16
   147  	outputBuffer.Write(payloadHeaderLengthAEADEncrypted) // 2+16
   148  	outputBuffer.Write(connectionNonce)                  // 8
   149  	outputBuffer.Write(payloadHeaderAEADEncrypted)
   150  
   151  	return outputBuffer.Bytes()
   152  }
   153  
   154  func OpenVMessAEADHeader(key [16]byte, authid [16]byte, data io.Reader) ([]byte, bool, int, error) {
   155  	var payloadHeaderLengthAEADEncrypted [18]byte
   156  	var nonce [8]byte
   157  
   158  	var bytesRead int
   159  
   160  	authidCheckValueReadBytesCounts, err := io.ReadFull(data, payloadHeaderLengthAEADEncrypted[:])
   161  	bytesRead += authidCheckValueReadBytesCounts
   162  	if err != nil {
   163  		return nil, false, bytesRead, err
   164  	}
   165  
   166  	nonceReadBytesCounts, err := io.ReadFull(data, nonce[:])
   167  	bytesRead += nonceReadBytesCounts
   168  	if err != nil {
   169  		return nil, false, bytesRead, err
   170  	}
   171  
   172  	// Decrypt Length
   173  
   174  	var decryptedAEADHeaderLengthPayloadResult []byte
   175  
   176  	{
   177  		payloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADKey, string(authid[:]), string(nonce[:]))
   178  
   179  		payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADIV, string(authid[:]), string(nonce[:]))[:12]
   180  
   181  		payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)
   182  		if err != nil {
   183  			panic(err.Error())
   184  		}
   185  
   186  		payloadHeaderLengthAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
   187  		if err != nil {
   188  			panic(err.Error())
   189  		}
   190  
   191  		decryptedAEADHeaderLengthPayload, erropenAEAD := payloadHeaderLengthAEAD.Open(nil, payloadHeaderLengthAEADNonce, payloadHeaderLengthAEADEncrypted[:], authid[:])
   192  
   193  		if erropenAEAD != nil {
   194  			return nil, true, bytesRead, erropenAEAD
   195  		}
   196  
   197  		decryptedAEADHeaderLengthPayloadResult = decryptedAEADHeaderLengthPayload
   198  	}
   199  
   200  	var length uint16
   201  
   202  	_ = binary.Read(bytes.NewReader(decryptedAEADHeaderLengthPayloadResult), binary.BigEndian, &length)
   203  
   204  	var decryptedAEADHeaderPayloadR []byte
   205  
   206  	var payloadHeaderAEADEncryptedReadedBytesCounts int
   207  
   208  	{
   209  		payloadHeaderAEADKey := KDF16(key[:], KDFSaltConstVMessHeaderPayloadAEADKey, string(authid[:]), string(nonce[:]))
   210  
   211  		payloadHeaderAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadAEADIV, string(authid[:]), string(nonce[:]))[:12]
   212  
   213  		// 16 == AEAD Tag size
   214  		payloadHeaderAEADEncrypted := make([]byte, length+16)
   215  
   216  		payloadHeaderAEADEncryptedReadedBytesCounts, err = io.ReadFull(data, payloadHeaderAEADEncrypted)
   217  		bytesRead += payloadHeaderAEADEncryptedReadedBytesCounts
   218  		if err != nil {
   219  			return nil, false, bytesRead, err
   220  		}
   221  
   222  		payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)
   223  		if err != nil {
   224  			panic(err.Error())
   225  		}
   226  
   227  		payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
   228  		if err != nil {
   229  			panic(err.Error())
   230  		}
   231  
   232  		decryptedAEADHeaderPayload, erropenAEAD := payloadHeaderAEAD.Open(nil, payloadHeaderAEADNonce, payloadHeaderAEADEncrypted, nil)
   233  
   234  		if erropenAEAD != nil {
   235  			return nil, true, bytesRead, erropenAEAD
   236  		}
   237  
   238  		decryptedAEADHeaderPayloadR = decryptedAEADHeaderPayload
   239  	}
   240  
   241  	return decryptedAEADHeaderPayloadR, false, bytesRead, nil
   242  }
   243  
   244  // from https://github.com/v2ray/v2ray-core/blob/5dffca84234a74da9e8174f1e0b0af3dfb2a58ce/proxy/vmess/encoding/client.go#L191
   245  func DecodeResponseHeader(responseBodyKey, responseBodyIV []byte, reader net.Conn) ([]byte, error) {
   246  	aeadResponseHeaderLengthEncryptionKey := KDF16(responseBodyKey[:], KDFSaltConstAEADRespHeaderLenKey)
   247  	aeadResponseHeaderLengthEncryptionIV := KDF(responseBodyIV[:], KDFSaltConstAEADRespHeaderLenIV)[:12]
   248  
   249  	aeadResponseHeaderLengthEncryptionKeyAESBlock, err := aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)
   250  	if err != nil {
   251  		return nil, fmt.Errorf("create aes cipher failed: %w", err)
   252  	}
   253  	aeadResponseHeaderLengthEncryptionAEAD, err := cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)
   254  	if err != nil {
   255  		return nil, fmt.Errorf("create aead failed: %w", err)
   256  	}
   257  
   258  	var aeadEncryptedResponseHeaderLength [18]byte
   259  	var decryptedResponseHeaderLength int
   260  	var decryptedResponseHeaderLengthBinaryDeserializeBuffer uint16
   261  
   262  	if _, err := io.ReadFull(reader, aeadEncryptedResponseHeaderLength[:]); err != nil {
   263  		return nil, fmt.Errorf("read encrypted response header length failed: %w", err)
   264  	}
   265  	if decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil); err != nil {
   266  		return nil, fmt.Errorf("decrypt response header length failed: %w", err)
   267  	} else {
   268  		_ = binary.Read(bytes.NewReader(decryptedResponseHeaderLengthBinaryBuffer), binary.BigEndian, &decryptedResponseHeaderLengthBinaryDeserializeBuffer)
   269  		decryptedResponseHeaderLength = int(decryptedResponseHeaderLengthBinaryDeserializeBuffer)
   270  	}
   271  
   272  	aeadResponseHeaderPayloadEncryptionKey := KDF16(responseBodyKey[:], KDFSaltConstAEADRespHeaderPayloadKey)
   273  	aeadResponseHeaderPayloadEncryptionIV := KDF(responseBodyIV[:], KDFSaltConstAEADRespHeaderPayloadIV)[:12]
   274  
   275  	aeadResponseHeaderPayloadEncryptionKeyAESBlock, err := aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)
   276  	if err != nil {
   277  		return nil, fmt.Errorf("create aes cipher failed: %w", err)
   278  	}
   279  	aeadResponseHeaderPayloadEncryptionAEAD, err := cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)
   280  	if err != nil {
   281  		return nil, fmt.Errorf("create aead failed: %w", err)
   282  	}
   283  
   284  	encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16)
   285  
   286  	if _, err := io.ReadFull(reader, encryptedResponseHeaderBuffer); err != nil {
   287  		return nil, fmt.Errorf("read encrypted response header failed: %w", err)
   288  	}
   289  
   290  	decryptedResponseHeaderBuffer, err := aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil)
   291  	if err != nil {
   292  		return nil, fmt.Errorf("decrypt response header failed: %w", err)
   293  	}
   294  
   295  	return decryptedResponseHeaderBuffer, nil
   296  }