mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-12-24 22:49:48 +00:00
120 lines
2.7 KiB
Go
120 lines
2.7 KiB
Go
|
package aead
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto/aes"
|
||
|
"crypto/cipher"
|
||
|
rand3 "crypto/rand"
|
||
|
"encoding/binary"
|
||
|
"errors"
|
||
|
"hash/crc32"
|
||
|
"io"
|
||
|
"math"
|
||
|
"time"
|
||
|
|
||
|
"github.com/xtls/xray-core/v1/common"
|
||
|
"github.com/xtls/xray-core/v1/common/antireplay"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
ErrNotFound = errors.New("user do not exist")
|
||
|
ErrReplay = errors.New("replayed request")
|
||
|
)
|
||
|
|
||
|
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, KDFSaltConstAuthIDEncryptionKey))
|
||
|
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), antireplay.NewReplayFilter(120)}
|
||
|
}
|
||
|
|
||
|
type AuthIDDecoderHolder struct {
|
||
|
decoders map[string]*AuthIDDecoderItem
|
||
|
filter *antireplay.ReplayFilter
|
||
|
}
|
||
|
|
||
|
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.decoders[string(key[:])] = NewAuthIDDecoderItem(key, ticket)
|
||
|
}
|
||
|
|
||
|
func (a *AuthIDDecoderHolder) RemoveUser(key [16]byte) {
|
||
|
delete(a.decoders, string(key[:]))
|
||
|
}
|
||
|
|
||
|
func (a *AuthIDDecoderHolder) Match(authID [16]byte) (interface{}, error) {
|
||
|
for _, v := range a.decoders {
|
||
|
t, z, _, d := v.dec.Decode(authID)
|
||
|
if z != crc32.ChecksumIEEE(d[:12]) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if t < 0 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) > 120 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if !a.filter.Check(authID[:]) {
|
||
|
return nil, ErrReplay
|
||
|
}
|
||
|
|
||
|
return v.ticket, nil
|
||
|
}
|
||
|
return nil, ErrNotFound
|
||
|
}
|