2018-07-03 00:31:43 +08:00
|
|
|
|
package vmess
|
|
|
|
|
|
|
|
|
|
import (
|
2018-07-03 14:30:56 +08:00
|
|
|
|
"bytes"
|
2018-07-03 01:07:28 +08:00
|
|
|
|
"crypto/md5"
|
2021-08-08 00:05:47 +08:00
|
|
|
|
"crypto/sha1"
|
2018-07-03 01:07:28 +08:00
|
|
|
|
"encoding/binary"
|
2018-07-03 00:31:43 +08:00
|
|
|
|
"encoding/hex"
|
|
|
|
|
"errors"
|
|
|
|
|
"strings"
|
2018-07-03 01:07:28 +08:00
|
|
|
|
"time"
|
2020-04-19 23:20:15 +08:00
|
|
|
|
|
2020-10-01 22:49:14 +08:00
|
|
|
|
"github.com/nadoo/glider/pool"
|
2018-07-03 00:31:43 +08:00
|
|
|
|
)
|
|
|
|
|
|
2020-08-16 12:00:46 +08:00
|
|
|
|
// User of vmess client.
|
2018-07-03 00:31:43 +08:00
|
|
|
|
type User struct {
|
2018-07-03 01:07:28 +08:00
|
|
|
|
UUID [16]byte
|
|
|
|
|
CmdKey [16]byte
|
2018-07-03 00:31:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 12:00:46 +08:00
|
|
|
|
// NewUser returns a new user.
|
2018-07-03 14:30:56 +08:00
|
|
|
|
func NewUser(uuid [16]byte) *User {
|
2018-07-03 01:07:28 +08:00
|
|
|
|
u := &User{UUID: uuid}
|
|
|
|
|
copy(u.CmdKey[:], GetKey(uuid))
|
2018-07-03 14:30:56 +08:00
|
|
|
|
return u
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func nextID(oldID [16]byte) (newID [16]byte) {
|
|
|
|
|
md5hash := md5.New()
|
|
|
|
|
md5hash.Write(oldID[:])
|
|
|
|
|
md5hash.Write([]byte("16167dc8-16b6-4e6d-b8bb-65dd68113a81"))
|
|
|
|
|
for {
|
|
|
|
|
md5hash.Sum(newID[:0])
|
|
|
|
|
if !bytes.Equal(oldID[:], newID[:]) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
md5hash.Write([]byte("533eff8a-4113-4b10-b5ce-0f5d76b98cd2"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 12:00:46 +08:00
|
|
|
|
// GenAlterIDUsers generates users according to primary user's id and alterID.
|
2018-07-03 14:30:56 +08:00
|
|
|
|
func (u *User) GenAlterIDUsers(alterID int) []*User {
|
|
|
|
|
users := make([]*User, alterID)
|
|
|
|
|
preID := u.UUID
|
|
|
|
|
for i := 0; i < alterID; i++ {
|
|
|
|
|
newID := nextID(preID)
|
|
|
|
|
// NOTE: alterID user is a user which have a different uuid but a same cmdkey with the primary user.
|
|
|
|
|
users[i] = &User{UUID: newID, CmdKey: u.CmdKey}
|
|
|
|
|
preID = newID
|
|
|
|
|
}
|
2018-07-03 00:31:43 +08:00
|
|
|
|
|
2018-07-03 14:30:56 +08:00
|
|
|
|
return users
|
2018-07-03 00:31:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// StrToUUID converts string to uuid.
|
|
|
|
|
func StrToUUID(s string) (uuid [16]byte, err error) {
|
2021-08-08 00:05:47 +08:00
|
|
|
|
if len(s) >= 1 && len(s) <= 30 {
|
|
|
|
|
h := sha1.New()
|
|
|
|
|
h.Write(uuid[:])
|
|
|
|
|
h.Write([]byte(s))
|
|
|
|
|
u := h.Sum(nil)[:16]
|
|
|
|
|
u[6] = (u[6] & 0x0f) | (5 << 4)
|
|
|
|
|
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
|
|
|
|
|
copy(uuid[:], u)
|
|
|
|
|
return
|
|
|
|
|
}
|
2018-07-03 00:31:43 +08:00
|
|
|
|
b := []byte(strings.Replace(s, "-", "", -1))
|
|
|
|
|
if len(b) != 32 {
|
|
|
|
|
return uuid, errors.New("invalid UUID: " + s)
|
|
|
|
|
}
|
|
|
|
|
_, err = hex.Decode(uuid[:], b)
|
|
|
|
|
return
|
|
|
|
|
}
|
2018-07-03 01:07:28 +08:00
|
|
|
|
|
2020-08-16 12:00:46 +08:00
|
|
|
|
// GetKey returns the key of AES-128-CFB encrypter.
|
2018-07-03 01:07:28 +08:00
|
|
|
|
// Key:MD5(UUID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
|
|
|
|
|
func GetKey(uuid [16]byte) []byte {
|
|
|
|
|
md5hash := md5.New()
|
|
|
|
|
md5hash.Write(uuid[:])
|
|
|
|
|
md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))
|
|
|
|
|
return md5hash.Sum(nil)
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 12:00:46 +08:00
|
|
|
|
// TimestampHash returns the iv of AES-128-CFB encrypter.
|
2018-07-03 01:07:28 +08:00
|
|
|
|
// IV:MD5(X + X + X + X),X = []byte(timestamp.now) (8 bytes, Big Endian)
|
|
|
|
|
func TimestampHash(t time.Time) []byte {
|
2020-04-19 23:20:15 +08:00
|
|
|
|
ts := pool.GetBuffer(8)
|
|
|
|
|
defer pool.PutBuffer(ts)
|
2018-07-03 01:07:28 +08:00
|
|
|
|
|
|
|
|
|
binary.BigEndian.PutUint64(ts, uint64(t.UTC().Unix()))
|
2020-04-19 23:20:15 +08:00
|
|
|
|
md5hash := md5.New()
|
2018-07-03 01:07:28 +08:00
|
|
|
|
md5hash.Write(ts)
|
|
|
|
|
md5hash.Write(ts)
|
|
|
|
|
md5hash.Write(ts)
|
|
|
|
|
md5hash.Write(ts)
|
|
|
|
|
return md5hash.Sum(nil)
|
|
|
|
|
}
|