mirror of https://github.com/cbeuw/Cloak
Reduce the size of UID to 16 bytes
This commit is contained in:
parent
d781c7b1be
commit
710fa6835a
|
|
@ -34,6 +34,8 @@ type UserInfo struct {
|
|||
ExpiryTime int64
|
||||
}
|
||||
|
||||
var b64 = base64.StdEncoding
|
||||
|
||||
type administrator struct {
|
||||
adminConn net.Conn
|
||||
adminUID []byte
|
||||
|
|
@ -87,7 +89,7 @@ func adminHandshake(sta *client.State) (*administrator, error) {
|
|||
fmt.Println("Enter the admin UID")
|
||||
var b64AdminUID string
|
||||
fmt.Scanln(&b64AdminUID)
|
||||
adminUID, err := base64.StdEncoding.DecodeString(b64AdminUID)
|
||||
adminUID, err := b64.DecodeString(b64AdminUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -122,7 +124,7 @@ func (a *administrator) getRequest() (req []byte, err error) {
|
|||
fmt.Println("Enter UID")
|
||||
var b64UID string
|
||||
fmt.Scanln(&b64UID)
|
||||
ret, _ := base64.StdEncoding.DecodeString(b64UID)
|
||||
ret, _ := b64.DecodeString(b64UID)
|
||||
return ret
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +161,7 @@ func (a *administrator) getRequest() (req []byte, err error) {
|
|||
var b64UID string
|
||||
fmt.Printf("UID:")
|
||||
fmt.Scanln(&b64UID)
|
||||
UID, _ := base64.StdEncoding.DecodeString(b64UID)
|
||||
UID, _ := b64.DecodeString(b64UID)
|
||||
uinfo.UID = UID
|
||||
fmt.Printf("SessionsCap:")
|
||||
fmt.Scanf("%d", &uinfo.SessionsCap)
|
||||
|
|
@ -188,44 +190,44 @@ func (a *administrator) getRequest() (req []byte, err error) {
|
|||
UID := promptUID()
|
||||
req = a.request(append([]byte{0x06}, UID...))
|
||||
case "7":
|
||||
arg := make([]byte, 36)
|
||||
arg := make([]byte, 20)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptUint32("SessionsCap"))
|
||||
copy(arg[16:], promptUint32("SessionsCap"))
|
||||
req = a.request(append([]byte{0x07}, arg...))
|
||||
case "8":
|
||||
arg := make([]byte, 40)
|
||||
arg := make([]byte, 24)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptInt64("UpRate"))
|
||||
copy(arg[16:], promptInt64("UpRate"))
|
||||
req = a.request(append([]byte{0x08}, arg...))
|
||||
case "9":
|
||||
arg := make([]byte, 40)
|
||||
arg := make([]byte, 24)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptInt64("DownRate"))
|
||||
copy(arg[16:], promptInt64("DownRate"))
|
||||
req = a.request(append([]byte{0x09}, arg...))
|
||||
case "10":
|
||||
arg := make([]byte, 40)
|
||||
arg := make([]byte, 24)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptInt64("UpCredit"))
|
||||
copy(arg[16:], promptInt64("UpCredit"))
|
||||
req = a.request(append([]byte{0x0a}, arg...))
|
||||
case "11":
|
||||
arg := make([]byte, 40)
|
||||
arg := make([]byte, 24)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptInt64("DownCredit"))
|
||||
copy(arg[16:], promptInt64("DownCredit"))
|
||||
req = a.request(append([]byte{0x0b}, arg...))
|
||||
case "12":
|
||||
arg := make([]byte, 40)
|
||||
arg := make([]byte, 24)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptInt64("ExpiryTime"))
|
||||
copy(arg[16:], promptInt64("ExpiryTime"))
|
||||
req = a.request(append([]byte{0x0c}, arg...))
|
||||
case "13":
|
||||
arg := make([]byte, 40)
|
||||
arg := make([]byte, 24)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptInt64("UpCredit to add"))
|
||||
copy(arg[16:], promptInt64("UpCredit to add"))
|
||||
req = a.request(append([]byte{0x0d}, arg...))
|
||||
case "14":
|
||||
arg := make([]byte, 40)
|
||||
arg := make([]byte, 24)
|
||||
copy(arg, promptUID())
|
||||
copy(arg[32:], promptInt64("DownCredit to add"))
|
||||
copy(arg[16:], promptInt64("DownCredit to add"))
|
||||
req = a.request(append([]byte{0x0e}, arg...))
|
||||
default:
|
||||
return nil, errors.New("Unreconised cmd")
|
||||
|
|
@ -245,11 +247,11 @@ func (a *administrator) request(data []byte) []byte {
|
|||
|
||||
rand.Read(buf[5:21]) //iv
|
||||
copy(buf[21:], data)
|
||||
block, _ := aes.NewCipher(a.adminUID[0:16])
|
||||
block, _ := aes.NewCipher(a.adminUID)
|
||||
stream := cipher.NewCTR(block, buf[5:21])
|
||||
stream.XORKeyStream(buf[21:21+dataLen], buf[21:21+dataLen])
|
||||
|
||||
mac := hmac.New(sha256.New, a.adminUID[16:32])
|
||||
mac := hmac.New(sha256.New, a.adminUID)
|
||||
mac.Write(buf[5 : 21+dataLen])
|
||||
copy(buf[21+dataLen:], mac.Sum(nil))
|
||||
|
||||
|
|
@ -260,7 +262,7 @@ var ErrInvalidMac = errors.New("Mac mismatch")
|
|||
|
||||
func (a *administrator) checkAndDecrypt(data []byte) ([]byte, error) {
|
||||
macIndex := len(data) - 32
|
||||
mac := hmac.New(sha256.New, a.adminUID[16:32])
|
||||
mac := hmac.New(sha256.New, a.adminUID)
|
||||
mac.Write(data[5:macIndex])
|
||||
expected := mac.Sum(nil)
|
||||
if !hmac.Equal(data[macIndex:], expected) {
|
||||
|
|
@ -269,7 +271,7 @@ func (a *administrator) checkAndDecrypt(data []byte) ([]byte, error) {
|
|||
|
||||
iv := data[5:21]
|
||||
ret := data[21:macIndex]
|
||||
block, _ := aes.NewCipher(a.adminUID[0:16])
|
||||
block, _ := aes.NewCipher(a.adminUID)
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(ret, ret)
|
||||
return ret, nil
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/cbeuw/Cloak/internal/util"
|
||||
)
|
||||
|
||||
var b64 = base64.StdEncoding
|
||||
var version string
|
||||
|
||||
func pipe(dst io.ReadWriteCloser, src io.ReadWriteCloser) {
|
||||
|
|
@ -184,13 +185,13 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
|
|||
sesh.AddConnection(conn)
|
||||
return
|
||||
} else {
|
||||
log.Printf("New session from UID:%v, sessionID:%v\n", base64.StdEncoding.EncodeToString(UID), sessionID)
|
||||
log.Printf("New session from UID:%v, sessionID:%v\n", b64.EncodeToString(UID), sessionID)
|
||||
sesh.AddConnection(conn)
|
||||
for {
|
||||
newStream, err := sesh.AcceptStream()
|
||||
if err != nil {
|
||||
if err == mux.ErrBrokenSession {
|
||||
log.Printf("Session closed for UID:%v, sessionID:%v\n", base64.StdEncoding.EncodeToString(UID), sessionID)
|
||||
log.Printf("Session closed for UID:%v, sessionID:%v\n", b64.EncodeToString(UID), sessionID)
|
||||
user.DelSession(sessionID)
|
||||
return
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,21 +2,18 @@ package main
|
|||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"github.com/cbeuw/Cloak/internal/ecdh"
|
||||
)
|
||||
|
||||
var b64 = base64.StdEncoding.EncodeToString
|
||||
|
||||
func generateUID() string {
|
||||
UID := make([]byte, 32)
|
||||
UID := make([]byte, 16)
|
||||
rand.Read(UID)
|
||||
return b64(UID)
|
||||
return b64.EncodeToString(UID)
|
||||
}
|
||||
|
||||
func generateKeyPair() (string, string) {
|
||||
staticPv, staticPub, _ := ecdh.GenerateKey(rand.Reader)
|
||||
marshPub := ecdh.Marshal(staticPub)
|
||||
marshPv := staticPv.(*[32]byte)[:]
|
||||
return b64(marshPub), b64(marshPv)
|
||||
return b64.EncodeToString(marshPub), b64.EncodeToString(marshPv)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"ProxyMethod":"shadowsocks",
|
||||
"EncryptionMethod":"plain",
|
||||
"UID":"iGAO85zysIyR4c09CyZSLdNhtP/ckcYu7nIPI082AHA=",
|
||||
"UID":"5nneblJy6lniPJfr81LuYQ==",
|
||||
"PublicKey":"IYoUzkle/T/kriE+Ufdm7AHQtIeGnBWbhhlTbmDpUUI=",
|
||||
"ServerName":"www.bing.com",
|
||||
"TicketTimeHint":3600,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
"RedirAddr":"204.79.197.200:443",
|
||||
"PrivateKey":"EN5aPEpNBO+vw+BtFQY2OnK9bQU7rvEj5qmnmgwEtUc=",
|
||||
"AdminUID":"ugDmcEmxWf0pKxfkZ/8EoP35Ht+wQnqf3L0xYgyQFlQ=",
|
||||
"AdminUID":"T6L7MKPOCTQDG7ACFIXJOT25OQ",
|
||||
"DatabasePath":"userinfo.db",
|
||||
"BackupDirPath":""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func MakeRandomField(sta *State) []byte {
|
|||
}
|
||||
|
||||
func MakeSessionTicket(sta *State) []byte {
|
||||
// sessionTicket: [marshalled ephemeral pub key 32 bytes][encrypted UID+sessionID 36 bytes, proxy method 16 bytes, encryption method 1 byte, sessionKey 32 bytes][16 bytes authentication tag][padding 59 bytes]
|
||||
// sessionTicket: [marshalled ephemeral pub key 32 bytes][encrypted UID+sessionID 20 bytes, proxy method 16 bytes, encryption method 1 byte, sessionKey 32 bytes][16 bytes authentication tag][padding 75 bytes]
|
||||
// The first 12 bytes of the marshalled ephemeral public key is used as the nonce
|
||||
// for encrypting the UID
|
||||
tthInterval := sta.Now().Unix() / int64(sta.TicketTimeHint)
|
||||
|
|
@ -53,15 +53,15 @@ func MakeSessionTicket(sta *State) []byte {
|
|||
copy(ticket[0:32], ecdh.Marshal(ephKP.PublicKey))
|
||||
key := ecdh.GenerateSharedSecret(ephKP.PrivateKey, sta.staticPub)
|
||||
|
||||
plain := make([]byte, 85)
|
||||
plain := make([]byte, 69)
|
||||
copy(plain, sta.UID)
|
||||
binary.BigEndian.PutUint32(plain[32:36], sta.sessionID)
|
||||
copy(plain[36:52], []byte(sta.ProxyMethod))
|
||||
plain[52] = sta.EncryptionMethod
|
||||
copy(plain[53:85], sta.SessionKey)
|
||||
binary.BigEndian.PutUint32(plain[16:20], sta.sessionID)
|
||||
copy(plain[20:36], []byte(sta.ProxyMethod))
|
||||
plain[36] = sta.EncryptionMethod
|
||||
copy(plain[37:69], sta.SessionKey)
|
||||
|
||||
cipher, _ := util.AESGCMEncrypt(ticket[0:12], key, plain)
|
||||
copy(ticket[32:133], cipher)
|
||||
copy(ticket[32:117], cipher)
|
||||
// The purpose of adding sessionID is that, the generated padding of sessionTicket needs to be unpredictable.
|
||||
// As shown in auth.go, the padding is generated by a psudo random generator. The seed
|
||||
// needs to be the same for each TicketTimeHint interval. However the value of epoch/TicketTimeHint
|
||||
|
|
@ -72,6 +72,6 @@ func MakeSessionTicket(sta *State) []byte {
|
|||
// With the sessionID value generated at startup of ckclient and used as a part of the seed, the
|
||||
// sessionTicket is still identical for each TicketTimeHint interval, but others won't be able to know
|
||||
// how it was generated. It will also be different for each client.
|
||||
copy(ticket[133:192], util.PsudoRandBytes(59, tthInterval+int64(sta.sessionID)))
|
||||
copy(ticket[117:192], util.PsudoRandBytes(75, tthInterval+int64(sta.sessionID)))
|
||||
return ticket
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ import (
|
|||
func decryptSessionTicket(staticPv crypto.PrivateKey, ticket []byte) ([]byte, uint32, string, byte, []byte) {
|
||||
ephPub, _ := ecdh.Unmarshal(ticket[0:32])
|
||||
key := ecdh.GenerateSharedSecret(staticPv, ephPub)
|
||||
plain, err := util.AESGCMDecrypt(ticket[0:12], key, ticket[32:133])
|
||||
plain, err := util.AESGCMDecrypt(ticket[0:12], key, ticket[32:117])
|
||||
if err != nil {
|
||||
return nil, 0, "", 0x00, nil
|
||||
}
|
||||
sessionID := binary.BigEndian.Uint32(plain[32:36])
|
||||
return plain[0:32], sessionID, string(bytes.Trim(plain[36:52], "\x00")), plain[52], plain[53:85]
|
||||
sessionID := binary.BigEndian.Uint32(plain[16:20])
|
||||
return plain[0:16], sessionID, string(bytes.Trim(plain[20:36], "\x00")), plain[36], plain[37:69]
|
||||
}
|
||||
|
||||
func validateRandom(random []byte, UID []byte, time int64) bool {
|
||||
|
|
@ -54,7 +54,7 @@ func TouchStone(ch *ClientHello, sta *State) (isCK bool, UID []byte, sessionID u
|
|||
return
|
||||
}
|
||||
UID, sessionID, proxyMethod, encryptionMethod, sessionKey = decryptSessionTicket(sta.staticPv, ticket)
|
||||
if len(UID) < 32 {
|
||||
if len(UID) < 16 {
|
||||
return
|
||||
}
|
||||
isCK = validateRandom(ch.random, UID, sta.Now().Unix())
|
||||
|
|
|
|||
|
|
@ -102,60 +102,60 @@ func (c *controller) HandleRequest(req []byte) (resp []byte, err error) {
|
|||
err = c.syncMemFromDB(arg)
|
||||
resp = check(err)
|
||||
case 7:
|
||||
if len(arg) < 36 {
|
||||
if len(arg) < 20 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.setSessionsCap(arg[0:32], Uint32(arg[32:36]))
|
||||
err = c.setSessionsCap(arg[0:16], Uint32(arg[16:20]))
|
||||
resp = check(err)
|
||||
case 8:
|
||||
if len(arg) < 40 {
|
||||
if len(arg) < 24 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.setUpRate(arg[0:32], int64(Uint64(arg[32:40])))
|
||||
err = c.setUpRate(arg[0:16], int64(Uint64(arg[16:24])))
|
||||
resp = check(err)
|
||||
case 9:
|
||||
if len(arg) < 40 {
|
||||
if len(arg) < 24 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.setDownRate(arg[0:32], int64(Uint64(arg[32:40])))
|
||||
err = c.setDownRate(arg[0:16], int64(Uint64(arg[16:24])))
|
||||
resp = check(err)
|
||||
case 10:
|
||||
if len(arg) < 40 {
|
||||
if len(arg) < 24 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.setUpCredit(arg[0:32], int64(Uint64(arg[32:40])))
|
||||
err = c.setUpCredit(arg[0:16], int64(Uint64(arg[16:24])))
|
||||
resp = check(err)
|
||||
case 11:
|
||||
if len(arg) < 40 {
|
||||
if len(arg) < 24 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.setDownCredit(arg[0:32], int64(Uint64(arg[32:40])))
|
||||
err = c.setDownCredit(arg[0:16], int64(Uint64(arg[16:24])))
|
||||
resp = check(err)
|
||||
case 12:
|
||||
if len(arg) < 40 {
|
||||
if len(arg) < 24 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.setExpiryTime(arg[0:32], int64(Uint64(arg[32:40])))
|
||||
err = c.setExpiryTime(arg[0:16], int64(Uint64(arg[16:24])))
|
||||
resp = check(err)
|
||||
case 13:
|
||||
if len(arg) < 40 {
|
||||
if len(arg) < 24 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.addUpCredit(arg[0:32], int64(Uint64(arg[32:40])))
|
||||
err = c.addUpCredit(arg[0:16], int64(Uint64(arg[16:24])))
|
||||
resp = check(err)
|
||||
case 14:
|
||||
if len(arg) < 40 {
|
||||
if len(arg) < 24 {
|
||||
resp = c.respond([]byte(errInvalidArgument.Error()))
|
||||
break
|
||||
}
|
||||
err = c.addDownCredit(arg[0:32], int64(Uint64(arg[32:40])))
|
||||
err = c.addDownCredit(arg[0:16], int64(Uint64(arg[16:24])))
|
||||
resp = check(err)
|
||||
default:
|
||||
return c.respond([]byte("Unsupported action")), nil
|
||||
|
|
@ -180,11 +180,11 @@ func (c *controller) respond(resp []byte) []byte {
|
|||
|
||||
rand.Read(buf[5:21]) //iv
|
||||
copy(buf[21:], resp)
|
||||
block, _ := aes.NewCipher(c.adminUID[0:16])
|
||||
block, _ := aes.NewCipher(c.adminUID)
|
||||
stream := cipher.NewCTR(block, buf[5:21])
|
||||
stream.XORKeyStream(buf[21:21+respLen], buf[21:21+respLen])
|
||||
|
||||
mac := hmac.New(sha256.New, c.adminUID[16:32])
|
||||
mac := hmac.New(sha256.New, c.adminUID)
|
||||
mac.Write(buf[5 : 21+respLen])
|
||||
copy(buf[21+respLen:], mac.Sum(nil))
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ func (c *controller) checkAndDecrypt(data []byte) ([]byte, error) {
|
|||
return nil, errMsgTooShort
|
||||
}
|
||||
macIndex := len(data) - 32
|
||||
mac := hmac.New(sha256.New, c.adminUID[16:32])
|
||||
mac := hmac.New(sha256.New, c.adminUID)
|
||||
mac.Write(data[5:macIndex])
|
||||
expected := mac.Sum(nil)
|
||||
if !hmac.Equal(data[macIndex:], expected) {
|
||||
|
|
@ -205,7 +205,7 @@ func (c *controller) checkAndDecrypt(data []byte) ([]byte, error) {
|
|||
|
||||
iv := data[5:21]
|
||||
ret := data[21:macIndex]
|
||||
block, _ := aes.NewCipher(c.adminUID[0:16])
|
||||
block, _ := aes.NewCipher(c.adminUID)
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(ret, ret)
|
||||
return ret, nil
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ type UserInfo struct {
|
|||
type User struct {
|
||||
up *Userpanel
|
||||
|
||||
arrUID [32]byte
|
||||
arrUID [16]byte
|
||||
|
||||
*UserInfo
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ type Userpanel struct {
|
|||
bakRoot string
|
||||
|
||||
activeUsersM sync.RWMutex
|
||||
activeUsers map[[32]byte]*User
|
||||
activeUsers map[[16]byte]*User
|
||||
}
|
||||
|
||||
func MakeUserpanel(dbPath, bakRoot string) (*Userpanel, error) {
|
||||
|
|
@ -40,7 +40,7 @@ func MakeUserpanel(dbPath, bakRoot string) (*Userpanel, error) {
|
|||
up := &Userpanel{
|
||||
db: db,
|
||||
bakRoot: bakRoot,
|
||||
activeUsers: make(map[[32]byte]*User),
|
||||
activeUsers: make(map[[16]byte]*User),
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
|
|
@ -102,7 +102,7 @@ var ErrUserNotActive = errors.New("User is not active")
|
|||
|
||||
func (up *Userpanel) GetAndActivateAdminUser(AdminUID []byte) (*User, error) {
|
||||
up.activeUsersM.Lock()
|
||||
var arrUID [32]byte
|
||||
var arrUID [16]byte
|
||||
copy(arrUID[:], AdminUID)
|
||||
if user, ok := up.activeUsers[arrUID]; ok {
|
||||
up.activeUsersM.Unlock()
|
||||
|
|
@ -129,7 +129,7 @@ func (up *Userpanel) GetAndActivateAdminUser(AdminUID []byte) (*User, error) {
|
|||
// from the db and mark it as an active user
|
||||
func (up *Userpanel) GetAndActivateUser(UID []byte) (*User, error) {
|
||||
up.activeUsersM.Lock()
|
||||
var arrUID [32]byte
|
||||
var arrUID [16]byte
|
||||
copy(arrUID[:], UID)
|
||||
if user, ok := up.activeUsers[arrUID]; ok {
|
||||
up.activeUsersM.Unlock()
|
||||
|
|
@ -191,7 +191,7 @@ func (up *Userpanel) updateDBEntryInt64(UID []byte, key string, value int64) err
|
|||
|
||||
// This is used when all sessions of a user close
|
||||
func (up *Userpanel) delActiveUser(UID []byte) {
|
||||
var arrUID [32]byte
|
||||
var arrUID [16]byte
|
||||
copy(arrUID[:], UID)
|
||||
up.activeUsersM.Lock()
|
||||
delete(up.activeUsers, arrUID)
|
||||
|
|
@ -199,7 +199,7 @@ func (up *Userpanel) delActiveUser(UID []byte) {
|
|||
}
|
||||
|
||||
func (up *Userpanel) getActiveUser(UID []byte) *User {
|
||||
var arrUID [32]byte
|
||||
var arrUID [16]byte
|
||||
copy(arrUID[:], UID)
|
||||
up.activeUsersM.RLock()
|
||||
ret := up.activeUsers[arrUID]
|
||||
|
|
|
|||
Loading…
Reference in New Issue