|
|
@ -4,10 +4,8 @@ import ( |
|
|
|
"bytes" |
|
|
|
"bytes" |
|
|
|
"crypto/aes" |
|
|
|
"crypto/aes" |
|
|
|
"crypto/cipher" |
|
|
|
"crypto/cipher" |
|
|
|
"crypto/hmac" |
|
|
|
|
|
|
|
"crypto/rand" |
|
|
|
"crypto/rand" |
|
|
|
"encoding/binary" |
|
|
|
"encoding/binary" |
|
|
|
"errors" |
|
|
|
|
|
|
|
"io" |
|
|
|
"io" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
"v2ray.com/core/common" |
|
|
|
"v2ray.com/core/common" |
|
|
@ -28,39 +26,54 @@ func SealVMessAEADHeader(key [16]byte, data []byte) []byte { |
|
|
|
|
|
|
|
|
|
|
|
common.Must(binary.Write(aeadPayloadLengthSerializeBuffer, binary.BigEndian, headerPayloadDataLen)) |
|
|
|
common.Must(binary.Write(aeadPayloadLengthSerializeBuffer, binary.BigEndian, headerPayloadDataLen)) |
|
|
|
|
|
|
|
|
|
|
|
authidCheckValue := KDF16(key[:], KDFSaltConst_VmessAuthIDCheckValue, string(generatedAuthID[:]), string(aeadPayloadLengthSerializeBuffer.Bytes()), string(connectionNonce)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
aeadPayloadLengthSerializedByte := aeadPayloadLengthSerializeBuffer.Bytes() |
|
|
|
aeadPayloadLengthSerializedByte := aeadPayloadLengthSerializeBuffer.Bytes() |
|
|
|
|
|
|
|
var payloadHeaderLengthAEADEncrypted []byte |
|
|
|
|
|
|
|
|
|
|
|
aeadPayloadLengthMask := KDF16(key[:], KDFSaltConst_VMessLengthMask, string(generatedAuthID[:]), string(connectionNonce[:]))[:2] |
|
|
|
{ |
|
|
|
|
|
|
|
payloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADKey, string(generatedAuthID[:]), string(connectionNonce)) |
|
|
|
|
|
|
|
|
|
|
|
aeadPayloadLengthSerializedByte[0] = aeadPayloadLengthSerializedByte[0] ^ aeadPayloadLengthMask[0] |
|
|
|
payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12] |
|
|
|
aeadPayloadLengthSerializedByte[1] = aeadPayloadLengthSerializedByte[1] ^ aeadPayloadLengthMask[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce)) |
|
|
|
payloadHeaderLengthAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12] |
|
|
|
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderLengthAEADAESBlock) |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
panic(err.Error()) |
|
|
|
panic(err.Error()) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:]) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock) |
|
|
|
var payloadHeaderAEADEncrypted []byte |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
{ |
|
|
|
panic(err.Error()) |
|
|
|
payloadHeaderAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12] |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADEncrypted := payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:]) |
|
|
|
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:]) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var outputBuffer = bytes.NewBuffer(nil) |
|
|
|
var outputBuffer = bytes.NewBuffer(nil) |
|
|
|
|
|
|
|
|
|
|
|
common.Must2(outputBuffer.Write(generatedAuthID[:])) //16
|
|
|
|
common.Must2(outputBuffer.Write(generatedAuthID[:])) //16
|
|
|
|
|
|
|
|
|
|
|
|
common.Must2(outputBuffer.Write(authidCheckValue)) //16
|
|
|
|
common.Must2(outputBuffer.Write(payloadHeaderLengthAEADEncrypted)) //2+16
|
|
|
|
|
|
|
|
|
|
|
|
common.Must2(outputBuffer.Write(aeadPayloadLengthSerializedByte)) //2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
common.Must2(outputBuffer.Write(connectionNonce)) //8
|
|
|
|
common.Must2(outputBuffer.Write(connectionNonce)) //8
|
|
|
|
|
|
|
|
|
|
|
@ -70,72 +83,93 @@ func SealVMessAEADHeader(key [16]byte, data []byte) []byte { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func OpenVMessAEADHeader(key [16]byte, authid [16]byte, data io.Reader) ([]byte, bool, error, int) { |
|
|
|
func OpenVMessAEADHeader(key [16]byte, authid [16]byte, data io.Reader) ([]byte, bool, error, int) { |
|
|
|
var authidCheckValue [16]byte |
|
|
|
var payloadHeaderLengthAEADEncrypted [18]byte |
|
|
|
var headerPayloadDataLen [2]byte |
|
|
|
|
|
|
|
var nonce [8]byte |
|
|
|
var nonce [8]byte |
|
|
|
|
|
|
|
|
|
|
|
authidCheckValueReadBytesCounts, err := io.ReadFull(data, authidCheckValue[:]) |
|
|
|
var bytesRead int |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, false, err, authidCheckValueReadBytesCounts |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
headerPayloadDataLenReadBytesCounts, err := io.ReadFull(data, headerPayloadDataLen[:]) |
|
|
|
authidCheckValueReadBytesCounts, err := io.ReadFull(data, payloadHeaderLengthAEADEncrypted[:]) |
|
|
|
|
|
|
|
bytesRead += authidCheckValueReadBytesCounts |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, false, err, authidCheckValueReadBytesCounts + headerPayloadDataLenReadBytesCounts |
|
|
|
return nil, false, err, bytesRead |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
nonceReadBytesCounts, err := io.ReadFull(data, nonce[:]) |
|
|
|
nonceReadBytesCounts, err := io.ReadFull(data, nonce[:]) |
|
|
|
|
|
|
|
bytesRead += nonceReadBytesCounts |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, false, err, authidCheckValueReadBytesCounts + headerPayloadDataLenReadBytesCounts + nonceReadBytesCounts |
|
|
|
return nil, false, err, bytesRead |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Unmask Length
|
|
|
|
//Decrypt Length
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var decryptedAEADHeaderLengthPayloadResult []byte |
|
|
|
|
|
|
|
|
|
|
|
LengthMask := KDF16(key[:], KDFSaltConst_VMessLengthMask, string(authid[:]), string(nonce[:]))[:2] |
|
|
|
{ |
|
|
|
|
|
|
|
payloadHeaderLengthAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADKey, string(authid[:]), string(nonce[:])) |
|
|
|
|
|
|
|
|
|
|
|
headerPayloadDataLen[0] = headerPayloadDataLen[0] ^ LengthMask[0] |
|
|
|
payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadLengthAEADIV, string(authid[:]), string(nonce[:]))[:12] |
|
|
|
headerPayloadDataLen[1] = headerPayloadDataLen[1] ^ LengthMask[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
authidCheckValueReceivedFromNetwork := KDF16(key[:], KDFSaltConst_VmessAuthIDCheckValue, string(authid[:]), string(headerPayloadDataLen[:]), string(nonce[:])) |
|
|
|
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if !hmac.Equal(authidCheckValueReceivedFromNetwork, authidCheckValue[:]) { |
|
|
|
payloadHeaderLengthAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock) |
|
|
|
return nil, true, errCheckMismatch, authidCheckValueReadBytesCounts + headerPayloadDataLenReadBytesCounts + nonceReadBytesCounts |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decryptedAEADHeaderLengthPayload, erropenAEAD := payloadHeaderLengthAEAD.Open(nil, payloadHeaderLengthAEADNonce, payloadHeaderLengthAEADEncrypted[:], authid[:]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if erropenAEAD != nil { |
|
|
|
|
|
|
|
return nil, true, erropenAEAD, bytesRead |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decryptedAEADHeaderLengthPayloadResult = decryptedAEADHeaderLengthPayload |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var length uint16 |
|
|
|
var length uint16 |
|
|
|
|
|
|
|
|
|
|
|
common.Must(binary.Read(bytes.NewReader(headerPayloadDataLen[:]), binary.BigEndian, &length)) |
|
|
|
common.Must(binary.Read(bytes.NewReader(decryptedAEADHeaderLengthPayloadResult[:]), binary.BigEndian, &length)) |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadAEADKey, string(authid[:]), string(nonce[:])) |
|
|
|
var decryptedAEADHeaderPayloadR []byte |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadAEADIV, string(authid[:]), string(nonce[:]))[:12] |
|
|
|
var payloadHeaderAEADEncryptedReadedBytesCounts int |
|
|
|
|
|
|
|
|
|
|
|
//16 == AEAD Tag size
|
|
|
|
{ |
|
|
|
payloadHeaderAEADEncrypted := make([]byte, length+16) |
|
|
|
payloadHeaderAEADKey := KDF16(key[:], KDFSaltConst_VMessHeaderPayloadAEADKey, string(authid[:]), string(nonce[:])) |
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADEncryptedReadedBytesCounts, err := io.ReadFull(data, payloadHeaderAEADEncrypted) |
|
|
|
payloadHeaderAEADNonce := KDF(key[:], KDFSaltConst_VMessHeaderPayloadAEADIV, string(authid[:]), string(nonce[:]))[:12] |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, false, err, authidCheckValueReadBytesCounts + headerPayloadDataLenReadBytesCounts + payloadHeaderAEADEncryptedReadedBytesCounts + nonceReadBytesCounts |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey) |
|
|
|
//16 == AEAD Tag size
|
|
|
|
if err != nil { |
|
|
|
payloadHeaderAEADEncrypted := make([]byte, length+16) |
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock) |
|
|
|
payloadHeaderAEADEncryptedReadedBytesCounts, err = io.ReadFull(data, payloadHeaderAEADEncrypted) |
|
|
|
|
|
|
|
bytesRead += payloadHeaderAEADEncryptedReadedBytesCounts |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, false, err, bytesRead |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey) |
|
|
|
panic(err.Error()) |
|
|
|
if err != nil { |
|
|
|
} |
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
decryptedAEADHeaderPayload, erropenAEAD := payloadHeaderAEAD.Open(nil, payloadHeaderAEADNonce, payloadHeaderAEADEncrypted, authid[:]) |
|
|
|
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock) |
|
|
|
|
|
|
|
|
|
|
|
if erropenAEAD != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, true, erropenAEAD, authidCheckValueReadBytesCounts + headerPayloadDataLenReadBytesCounts + payloadHeaderAEADEncryptedReadedBytesCounts + nonceReadBytesCounts |
|
|
|
panic(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decryptedAEADHeaderPayload, erropenAEAD := payloadHeaderAEAD.Open(nil, payloadHeaderAEADNonce, payloadHeaderAEADEncrypted, authid[:]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if erropenAEAD != nil { |
|
|
|
|
|
|
|
return nil, true, erropenAEAD, bytesRead |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decryptedAEADHeaderPayloadR = decryptedAEADHeaderPayload |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return decryptedAEADHeaderPayload, false, nil, authidCheckValueReadBytesCounts + headerPayloadDataLenReadBytesCounts + payloadHeaderAEADEncryptedReadedBytesCounts + nonceReadBytesCounts |
|
|
|
return decryptedAEADHeaderPayloadR, false, nil, bytesRead |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var errCheckMismatch = errors.New("check verify failed") |
|
|
|
|
|
|
|