package aead import ( "bytes" "crypto/aes" "crypto/cipher" rand3 "crypto/rand" "encoding/binary" "errors" "hash/crc32" "io" "math" "time" "v2ray.com/core/common" antiReplayWindow "v2ray.com/core/common/antireplay" ) func CreateAuthID(cmdKey []byte, time int64) [16]byte { buf := bytes.NewBuffer(nil) common.Must(binary.Write(buf, binary.BigEndian, time)) var zero uint32 common.Must2(io.CopyN(buf, rand3.Reader, 4)) zero = crc32.ChecksumIEEE(buf.Bytes()) common.Must(binary.Write(buf, binary.BigEndian, zero)) aesBlock := NewCipherFromKey(cmdKey) if buf.Len() != 16 { panic("Size unexpected") } var result [16]byte aesBlock.Encrypt(result[:], buf.Bytes()) return result } func NewCipherFromKey(cmdKey []byte) cipher.Block { aesBlock, err := aes.NewCipher(KDF16(cmdKey, "AES Auth ID Encryption")) if err != nil { panic(err) } return aesBlock } type AuthIDDecoder struct { s cipher.Block } func NewAuthIDDecoder(cmdKey []byte) *AuthIDDecoder { return &AuthIDDecoder{NewCipherFromKey(cmdKey)} } func (aidd *AuthIDDecoder) Decode(data [16]byte) (int64, uint32, int32, []byte) { aidd.s.Decrypt(data[:], data[:]) var t int64 var zero uint32 var rand int32 reader := bytes.NewReader(data[:]) common.Must(binary.Read(reader, binary.BigEndian, &t)) common.Must(binary.Read(reader, binary.BigEndian, &rand)) common.Must(binary.Read(reader, binary.BigEndian, &zero)) return t, zero, rand, data[:] } func NewAuthIDDecoderHolder() *AuthIDDecoderHolder { return &AuthIDDecoderHolder{make(map[string]*AuthIDDecoderItem), antiReplayWindow.NewAntiReplayWindow(120)} } type AuthIDDecoderHolder struct { aidhi map[string]*AuthIDDecoderItem apw *antiReplayWindow.AntiReplayWindow } type AuthIDDecoderItem struct { dec *AuthIDDecoder ticket interface{} } func NewAuthIDDecoderItem(key [16]byte, ticket interface{}) *AuthIDDecoderItem { return &AuthIDDecoderItem{ dec: NewAuthIDDecoder(key[:]), ticket: ticket, } } func (a *AuthIDDecoderHolder) AddUser(key [16]byte, ticket interface{}) { a.aidhi[string(key[:])] = NewAuthIDDecoderItem(key, ticket) } func (a *AuthIDDecoderHolder) RemoveUser(key [16]byte) { delete(a.aidhi, string(key[:])) } func (a *AuthIDDecoderHolder) Match(AuthID [16]byte) (interface{}, error) { for _, v := range a.aidhi { t, z, r, d := v.dec.Decode(AuthID) if z != crc32.ChecksumIEEE(d[:12]) { continue } if !a.apw.Check(AuthID[:]) { return nil, ErrReplay } if math.Abs(float64(t-time.Now().Unix())) > 120 { continue } _ = r return v.ticket, nil } return nil, ErrNotFound } var ErrNotFound = errors.New("user do not exist") var ErrReplay = errors.New("replayed request")