Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
This commit is contained in:
@ -1,4 +1,9 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
|
v4.8
|
||||||
|
1.优化了SPS连接HTTP上级的指令,避免了某些代理不响应的问题.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
v4.7
|
v4.7
|
||||||
1.增加了基于gomobile的sdk,对android/ios/windows/linux/mac提供SDK支持.
|
1.增加了基于gomobile的sdk,对android/ios/windows/linux/mac提供SDK支持.
|
||||||
2.优化了bridge的日志,增加了client和server的掉线日志.
|
2.优化了bridge的日志,增加了client和server的掉线日志.
|
||||||
|
|||||||
140
Godeps/Godeps.json
generated
140
Godeps/Godeps.json
generated
@ -1,11 +1,27 @@
|
|||||||
{
|
{
|
||||||
"ImportPath": "github.com/snail007/goproxy",
|
"ImportPath": "github.com/snail007/goproxy",
|
||||||
"GoVersion": "go1.9",
|
"GoVersion": "go1.8",
|
||||||
"GodepVersion": "v80",
|
"GodepVersion": "v80",
|
||||||
"Packages": [
|
"Packages": [
|
||||||
"./..."
|
"./..."
|
||||||
],
|
],
|
||||||
"Deps": [
|
"Deps": [
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/Yawning/chacha20",
|
||||||
|
"Rev": "e3b1f968fc6397b51d963fee8ec8711a47bc0ce8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/alecthomas/template",
|
||||||
|
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/alecthomas/template/parse",
|
||||||
|
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/alecthomas/units",
|
||||||
|
"Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/golang/snappy",
|
"ImportPath": "github.com/golang/snappy",
|
||||||
"Rev": "553a641470496b2327abcac10b36396bd98e45c9"
|
"Rev": "553a641470496b2327abcac10b36396bd98e45c9"
|
||||||
@ -15,66 +31,15 @@
|
|||||||
"Comment": "v1.0.4-1-g40b5202",
|
"Comment": "v1.0.4-1-g40b5202",
|
||||||
"Rev": "40b520211179dbf7eaafaa7fe1ffaa1b7d929ee0"
|
"Rev": "40b520211179dbf7eaafaa7fe1ffaa1b7d929ee0"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/xtaci/kcp-go",
|
|
||||||
"Comment": "v3.19-6-g21da33a",
|
|
||||||
"Rev": "21da33a6696d67c1bffb3c954366499d613097a6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/xtaci/smux",
|
|
||||||
"Comment": "v1.0.6",
|
|
||||||
"Rev": "ebec7ef2574b42a7088cd7751176483e0a27d458"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/crypto/ssh",
|
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/time/rate",
|
|
||||||
"Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
|
|
||||||
"Comment": "v2.2.5",
|
|
||||||
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/crypto/ed25519",
|
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/ipv4",
|
|
||||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/ipv6",
|
|
||||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/bpf",
|
|
||||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/internal/iana",
|
|
||||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "golang.org/x/net/internal/socket",
|
|
||||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/pkg/errors",
|
"ImportPath": "github.com/pkg/errors",
|
||||||
"Comment": "v0.8.0-6-g602255c",
|
"Comment": "v0.8.0-6-g602255c",
|
||||||
"Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9"
|
"Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/templexxx/cpufeat",
|
||||||
|
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/templexxx/reedsolomon",
|
"ImportPath": "github.com/templexxx/reedsolomon",
|
||||||
"Comment": "0.1.1-4-g7092926",
|
"Comment": "0.1.1-4-g7092926",
|
||||||
@ -90,6 +55,16 @@
|
|||||||
"Comment": "v1.0.1-3-g9d99fac",
|
"Comment": "v1.0.1-3-g9d99fac",
|
||||||
"Rev": "9d99face20b0dd300b7db50b3f69758de41c096a"
|
"Rev": "9d99face20b0dd300b7db50b3f69758de41c096a"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/xtaci/kcp-go",
|
||||||
|
"Comment": "v3.19-6-g21da33a",
|
||||||
|
"Rev": "21da33a6696d67c1bffb3c954366499d613097a6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/xtaci/smux",
|
||||||
|
"Comment": "v1.0.6",
|
||||||
|
"Rev": "ebec7ef2574b42a7088cd7751176483e0a27d458"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/blowfish",
|
"ImportPath": "golang.org/x/crypto/blowfish",
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
@ -98,10 +73,34 @@
|
|||||||
"ImportPath": "golang.org/x/crypto/cast5",
|
"ImportPath": "golang.org/x/crypto/cast5",
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||||
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/ed25519",
|
||||||
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
|
||||||
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
||||||
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/salsa20",
|
"ImportPath": "golang.org/x/crypto/salsa20",
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
||||||
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/crypto/ssh",
|
||||||
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/tea",
|
"ImportPath": "golang.org/x/crypto/tea",
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
@ -115,28 +114,33 @@
|
|||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/templexxx/cpufeat",
|
"ImportPath": "golang.org/x/net/bpf",
|
||||||
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
|
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
"ImportPath": "golang.org/x/net/internal/iana",
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
"ImportPath": "golang.org/x/net/internal/socket",
|
||||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/alecthomas/template",
|
"ImportPath": "golang.org/x/net/ipv4",
|
||||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/alecthomas/units",
|
"ImportPath": "golang.org/x/net/ipv6",
|
||||||
"Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
|
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/alecthomas/template/parse",
|
"ImportPath": "golang.org/x/time/rate",
|
||||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
"Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
|
||||||
|
"Comment": "v2.2.5",
|
||||||
|
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -242,6 +242,8 @@ func initConfig() (err error) {
|
|||||||
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||||
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||||
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||||
|
spsArgs.SSMethod = sps.Hidden().Flag("ss-method", "").Short('h').Default("aes-256-cfb").String()
|
||||||
|
spsArgs.SSKey = sps.Hidden().Flag("ss-key", "").Short('j').Default("sspassword").String()
|
||||||
|
|
||||||
//parse args
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
|
|||||||
@ -232,6 +232,8 @@ type SPSArgs struct {
|
|||||||
ParentKey *string
|
ParentKey *string
|
||||||
LocalCompress *bool
|
LocalCompress *bool
|
||||||
ParentCompress *bool
|
ParentCompress *bool
|
||||||
|
SSMethod *string
|
||||||
|
SSKey *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SPSArgs) Protocol() string {
|
func (a *SPSArgs) Protocol() string {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/snail007/goproxy/utils"
|
"github.com/snail007/goproxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/conncrypt"
|
"github.com/snail007/goproxy/utils/conncrypt"
|
||||||
"github.com/snail007/goproxy/utils/socks"
|
"github.com/snail007/goproxy/utils/socks"
|
||||||
|
"src/github.com/snail007/goproxy/utils/ss"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SPS struct {
|
type SPS struct {
|
||||||
@ -26,6 +27,7 @@ type SPS struct {
|
|||||||
serverChannels []*utils.ServerChannel
|
serverChannels []*utils.ServerChannel
|
||||||
userConns utils.ConcurrentMap
|
userConns utils.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
|
cipher *ss.Cipher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSPS() Service {
|
func NewSPS() Service {
|
||||||
@ -67,6 +69,13 @@ func (s *SPS) InitService() (err error) {
|
|||||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
||||||
}
|
}
|
||||||
err = s.InitBasicAuth()
|
err = s.InitBasicAuth()
|
||||||
|
if *s.cfg.SSMethod != "" && *s.cfg.SSKey != "" {
|
||||||
|
s.cipher, err = ss.NewCipher(*s.cfg.SSMethod, *s.cfg.SSKey)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("error generating cipher : %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *SPS) InitOutConnPool() {
|
func (s *SPS) InitOutConnPool() {
|
||||||
@ -171,39 +180,52 @@ func (s *SPS) callback(inConn net.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||||
buf := make([]byte, 1024)
|
bInConn := utils.NewBufferedConn(*inConn)
|
||||||
n, err := (*inConn).Read(buf)
|
//important
|
||||||
header := buf[:n]
|
//action read will regist read event to system,
|
||||||
|
//when data arrived , system call process
|
||||||
|
//so that we can get buffered bytes count
|
||||||
|
//otherwise Buffered() always return 0
|
||||||
|
bInConn.ReadByte()
|
||||||
|
bInConn.UnreadByte()
|
||||||
|
|
||||||
|
n := 8
|
||||||
|
if n > bInConn.Buffered() {
|
||||||
|
n = bInConn.Buffered()
|
||||||
|
}
|
||||||
|
h, err := bInConn.Peek(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("ERR:%s", err)
|
s.log.Printf("peek error %s ", err)
|
||||||
utils.CloseConn(inConn)
|
(*inConn).Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*inConn = bInConn
|
||||||
address := ""
|
address := ""
|
||||||
var auth socks.Auth
|
var auth socks.Auth
|
||||||
var forwardBytes []byte
|
var forwardBytes []byte
|
||||||
//fmt.Printf("%v", header)
|
//fmt.Printf("%v", header)
|
||||||
if header[0] == socks.VERSION_V5 {
|
if utils.IsSocks5(h) {
|
||||||
//socks5 server
|
//socks5 server
|
||||||
var serverConn *socks.ServerConn
|
var serverConn *socks.ServerConn
|
||||||
if s.IsBasicAuth() {
|
if s.IsBasicAuth() {
|
||||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", header)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", nil)
|
||||||
} else {
|
} else {
|
||||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", header)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", nil)
|
||||||
}
|
}
|
||||||
if err = serverConn.Handshake(); err != nil {
|
if err = serverConn.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
address = serverConn.Target()
|
address = serverConn.Target()
|
||||||
auth = serverConn.AuthData()
|
auth = serverConn.AuthData()
|
||||||
} else if bytes.IndexByte(header, '\n') != -1 {
|
} else if utils.IsHTTP(h) {
|
||||||
//http
|
//http
|
||||||
var request utils.HTTPRequest
|
var request utils.HTTPRequest
|
||||||
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
if s.IsBasicAuth() {
|
if s.IsBasicAuth() {
|
||||||
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, header)
|
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, nil)
|
||||||
} else {
|
} else {
|
||||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, nil)
|
||||||
}
|
}
|
||||||
(*inConn).SetDeadline(time.Time{})
|
(*inConn).SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -211,7 +233,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(header) >= 7 && strings.ToLower(string(header[:7])) == "connect" {
|
if len(h) >= 7 && strings.ToLower(string(h[:7])) == "connect" {
|
||||||
//https
|
//https
|
||||||
request.HTTPSReply()
|
request.HTTPSReply()
|
||||||
//s.log.Printf("https reply: %s", request.Host)
|
//s.log.Printf("https reply: %s", request.Host)
|
||||||
@ -231,7 +253,21 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
//ss
|
||||||
|
ssConn := ss.NewConn(*inConn, s.cipher.Copy())
|
||||||
|
address, err = ss.GetRequest(ssConn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ensure the host does not contain some illegal characters, NUL may panic on Win32
|
||||||
|
if strings.ContainsRune(address, 0x00) {
|
||||||
|
err = errors.New("invalid domain name")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*inConn = ssConn
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(h))
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
err = errors.New("unknown request")
|
err = errors.New("unknown request")
|
||||||
return
|
return
|
||||||
@ -256,7 +292,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
if *s.cfg.ParentServiceType == "http" {
|
if *s.cfg.ParentServiceType == "http" {
|
||||||
//http parent
|
//http parent
|
||||||
pb := new(bytes.Buffer)
|
pb := new(bytes.Buffer)
|
||||||
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address)))
|
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost:%s\r\nProxy-Connection: Keep-Alive\r\n", address, address)))
|
||||||
//Proxy-Authorization:\r\n
|
//Proxy-Authorization:\r\n
|
||||||
u := ""
|
u := ""
|
||||||
if *s.cfg.ParentAuth != "" {
|
if *s.cfg.ParentAuth != "" {
|
||||||
@ -305,12 +341,12 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
err = fmt.Errorf("parent auth data format error")
|
err = fmt.Errorf("parent auth data format error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, header)
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
|
||||||
} else {
|
} else {
|
||||||
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, header)
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
|
||||||
} else {
|
} else {
|
||||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, header)
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = clientConn.Handshake(); err != nil {
|
if err = clientConn.Handshake(); err != nil {
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import (
|
|||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -20,13 +19,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/snail007/goproxy/services/kcpcfg"
|
||||||
|
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/utils/id"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/snail007/goproxy/utils/id"
|
||||||
|
|
||||||
kcp "github.com/xtaci/kcp-go"
|
kcp "github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,7 +70,9 @@ func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interfac
|
|||||||
}
|
}
|
||||||
src.Close()
|
src.Close()
|
||||||
dst.Close()
|
dst.Close()
|
||||||
|
if fn != nil {
|
||||||
fn(err)
|
fn(err)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
|
func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
|
||||||
@ -171,33 +175,6 @@ func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.C
|
|||||||
return NewCompStream(kcpconn), err
|
return NewCompStream(kcpconn), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListenTls(ip string, port int, certBytes, keyBytes, caCertBytes []byte) (ln *net.Listener, err error) {
|
|
||||||
|
|
||||||
var cert tls.Certificate
|
|
||||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clientCertPool := x509.NewCertPool()
|
|
||||||
caBytes := certBytes
|
|
||||||
if caCertBytes != nil {
|
|
||||||
caBytes = caCertBytes
|
|
||||||
}
|
|
||||||
ok := clientCertPool.AppendCertsFromPEM(caBytes)
|
|
||||||
if !ok {
|
|
||||||
err = errors.New("failed to parse root certificate")
|
|
||||||
}
|
|
||||||
config := &tls.Config{
|
|
||||||
ClientCAs: clientCertPool,
|
|
||||||
Certificates: []tls.Certificate{cert},
|
|
||||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
|
||||||
}
|
|
||||||
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
|
|
||||||
if err == nil {
|
|
||||||
ln = &_ln
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func PathExists(_path string) bool {
|
func PathExists(_path string) bool {
|
||||||
_, err := os.Stat(_path)
|
_, err := os.Stat(_path)
|
||||||
if err != nil && os.IsNotExist(err) {
|
if err != nil && os.IsNotExist(err) {
|
||||||
@ -624,6 +601,26 @@ func IsIternalIP(domainOrIP string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
func IsHTTP(head []byte) bool {
|
||||||
|
keys := []string{"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"}
|
||||||
|
for _, key := range keys {
|
||||||
|
if bytes.HasPrefix(head, []byte(key)) || bytes.HasPrefix(head, []byte(strings.ToLower(key))) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func IsSocks5(head []byte) bool {
|
||||||
|
if len(head) < 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if head[0] == uint8(0x05) && 0 < int(head[1]) && int(head[1]) < 255 {
|
||||||
|
if len(head) == 2+int(head[1]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// type sockaddr struct {
|
// type sockaddr struct {
|
||||||
// family uint16
|
// family uint16
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/snail007/goproxy/services/kcpcfg"
|
||||||
|
|
||||||
kcp "github.com/xtaci/kcp-go"
|
kcp "github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,7 +47,7 @@ func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
|||||||
sc.errAcceptHandler = fn
|
sc.errAcceptHandler = fn
|
||||||
}
|
}
|
||||||
func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn func(conn net.Conn)) (err error) {
|
func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn func(conn net.Conn)) (err error) {
|
||||||
sc.Listener, err = ListenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
|
sc.Listener, err = sc.listenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -73,7 +77,33 @@ func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn f
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (sc *ServerChannel) listenTls(ip string, port int, certBytes, keyBytes, caCertBytes []byte) (ln *net.Listener, err error) {
|
||||||
|
|
||||||
|
var cert tls.Certificate
|
||||||
|
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clientCertPool := x509.NewCertPool()
|
||||||
|
caBytes := certBytes
|
||||||
|
if caCertBytes != nil {
|
||||||
|
caBytes = caCertBytes
|
||||||
|
}
|
||||||
|
ok := clientCertPool.AppendCertsFromPEM(caBytes)
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("failed to parse root certificate")
|
||||||
|
}
|
||||||
|
config := &tls.Config{
|
||||||
|
ClientCAs: clientCertPool,
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||||
|
}
|
||||||
|
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
|
||||||
|
if err == nil {
|
||||||
|
ln = &_ln
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
|
func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
|
||||||
var l net.Listener
|
var l net.Listener
|
||||||
l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sc.ip, sc.port))
|
l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sc.ip, sc.port))
|
||||||
|
|||||||
186
utils/ss/conn.go
Normal file
186
utils/ss/conn.go
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
package ss
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OneTimeAuthMask byte = 0x10
|
||||||
|
AddrMask byte = 0xf
|
||||||
|
)
|
||||||
|
|
||||||
|
type Conn struct {
|
||||||
|
net.Conn
|
||||||
|
*Cipher
|
||||||
|
readBuf []byte
|
||||||
|
writeBuf []byte
|
||||||
|
chunkId uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConn(c net.Conn, cipher *Cipher) *Conn {
|
||||||
|
return &Conn{
|
||||||
|
Conn: c,
|
||||||
|
Cipher: cipher,
|
||||||
|
readBuf: leakyBuf.Get(),
|
||||||
|
writeBuf: leakyBuf.Get()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) Close() error {
|
||||||
|
leakyBuf.Put(c.readBuf)
|
||||||
|
leakyBuf.Put(c.writeBuf)
|
||||||
|
return c.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RawAddr(addr string) (buf []byte, err error) {
|
||||||
|
host, portStr, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ss: address error %s %v", addr, err)
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(portStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ss: invalid port %s", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostLen := len(host)
|
||||||
|
l := 1 + 1 + hostLen + 2 // addrType + lenByte + address + port
|
||||||
|
buf = make([]byte, l)
|
||||||
|
buf[0] = 3 // 3 means the address is domain name
|
||||||
|
buf[1] = byte(hostLen) // host address length followed by host address
|
||||||
|
copy(buf[2:], host)
|
||||||
|
binary.BigEndian.PutUint16(buf[2+hostLen:2+hostLen+2], uint16(port))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is intended for use by users implementing a local socks proxy.
|
||||||
|
// rawaddr shoud contain part of the data in socks request, starting from the
|
||||||
|
// ATYP field. (Refer to rfc1928 for more information.)
|
||||||
|
func DialWithRawAddr(rawaddr []byte, server string, cipher *Cipher) (c *Conn, err error) {
|
||||||
|
conn, err := net.Dial("tcp", server)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c = NewConn(conn, cipher)
|
||||||
|
if cipher.ota {
|
||||||
|
if c.enc == nil {
|
||||||
|
if _, err = c.initEncrypt(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// since we have initEncrypt, we must send iv manually
|
||||||
|
conn.Write(cipher.iv)
|
||||||
|
rawaddr[0] |= OneTimeAuthMask
|
||||||
|
rawaddr = otaConnectAuth(cipher.iv, cipher.key, rawaddr)
|
||||||
|
}
|
||||||
|
if _, err = c.write(rawaddr); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// addr should be in the form of host:port
|
||||||
|
func Dial(addr, server string, cipher *Cipher) (c *Conn, err error) {
|
||||||
|
ra, err := RawAddr(addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return DialWithRawAddr(ra, server, cipher)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) GetIv() (iv []byte) {
|
||||||
|
iv = make([]byte, len(c.iv))
|
||||||
|
copy(iv, c.iv)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) GetKey() (key []byte) {
|
||||||
|
key = make([]byte, len(c.key))
|
||||||
|
copy(key, c.key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) IsOta() bool {
|
||||||
|
return c.ota
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) GetAndIncrChunkId() (chunkId uint32) {
|
||||||
|
chunkId = c.chunkId
|
||||||
|
c.chunkId += 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) Read(b []byte) (n int, err error) {
|
||||||
|
if c.dec == nil {
|
||||||
|
iv := make([]byte, c.info.ivLen)
|
||||||
|
if _, err = io.ReadFull(c.Conn, iv); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = c.initDecrypt(iv); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(c.iv) == 0 {
|
||||||
|
c.iv = iv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cipherData := c.readBuf
|
||||||
|
if len(b) > len(cipherData) {
|
||||||
|
cipherData = make([]byte, len(b))
|
||||||
|
} else {
|
||||||
|
cipherData = cipherData[:len(b)]
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = c.Conn.Read(cipherData)
|
||||||
|
if n > 0 {
|
||||||
|
c.decrypt(b[0:n], cipherData[0:n])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) Write(b []byte) (n int, err error) {
|
||||||
|
nn := len(b)
|
||||||
|
if c.ota {
|
||||||
|
chunkId := c.GetAndIncrChunkId()
|
||||||
|
b = otaReqChunkAuth(c.iv, chunkId, b)
|
||||||
|
}
|
||||||
|
headerLen := len(b) - nn
|
||||||
|
|
||||||
|
n, err = c.write(b)
|
||||||
|
// Make sure <= 0 <= len(b), where b is the slice passed in.
|
||||||
|
if n >= headerLen {
|
||||||
|
n -= headerLen
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) write(b []byte) (n int, err error) {
|
||||||
|
var iv []byte
|
||||||
|
if c.enc == nil {
|
||||||
|
iv, err = c.initEncrypt()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cipherData := c.writeBuf
|
||||||
|
dataSize := len(b) + len(iv)
|
||||||
|
if dataSize > len(cipherData) {
|
||||||
|
cipherData = make([]byte, dataSize)
|
||||||
|
} else {
|
||||||
|
cipherData = cipherData[:dataSize]
|
||||||
|
}
|
||||||
|
|
||||||
|
if iv != nil {
|
||||||
|
// Put initialization vector in buffer, do a single write to send both
|
||||||
|
// iv and data.
|
||||||
|
copy(cipherData, iv)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.encrypt(cipherData[len(iv):], b)
|
||||||
|
n, err = c.Conn.Write(cipherData)
|
||||||
|
return
|
||||||
|
}
|
||||||
274
utils/ss/encrypt.go
Normal file
274
utils/ss/encrypt.go
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
package ss
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rc4"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Yawning/chacha20"
|
||||||
|
"golang.org/x/crypto/blowfish"
|
||||||
|
"golang.org/x/crypto/cast5"
|
||||||
|
"golang.org/x/crypto/salsa20/salsa"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errEmptyPassword = errors.New("empty key")
|
||||||
|
|
||||||
|
func md5sum(d []byte) []byte {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(d)
|
||||||
|
return h.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func evpBytesToKey(password string, keyLen int) (key []byte) {
|
||||||
|
const md5Len = 16
|
||||||
|
|
||||||
|
cnt := (keyLen-1)/md5Len + 1
|
||||||
|
m := make([]byte, cnt*md5Len)
|
||||||
|
copy(m, md5sum([]byte(password)))
|
||||||
|
|
||||||
|
// Repeatedly call md5 until bytes generated is enough.
|
||||||
|
// Each call to md5 uses data: prev md5 sum + password.
|
||||||
|
d := make([]byte, md5Len+len(password))
|
||||||
|
start := 0
|
||||||
|
for i := 1; i < cnt; i++ {
|
||||||
|
start += md5Len
|
||||||
|
copy(d, m[start-md5Len:start])
|
||||||
|
copy(d[md5Len:], password)
|
||||||
|
copy(m[start:], md5sum(d))
|
||||||
|
}
|
||||||
|
return m[:keyLen]
|
||||||
|
}
|
||||||
|
|
||||||
|
type DecOrEnc int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Decrypt DecOrEnc = iota
|
||||||
|
Encrypt
|
||||||
|
)
|
||||||
|
|
||||||
|
func newStream(block cipher.Block, err error, key, iv []byte,
|
||||||
|
doe DecOrEnc) (cipher.Stream, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if doe == Encrypt {
|
||||||
|
return cipher.NewCFBEncrypter(block, iv), nil
|
||||||
|
} else {
|
||||||
|
return cipher.NewCFBDecrypter(block, iv), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAESCFBStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
return newStream(block, err, key, iv, doe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAESCTRStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cipher.NewCTR(block, iv), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDESStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||||
|
block, err := des.NewCipher(key)
|
||||||
|
return newStream(block, err, key, iv, doe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBlowFishStream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||||
|
block, err := blowfish.NewCipher(key)
|
||||||
|
return newStream(block, err, key, iv, doe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCast5Stream(key, iv []byte, doe DecOrEnc) (cipher.Stream, error) {
|
||||||
|
block, err := cast5.NewCipher(key)
|
||||||
|
return newStream(block, err, key, iv, doe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRC4MD5Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(key)
|
||||||
|
h.Write(iv)
|
||||||
|
rc4key := h.Sum(nil)
|
||||||
|
|
||||||
|
return rc4.NewCipher(rc4key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChaCha20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||||
|
return chacha20.NewCipher(key, iv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChaCha20IETFStream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||||
|
return chacha20.NewCipher(key, iv)
|
||||||
|
}
|
||||||
|
|
||||||
|
type salsaStreamCipher struct {
|
||||||
|
nonce [8]byte
|
||||||
|
key [32]byte
|
||||||
|
counter int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *salsaStreamCipher) XORKeyStream(dst, src []byte) {
|
||||||
|
var buf []byte
|
||||||
|
padLen := c.counter % 64
|
||||||
|
dataSize := len(src) + padLen
|
||||||
|
if cap(dst) >= dataSize {
|
||||||
|
buf = dst[:dataSize]
|
||||||
|
} else if leakyBufSize >= dataSize {
|
||||||
|
buf = leakyBuf.Get()
|
||||||
|
defer leakyBuf.Put(buf)
|
||||||
|
buf = buf[:dataSize]
|
||||||
|
} else {
|
||||||
|
buf = make([]byte, dataSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
var subNonce [16]byte
|
||||||
|
copy(subNonce[:], c.nonce[:])
|
||||||
|
binary.LittleEndian.PutUint64(subNonce[len(c.nonce):], uint64(c.counter/64))
|
||||||
|
|
||||||
|
// It's difficult to avoid data copy here. src or dst maybe slice from
|
||||||
|
// Conn.Read/Write, which can't have padding.
|
||||||
|
copy(buf[padLen:], src[:])
|
||||||
|
salsa.XORKeyStream(buf, buf, &subNonce, &c.key)
|
||||||
|
copy(dst, buf[padLen:])
|
||||||
|
|
||||||
|
c.counter += len(src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSalsa20Stream(key, iv []byte, _ DecOrEnc) (cipher.Stream, error) {
|
||||||
|
var c salsaStreamCipher
|
||||||
|
copy(c.nonce[:], iv[:8])
|
||||||
|
copy(c.key[:], key[:32])
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type cipherInfo struct {
|
||||||
|
keyLen int
|
||||||
|
ivLen int
|
||||||
|
newStream func(key, iv []byte, doe DecOrEnc) (cipher.Stream, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cipherMethod = map[string]*cipherInfo{
|
||||||
|
"aes-128-cfb": {16, 16, newAESCFBStream},
|
||||||
|
"aes-192-cfb": {24, 16, newAESCFBStream},
|
||||||
|
"aes-256-cfb": {32, 16, newAESCFBStream},
|
||||||
|
"aes-128-ctr": {16, 16, newAESCTRStream},
|
||||||
|
"aes-192-ctr": {24, 16, newAESCTRStream},
|
||||||
|
"aes-256-ctr": {32, 16, newAESCTRStream},
|
||||||
|
"des-cfb": {8, 8, newDESStream},
|
||||||
|
"bf-cfb": {16, 8, newBlowFishStream},
|
||||||
|
"cast5-cfb": {16, 8, newCast5Stream},
|
||||||
|
"rc4-md5": {16, 16, newRC4MD5Stream},
|
||||||
|
"rc4-md5-6": {16, 6, newRC4MD5Stream},
|
||||||
|
"chacha20": {32, 8, newChaCha20Stream},
|
||||||
|
"chacha20-ietf": {32, 12, newChaCha20IETFStream},
|
||||||
|
"salsa20": {32, 8, newSalsa20Stream},
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckCipherMethod(method string) error {
|
||||||
|
if method == "" {
|
||||||
|
method = "aes-256-cfb"
|
||||||
|
}
|
||||||
|
_, ok := cipherMethod[method]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("Unsupported encryption method: " + method)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cipher struct {
|
||||||
|
enc cipher.Stream
|
||||||
|
dec cipher.Stream
|
||||||
|
key []byte
|
||||||
|
info *cipherInfo
|
||||||
|
ota bool // one-time auth
|
||||||
|
iv []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCipher creates a cipher that can be used in Dial() etc.
|
||||||
|
// Use cipher.Copy() to create a new cipher with the same method and password
|
||||||
|
// to avoid the cost of repeated cipher initialization.
|
||||||
|
func NewCipher(method, password string) (c *Cipher, err error) {
|
||||||
|
if password == "" {
|
||||||
|
return nil, errEmptyPassword
|
||||||
|
}
|
||||||
|
var ota bool
|
||||||
|
if strings.HasSuffix(strings.ToLower(method), "-auth") {
|
||||||
|
method = method[:len(method)-5] // len("-auth") = 5
|
||||||
|
ota = true
|
||||||
|
} else {
|
||||||
|
ota = false
|
||||||
|
}
|
||||||
|
mi, ok := cipherMethod[method]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("Unsupported encryption method: " + method)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := evpBytesToKey(password, mi.keyLen)
|
||||||
|
|
||||||
|
c = &Cipher{key: key, info: mi}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.ota = ota
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes the block cipher with CFB mode, returns IV.
|
||||||
|
func (c *Cipher) initEncrypt() (iv []byte, err error) {
|
||||||
|
if c.iv == nil {
|
||||||
|
iv = make([]byte, c.info.ivLen)
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.iv = iv
|
||||||
|
} else {
|
||||||
|
iv = c.iv
|
||||||
|
}
|
||||||
|
c.enc, err = c.info.newStream(c.key, iv, Encrypt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cipher) initDecrypt(iv []byte) (err error) {
|
||||||
|
c.dec, err = c.info.newStream(c.key, iv, Decrypt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cipher) encrypt(dst, src []byte) {
|
||||||
|
c.enc.XORKeyStream(dst, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cipher) decrypt(dst, src []byte) {
|
||||||
|
c.dec.XORKeyStream(dst, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a new cipher at it's initial state.
|
||||||
|
func (c *Cipher) Copy() *Cipher {
|
||||||
|
// This optimization maybe not necessary. But without this function, we
|
||||||
|
// need to maintain a table cache for newTableCipher and use lock to
|
||||||
|
// protect concurrent access to that cache.
|
||||||
|
|
||||||
|
// AES and DES ciphers does not return specific types, so it's difficult
|
||||||
|
// to create copy. But their initizliation time is less than 4000ns on my
|
||||||
|
// 2.26 GHz Intel Core 2 Duo processor. So no need to worry.
|
||||||
|
|
||||||
|
// Currently, blow-fish and cast5 initialization cost is an order of
|
||||||
|
// maganitude slower than other ciphers. (I'm not sure whether this is
|
||||||
|
// because the current implementation is not highly optimized, or this is
|
||||||
|
// the nature of the algorithm.)
|
||||||
|
|
||||||
|
nc := *c
|
||||||
|
nc.enc = nil
|
||||||
|
nc.dec = nil
|
||||||
|
nc.ota = c.ota
|
||||||
|
return &nc
|
||||||
|
}
|
||||||
45
utils/ss/leakybuf.go
Normal file
45
utils/ss/leakybuf.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Provides leaky buffer, based on the example in Effective Go.
|
||||||
|
package ss
|
||||||
|
|
||||||
|
type LeakyBuf struct {
|
||||||
|
bufSize int // size of each buffer
|
||||||
|
freeList chan []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
const leakyBufSize = 4108 // data.len(2) + hmacsha1(10) + data(4096)
|
||||||
|
const maxNBuf = 2048
|
||||||
|
|
||||||
|
var leakyBuf = NewLeakyBuf(maxNBuf, leakyBufSize)
|
||||||
|
|
||||||
|
// NewLeakyBuf creates a leaky buffer which can hold at most n buffer, each
|
||||||
|
// with bufSize bytes.
|
||||||
|
func NewLeakyBuf(n, bufSize int) *LeakyBuf {
|
||||||
|
return &LeakyBuf{
|
||||||
|
bufSize: bufSize,
|
||||||
|
freeList: make(chan []byte, n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a buffer from the leaky buffer or create a new buffer.
|
||||||
|
func (lb *LeakyBuf) Get() (b []byte) {
|
||||||
|
select {
|
||||||
|
case b = <-lb.freeList:
|
||||||
|
default:
|
||||||
|
b = make([]byte, lb.bufSize)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put add the buffer into the free buffer pool for reuse. Panic if the buffer
|
||||||
|
// size is not the same with the leaky buffer's. This is intended to expose
|
||||||
|
// error usage of leaky buffer.
|
||||||
|
func (lb *LeakyBuf) Put(b []byte) {
|
||||||
|
if len(b) != lb.bufSize {
|
||||||
|
panic("invalid buffer size that's put into leaky buffer")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case lb.freeList <- b:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
105
utils/ss/pipe.go
Normal file
105
utils/ss/pipe.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package ss
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetReadTimeout(c net.Conn) {
|
||||||
|
c.SetReadDeadline(time.Now().Add(time.Second * 5))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipeThenClose copies data from src to dst, closes dst when done.
|
||||||
|
func PipeThenClose(src, dst net.Conn, addFlow func(int)) {
|
||||||
|
defer dst.Close()
|
||||||
|
buf := leakyBuf.Get()
|
||||||
|
defer leakyBuf.Put(buf)
|
||||||
|
for {
|
||||||
|
SetReadTimeout(src)
|
||||||
|
n, err := src.Read(buf)
|
||||||
|
if addFlow != nil {
|
||||||
|
addFlow(n)
|
||||||
|
}
|
||||||
|
// read may return EOF with n > 0
|
||||||
|
// should always process n > 0 bytes before handling error
|
||||||
|
if n > 0 {
|
||||||
|
// Note: avoid overwrite err returned by Read.
|
||||||
|
if _, err := dst.Write(buf[0:n]); err != nil {
|
||||||
|
log.Println("write:", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// Always "use of closed network connection", but no easy way to
|
||||||
|
// identify this specific error. So just leave the error along for now.
|
||||||
|
// More info here: https://code.google.com/p/go/issues/detail?id=4373
|
||||||
|
/*
|
||||||
|
if bool(log.) && err != io.EOF {
|
||||||
|
log.Println("read:", err)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipeThenClose copies data from src to dst, closes dst when done, with ota verification.
|
||||||
|
func PipeThenCloseOta(src *Conn, dst net.Conn, addFlow func(int)) {
|
||||||
|
const (
|
||||||
|
dataLenLen = 2
|
||||||
|
hmacSha1Len = 10
|
||||||
|
idxData0 = dataLenLen + hmacSha1Len
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
dst.Close()
|
||||||
|
}()
|
||||||
|
// sometimes it have to fill large block
|
||||||
|
buf := leakyBuf.Get()
|
||||||
|
defer leakyBuf.Put(buf)
|
||||||
|
for i := 1; ; i += 1 {
|
||||||
|
SetReadTimeout(src)
|
||||||
|
if n, err := io.ReadFull(src, buf[:dataLenLen+hmacSha1Len]); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Printf("conn=%p #%v read header error n=%v: %v", src, i, n, err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
dataLen := binary.BigEndian.Uint16(buf[:dataLenLen])
|
||||||
|
expectedHmacSha1 := buf[dataLenLen:idxData0]
|
||||||
|
|
||||||
|
var dataBuf []byte
|
||||||
|
if len(buf) < int(idxData0+dataLen) {
|
||||||
|
dataBuf = make([]byte, dataLen)
|
||||||
|
} else {
|
||||||
|
dataBuf = buf[idxData0 : idxData0+dataLen]
|
||||||
|
}
|
||||||
|
if n, err := io.ReadFull(src, dataBuf); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Printf("conn=%p #%v read data error n=%v: %v", src, i, n, err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
addFlow(int(dataLen))
|
||||||
|
chunkIdBytes := make([]byte, 4)
|
||||||
|
chunkId := src.GetAndIncrChunkId()
|
||||||
|
binary.BigEndian.PutUint32(chunkIdBytes, chunkId)
|
||||||
|
actualHmacSha1 := HmacSha1(append(src.GetIv(), chunkIdBytes...), dataBuf)
|
||||||
|
if !bytes.Equal(expectedHmacSha1, actualHmacSha1) {
|
||||||
|
log.Printf("conn=%p #%v read data hmac-sha1 mismatch, iv=%v chunkId=%v src=%v dst=%v len=%v expeced=%v actual=%v", src, i, src.GetIv(), chunkId, src.RemoteAddr(), dst.RemoteAddr(), dataLen, expectedHmacSha1, actualHmacSha1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if n, err := dst.Write(dataBuf); err != nil {
|
||||||
|
log.Printf("conn=%p #%v write data error n=%v: %v", dst, i, n, err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
124
utils/ss/util.go
Normal file
124
utils/ss/util.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package ss
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsFileExists(path string) (bool, error) {
|
||||||
|
stat, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
if stat.Mode()&os.ModeType == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, errors.New(path + " exists but is not regular file")
|
||||||
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func HmacSha1(key []byte, data []byte) []byte {
|
||||||
|
hmacSha1 := hmac.New(sha1.New, key)
|
||||||
|
hmacSha1.Write(data)
|
||||||
|
return hmacSha1.Sum(nil)[:10]
|
||||||
|
}
|
||||||
|
|
||||||
|
func otaConnectAuth(iv, key, data []byte) []byte {
|
||||||
|
return append(data, HmacSha1(append(iv, key...), data)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func otaReqChunkAuth(iv []byte, chunkId uint32, data []byte) []byte {
|
||||||
|
nb := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(nb, uint16(len(data)))
|
||||||
|
chunkIdBytes := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(chunkIdBytes, chunkId)
|
||||||
|
header := append(nb, HmacSha1(append(iv, chunkIdBytes...), data)...)
|
||||||
|
return append(header, data...)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
idType = 0 // address type index
|
||||||
|
idIP0 = 1 // ip addres start index
|
||||||
|
idDmLen = 1 // domain address length index
|
||||||
|
idDm0 = 2 // domain address start index
|
||||||
|
|
||||||
|
typeIPv4 = 1 // type is ipv4 address
|
||||||
|
typeDm = 3 // type is domain address
|
||||||
|
typeIPv6 = 4 // type is ipv6 address
|
||||||
|
|
||||||
|
lenIPv4 = net.IPv4len + 2 // ipv4 + 2port
|
||||||
|
lenIPv6 = net.IPv6len + 2 // ipv6 + 2port
|
||||||
|
lenDmBase = 2 // 1addrLen + 2port, plus addrLen
|
||||||
|
lenHmacSha1 = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetRequest(conn *Conn) (host string, err error) {
|
||||||
|
|
||||||
|
// buf size should at least have the same size with the largest possible
|
||||||
|
// request size (when addrType is 3, domain name has at most 256 bytes)
|
||||||
|
// 1(addrType) + 1(lenByte) + 255(max length address) + 2(port) + 10(hmac-sha1)
|
||||||
|
buf := make([]byte, 269)
|
||||||
|
// read till we get possible domain length field
|
||||||
|
if _, err = io.ReadFull(conn, buf[:idType+1]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var reqStart, reqEnd int
|
||||||
|
addrType := buf[idType]
|
||||||
|
switch addrType & AddrMask {
|
||||||
|
case typeIPv4:
|
||||||
|
reqStart, reqEnd = idIP0, idIP0+lenIPv4
|
||||||
|
case typeIPv6:
|
||||||
|
reqStart, reqEnd = idIP0, idIP0+lenIPv6
|
||||||
|
case typeDm:
|
||||||
|
if _, err = io.ReadFull(conn, buf[idType+1:idDmLen+1]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reqStart, reqEnd = idDm0, idDm0+int(buf[idDmLen])+lenDmBase
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("addr type %d not supported", addrType&AddrMask)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = io.ReadFull(conn, buf[reqStart:reqEnd]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return string for typeIP is not most efficient, but browsers (Chrome,
|
||||||
|
// Safari, Firefox) all seems using typeDm exclusively. So this is not a
|
||||||
|
// big problem.
|
||||||
|
switch addrType & AddrMask {
|
||||||
|
case typeIPv4:
|
||||||
|
host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String()
|
||||||
|
case typeIPv6:
|
||||||
|
host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String()
|
||||||
|
case typeDm:
|
||||||
|
host = string(buf[idDm0 : idDm0+int(buf[idDmLen])])
|
||||||
|
}
|
||||||
|
// parse port
|
||||||
|
port := binary.BigEndian.Uint16(buf[reqEnd-2 : reqEnd])
|
||||||
|
host = net.JoinHostPort(host, strconv.Itoa(int(port)))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClosedFlag struct {
|
||||||
|
flag bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flag *ClosedFlag) SetClosed() {
|
||||||
|
flag.flag = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flag *ClosedFlag) IsClosed() bool {
|
||||||
|
return flag.flag
|
||||||
|
}
|
||||||
@ -1,13 +1,12 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
|
||||||
"github.com/snail007/goproxy/utils/sni"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -17,6 +16,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/snail007/goproxy/services/kcpcfg"
|
||||||
|
"github.com/snail007/goproxy/utils/sni"
|
||||||
|
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
@ -792,3 +794,33 @@ func (c *CompStream) SetReadDeadline(t time.Time) error {
|
|||||||
func (c *CompStream) SetWriteDeadline(t time.Time) error {
|
func (c *CompStream) SetWriteDeadline(t time.Time) error {
|
||||||
return c.conn.SetWriteDeadline(t)
|
return c.conn.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BufferedConn struct {
|
||||||
|
r *bufio.Reader
|
||||||
|
net.Conn // So that most methods are embedded
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBufferedConn(c net.Conn) BufferedConn {
|
||||||
|
return BufferedConn{bufio.NewReader(c), c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBufferedConnSize(c net.Conn, n int) BufferedConn {
|
||||||
|
return BufferedConn{bufio.NewReaderSize(c, n), c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BufferedConn) Peek(n int) ([]byte, error) {
|
||||||
|
return b.r.Peek(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BufferedConn) Read(p []byte) (int, error) {
|
||||||
|
return b.r.Read(p)
|
||||||
|
}
|
||||||
|
func (b BufferedConn) ReadByte() (byte, error) {
|
||||||
|
return b.r.ReadByte()
|
||||||
|
}
|
||||||
|
func (b BufferedConn) UnreadByte() error {
|
||||||
|
return b.r.UnreadByte()
|
||||||
|
}
|
||||||
|
func (b BufferedConn) Buffered() int {
|
||||||
|
return b.r.Buffered()
|
||||||
|
}
|
||||||
|
|||||||
122
vendor/github.com/Yawning/chacha20/LICENSE
generated
vendored
Normal file
122
vendor/github.com/Yawning/chacha20/LICENSE
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
CC0 1.0 Universal
|
||||||
|
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||||
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||||
|
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||||
|
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||||
|
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||||
|
HEREUNDER.
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer
|
||||||
|
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||||
|
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||||
|
authorship and/or a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for
|
||||||
|
the purpose of contributing to a commons of creative, cultural and
|
||||||
|
scientific works ("Commons") that the public can reliably and without fear
|
||||||
|
of later claims of infringement build upon, modify, incorporate in other
|
||||||
|
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||||
|
and for any purposes, including without limitation commercial purposes.
|
||||||
|
These owners may contribute to the Commons to promote the ideal of a free
|
||||||
|
culture and the further production of creative, cultural and scientific
|
||||||
|
works, or to gain reputation or greater distribution for their Work in
|
||||||
|
part through the use and efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any
|
||||||
|
expectation of additional consideration or compensation, the person
|
||||||
|
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||||
|
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||||
|
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||||
|
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||||
|
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||||
|
protected by copyright and related or neighboring rights ("Copyright and
|
||||||
|
Related Rights"). Copyright and Related Rights include, but are not
|
||||||
|
limited to, the following:
|
||||||
|
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display,
|
||||||
|
communicate, and translate a Work;
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or
|
||||||
|
likeness depicted in a Work;
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work,
|
||||||
|
subject to the limitations in paragraph 4(a), below;
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||||
|
in a Work;
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
|
European Parliament and of the Council of 11 March 1996 on the legal
|
||||||
|
protection of databases, and under any national implementation
|
||||||
|
thereof, including any amended or successor version of such
|
||||||
|
directive); and
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the
|
||||||
|
world based on applicable law or treaty, and any national
|
||||||
|
implementations thereof.
|
||||||
|
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||||
|
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||||
|
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||||
|
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||||
|
of action, whether now known or unknown (including existing as well as
|
||||||
|
future claims and causes of action), in the Work (i) in all territories
|
||||||
|
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||||
|
treaty (including future time extensions), (iii) in any current or future
|
||||||
|
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||||
|
including without limitation commercial, advertising or promotional
|
||||||
|
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||||
|
member of the public at large and to the detriment of Affirmer's heirs and
|
||||||
|
successors, fully intending that such Waiver shall not be subject to
|
||||||
|
revocation, rescission, cancellation, termination, or any other legal or
|
||||||
|
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||||
|
as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||||
|
be judged legally invalid or ineffective under applicable law, then the
|
||||||
|
Waiver shall be preserved to the maximum extent permitted taking into
|
||||||
|
account Affirmer's express Statement of Purpose. In addition, to the
|
||||||
|
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||||
|
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||||
|
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||||
|
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||||
|
maximum duration provided by applicable law or treaty (including future
|
||||||
|
time extensions), (iii) in any current or future medium and for any number
|
||||||
|
of copies, and (iv) for any purpose whatsoever, including without
|
||||||
|
limitation commercial, advertising or promotional purposes (the
|
||||||
|
"License"). The License shall be deemed effective as of the date CC0 was
|
||||||
|
applied by Affirmer to the Work. Should any part of the License for any
|
||||||
|
reason be judged legally invalid or ineffective under applicable law, such
|
||||||
|
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||||
|
of the License, and in such case Affirmer hereby affirms that he or she
|
||||||
|
will not (i) exercise any of his or her remaining Copyright and Related
|
||||||
|
Rights in the Work or (ii) assert any associated claims and causes of
|
||||||
|
action with respect to the Work, in either case contrary to Affirmer's
|
||||||
|
express Statement of Purpose.
|
||||||
|
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||||
|
surrendered, licensed or otherwise affected by this document.
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or
|
||||||
|
warranties of any kind concerning the Work, express, implied,
|
||||||
|
statutory or otherwise, including without limitation warranties of
|
||||||
|
title, merchantability, fitness for a particular purpose, non
|
||||||
|
infringement, or the absence of latent or other defects, accuracy, or
|
||||||
|
the present or absence of errors, whether or not discoverable, all to
|
||||||
|
the greatest extent permissible under applicable law.
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
|
that may apply to the Work or any use thereof, including without
|
||||||
|
limitation any person's Copyright and Related Rights in the Work.
|
||||||
|
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||||
|
consents, permissions or other rights required for any use of the
|
||||||
|
Work.
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||||
|
party to this document and has no duty or obligation with respect to
|
||||||
|
this CC0 or use of the Work.
|
||||||
|
|
||||||
14
vendor/github.com/Yawning/chacha20/README.md
generated
vendored
Normal file
14
vendor/github.com/Yawning/chacha20/README.md
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
### chacha20 - ChaCha20
|
||||||
|
#### Yawning Angel (yawning at schwanenlied dot me)
|
||||||
|
|
||||||
|
Yet another Go ChaCha20 implementation. Everything else I found was slow,
|
||||||
|
didn't support all the variants I need to use, or relied on cgo to go fast.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
* 20 round, 256 bit key only. Everything else is pointless and stupid.
|
||||||
|
* IETF 96 bit nonce variant.
|
||||||
|
* XChaCha 24 byte nonce variant.
|
||||||
|
* SSE2 and AVX2 support on amd64 targets.
|
||||||
|
* Incremental encrypt/decrypt support, unlike golang.org/x/crypto/salsa20.
|
||||||
|
|
||||||
273
vendor/github.com/Yawning/chacha20/chacha20.go
generated
vendored
Normal file
273
vendor/github.com/Yawning/chacha20/chacha20.go
generated
vendored
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
// chacha20.go - A ChaCha stream cipher implementation.
|
||||||
|
//
|
||||||
|
// To the extent possible under law, Yawning Angel has waived all copyright
|
||||||
|
// and related or neighboring rights to chacha20, using the Creative
|
||||||
|
// Commons "CC0" public domain dedication. See LICENSE or
|
||||||
|
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
|
||||||
|
package chacha20
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/cipher"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// KeySize is the ChaCha20 key size in bytes.
|
||||||
|
KeySize = 32
|
||||||
|
|
||||||
|
// NonceSize is the ChaCha20 nonce size in bytes.
|
||||||
|
NonceSize = 8
|
||||||
|
|
||||||
|
// INonceSize is the IETF ChaCha20 nonce size in bytes.
|
||||||
|
INonceSize = 12
|
||||||
|
|
||||||
|
// XNonceSize is the XChaCha20 nonce size in bytes.
|
||||||
|
XNonceSize = 24
|
||||||
|
|
||||||
|
// HNonceSize is the HChaCha20 nonce size in bytes.
|
||||||
|
HNonceSize = 16
|
||||||
|
|
||||||
|
// BlockSize is the ChaCha20 block size in bytes.
|
||||||
|
BlockSize = 64
|
||||||
|
|
||||||
|
stateSize = 16
|
||||||
|
chachaRounds = 20
|
||||||
|
|
||||||
|
// The constant "expand 32-byte k" as little endian uint32s.
|
||||||
|
sigma0 = uint32(0x61707865)
|
||||||
|
sigma1 = uint32(0x3320646e)
|
||||||
|
sigma2 = uint32(0x79622d32)
|
||||||
|
sigma3 = uint32(0x6b206574)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrInvalidKey is the error returned when the key is invalid.
|
||||||
|
ErrInvalidKey = errors.New("key length must be KeySize bytes")
|
||||||
|
|
||||||
|
// ErrInvalidNonce is the error returned when the nonce is invalid.
|
||||||
|
ErrInvalidNonce = errors.New("nonce length must be NonceSize/INonceSize/XNonceSize bytes")
|
||||||
|
|
||||||
|
// ErrInvalidCounter is the error returned when the counter is invalid.
|
||||||
|
ErrInvalidCounter = errors.New("block counter is invalid (out of range)")
|
||||||
|
|
||||||
|
useUnsafe = false
|
||||||
|
usingVectors = false
|
||||||
|
blocksFn = blocksRef
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Cipher is an instance of ChaCha20/XChaCha20 using a particular key and
|
||||||
|
// nonce.
|
||||||
|
type Cipher struct {
|
||||||
|
state [stateSize]uint32
|
||||||
|
|
||||||
|
buf [BlockSize]byte
|
||||||
|
off int
|
||||||
|
ietf bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset zeros the key data so that it will no longer appear in the process's
|
||||||
|
// memory.
|
||||||
|
func (c *Cipher) Reset() {
|
||||||
|
for i := range c.state {
|
||||||
|
c.state[i] = 0
|
||||||
|
}
|
||||||
|
for i := range c.buf {
|
||||||
|
c.buf[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XORKeyStream sets dst to the result of XORing src with the key stream. Dst
|
||||||
|
// and src may be the same slice but otherwise should not overlap.
|
||||||
|
func (c *Cipher) XORKeyStream(dst, src []byte) {
|
||||||
|
if len(dst) < len(src) {
|
||||||
|
src = src[:len(dst)]
|
||||||
|
}
|
||||||
|
|
||||||
|
for remaining := len(src); remaining > 0; {
|
||||||
|
// Process multiple blocks at once.
|
||||||
|
if c.off == BlockSize {
|
||||||
|
nrBlocks := remaining / BlockSize
|
||||||
|
directBytes := nrBlocks * BlockSize
|
||||||
|
if nrBlocks > 0 {
|
||||||
|
blocksFn(&c.state, src, dst, nrBlocks, c.ietf)
|
||||||
|
remaining -= directBytes
|
||||||
|
if remaining == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst = dst[directBytes:]
|
||||||
|
src = src[directBytes:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's a partial block, generate 1 block of keystream into
|
||||||
|
// the internal buffer.
|
||||||
|
blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
|
||||||
|
c.off = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process partial blocks from the buffered keystream.
|
||||||
|
toXor := BlockSize - c.off
|
||||||
|
if remaining < toXor {
|
||||||
|
toXor = remaining
|
||||||
|
}
|
||||||
|
if toXor > 0 {
|
||||||
|
for i, v := range src[:toXor] {
|
||||||
|
dst[i] = v ^ c.buf[c.off+i]
|
||||||
|
}
|
||||||
|
dst = dst[toXor:]
|
||||||
|
src = src[toXor:]
|
||||||
|
|
||||||
|
remaining -= toXor
|
||||||
|
c.off += toXor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyStream sets dst to the raw keystream.
|
||||||
|
func (c *Cipher) KeyStream(dst []byte) {
|
||||||
|
for remaining := len(dst); remaining > 0; {
|
||||||
|
// Process multiple blocks at once.
|
||||||
|
if c.off == BlockSize {
|
||||||
|
nrBlocks := remaining / BlockSize
|
||||||
|
directBytes := nrBlocks * BlockSize
|
||||||
|
if nrBlocks > 0 {
|
||||||
|
blocksFn(&c.state, nil, dst, nrBlocks, c.ietf)
|
||||||
|
remaining -= directBytes
|
||||||
|
if remaining == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst = dst[directBytes:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's a partial block, generate 1 block of keystream into
|
||||||
|
// the internal buffer.
|
||||||
|
blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
|
||||||
|
c.off = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process partial blocks from the buffered keystream.
|
||||||
|
toCopy := BlockSize - c.off
|
||||||
|
if remaining < toCopy {
|
||||||
|
toCopy = remaining
|
||||||
|
}
|
||||||
|
if toCopy > 0 {
|
||||||
|
copy(dst[:toCopy], c.buf[c.off:c.off+toCopy])
|
||||||
|
dst = dst[toCopy:]
|
||||||
|
remaining -= toCopy
|
||||||
|
c.off += toCopy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReKey reinitializes the ChaCha20/XChaCha20 instance with the provided key
|
||||||
|
// and nonce.
|
||||||
|
func (c *Cipher) ReKey(key, nonce []byte) error {
|
||||||
|
if len(key) != KeySize {
|
||||||
|
return ErrInvalidKey
|
||||||
|
}
|
||||||
|
|
||||||
|
switch len(nonce) {
|
||||||
|
case NonceSize:
|
||||||
|
case INonceSize:
|
||||||
|
case XNonceSize:
|
||||||
|
var subkey [KeySize]byte
|
||||||
|
var subnonce [HNonceSize]byte
|
||||||
|
copy(subnonce[:], nonce[0:16])
|
||||||
|
HChaCha(key, &subnonce, &subkey)
|
||||||
|
key = subkey[:]
|
||||||
|
nonce = nonce[16:24]
|
||||||
|
defer func() {
|
||||||
|
for i := range subkey {
|
||||||
|
subkey[i] = 0
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
default:
|
||||||
|
return ErrInvalidNonce
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Reset()
|
||||||
|
c.state[0] = sigma0
|
||||||
|
c.state[1] = sigma1
|
||||||
|
c.state[2] = sigma2
|
||||||
|
c.state[3] = sigma3
|
||||||
|
c.state[4] = binary.LittleEndian.Uint32(key[0:4])
|
||||||
|
c.state[5] = binary.LittleEndian.Uint32(key[4:8])
|
||||||
|
c.state[6] = binary.LittleEndian.Uint32(key[8:12])
|
||||||
|
c.state[7] = binary.LittleEndian.Uint32(key[12:16])
|
||||||
|
c.state[8] = binary.LittleEndian.Uint32(key[16:20])
|
||||||
|
c.state[9] = binary.LittleEndian.Uint32(key[20:24])
|
||||||
|
c.state[10] = binary.LittleEndian.Uint32(key[24:28])
|
||||||
|
c.state[11] = binary.LittleEndian.Uint32(key[28:32])
|
||||||
|
c.state[12] = 0
|
||||||
|
if len(nonce) == INonceSize {
|
||||||
|
c.state[13] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||||
|
c.state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||||
|
c.state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||||
|
c.ietf = true
|
||||||
|
} else {
|
||||||
|
c.state[13] = 0
|
||||||
|
c.state[14] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||||
|
c.state[15] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||||
|
c.ietf = false
|
||||||
|
}
|
||||||
|
c.off = BlockSize
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek sets the block counter to a given offset.
|
||||||
|
func (c *Cipher) Seek(blockCounter uint64) error {
|
||||||
|
if c.ietf {
|
||||||
|
if blockCounter > math.MaxUint32 {
|
||||||
|
return ErrInvalidCounter
|
||||||
|
}
|
||||||
|
c.state[12] = uint32(blockCounter)
|
||||||
|
} else {
|
||||||
|
c.state[12] = uint32(blockCounter)
|
||||||
|
c.state[13] = uint32(blockCounter >> 32)
|
||||||
|
}
|
||||||
|
c.off = BlockSize
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCipher returns a new ChaCha20/XChaCha20 instance.
|
||||||
|
func NewCipher(key, nonce []byte) (*Cipher, error) {
|
||||||
|
c := new(Cipher)
|
||||||
|
if err := c.ReKey(key, nonce); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HChaCha is the HChaCha20 hash function used to make XChaCha.
|
||||||
|
func HChaCha(key []byte, nonce *[HNonceSize]byte, out *[32]byte) {
|
||||||
|
var x [stateSize]uint32 // Last 4 slots unused, sigma hardcoded.
|
||||||
|
x[0] = binary.LittleEndian.Uint32(key[0:4])
|
||||||
|
x[1] = binary.LittleEndian.Uint32(key[4:8])
|
||||||
|
x[2] = binary.LittleEndian.Uint32(key[8:12])
|
||||||
|
x[3] = binary.LittleEndian.Uint32(key[12:16])
|
||||||
|
x[4] = binary.LittleEndian.Uint32(key[16:20])
|
||||||
|
x[5] = binary.LittleEndian.Uint32(key[20:24])
|
||||||
|
x[6] = binary.LittleEndian.Uint32(key[24:28])
|
||||||
|
x[7] = binary.LittleEndian.Uint32(key[28:32])
|
||||||
|
x[8] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||||
|
x[9] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||||
|
x[10] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||||
|
x[11] = binary.LittleEndian.Uint32(nonce[12:16])
|
||||||
|
hChaChaRef(&x, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "386", "amd64":
|
||||||
|
// Abuse unsafe to skip calling binary.LittleEndian.PutUint32
|
||||||
|
// in the critical path. This is a big boost on systems that are
|
||||||
|
// little endian and not overly picky about alignment.
|
||||||
|
useUnsafe = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ cipher.Stream = (*Cipher)(nil)
|
||||||
95
vendor/github.com/Yawning/chacha20/chacha20_amd64.go
generated
vendored
Normal file
95
vendor/github.com/Yawning/chacha20/chacha20_amd64.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// chacha20_amd64.go - AMD64 optimized chacha20.
|
||||||
|
//
|
||||||
|
// To the extent possible under law, Yawning Angel has waived all copyright
|
||||||
|
// and related or neighboring rights to chacha20, using the Creative
|
||||||
|
// Commons "CC0" public domain dedication. See LICENSE or
|
||||||
|
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
|
||||||
|
// +build amd64,!gccgo,!appengine
|
||||||
|
|
||||||
|
package chacha20
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
var usingAVX2 = false
|
||||||
|
|
||||||
|
func blocksAmd64SSE2(x *uint32, inp, outp *byte, nrBlocks uint)
|
||||||
|
|
||||||
|
func blocksAmd64AVX2(x *uint32, inp, outp *byte, nrBlocks uint)
|
||||||
|
|
||||||
|
func cpuidAmd64(cpuidParams *uint32)
|
||||||
|
|
||||||
|
func xgetbv0Amd64(xcrVec *uint32)
|
||||||
|
|
||||||
|
func blocksAmd64(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
|
||||||
|
// Probably unneeded, but stating this explicitly simplifies the assembly.
|
||||||
|
if nrBlocks == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isIetf {
|
||||||
|
var totalBlocks uint64
|
||||||
|
totalBlocks = uint64(x[12]) + uint64(nrBlocks)
|
||||||
|
if totalBlocks > math.MaxUint32 {
|
||||||
|
panic("chacha20: Exceeded keystream per nonce limit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if in == nil {
|
||||||
|
for i := range out {
|
||||||
|
out[i] = 0
|
||||||
|
}
|
||||||
|
in = out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointless to call the AVX2 code for just a single block, since half of
|
||||||
|
// the output gets discarded...
|
||||||
|
if usingAVX2 && nrBlocks > 1 {
|
||||||
|
blocksAmd64AVX2(&x[0], &in[0], &out[0], uint(nrBlocks))
|
||||||
|
} else {
|
||||||
|
blocksAmd64SSE2(&x[0], &in[0], &out[0], uint(nrBlocks))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func supportsAVX2() bool {
|
||||||
|
// https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
|
||||||
|
const (
|
||||||
|
osXsaveBit = 1 << 27
|
||||||
|
avx2Bit = 1 << 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check to see if CPUID actually supports the leaf that indicates AVX2.
|
||||||
|
// CPUID.(EAX=0H, ECX=0H) >= 7
|
||||||
|
regs := [4]uint32{0x00}
|
||||||
|
cpuidAmd64(®s[0])
|
||||||
|
if regs[0] < 7 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if the OS knows how to save/restore XMM/YMM state.
|
||||||
|
// CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1
|
||||||
|
regs = [4]uint32{0x01}
|
||||||
|
cpuidAmd64(®s[0])
|
||||||
|
if regs[2]&osXsaveBit == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
xcrRegs := [2]uint32{}
|
||||||
|
xgetbv0Amd64(&xcrRegs[0])
|
||||||
|
if xcrRegs[0]&6 != 6 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for AVX2 support.
|
||||||
|
// CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1
|
||||||
|
regs = [4]uint32{0x07}
|
||||||
|
cpuidAmd64(®s[0])
|
||||||
|
return regs[1]&avx2Bit != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
blocksFn = blocksAmd64
|
||||||
|
usingVectors = true
|
||||||
|
usingAVX2 = supportsAVX2()
|
||||||
|
}
|
||||||
1295
vendor/github.com/Yawning/chacha20/chacha20_amd64.py
generated
vendored
Normal file
1295
vendor/github.com/Yawning/chacha20/chacha20_amd64.py
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1180
vendor/github.com/Yawning/chacha20/chacha20_amd64.s
generated
vendored
Normal file
1180
vendor/github.com/Yawning/chacha20/chacha20_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
394
vendor/github.com/Yawning/chacha20/chacha20_ref.go
generated
vendored
Normal file
394
vendor/github.com/Yawning/chacha20/chacha20_ref.go
generated
vendored
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
// chacha20_ref.go - Reference ChaCha20.
|
||||||
|
//
|
||||||
|
// To the extent possible under law, Yawning Angel has waived all copyright
|
||||||
|
// and related or neighboring rights to chacha20, using the Creative
|
||||||
|
// Commons "CC0" public domain dedication. See LICENSE or
|
||||||
|
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package chacha20
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"math"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func blocksRef(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
|
||||||
|
if isIetf {
|
||||||
|
var totalBlocks uint64
|
||||||
|
totalBlocks = uint64(x[12]) + uint64(nrBlocks)
|
||||||
|
if totalBlocks > math.MaxUint32 {
|
||||||
|
panic("chacha20: Exceeded keystream per nonce limit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This routine ignores x[0]...x[4] in favor the const values since it's
|
||||||
|
// ever so slightly faster.
|
||||||
|
|
||||||
|
for n := 0; n < nrBlocks; n++ {
|
||||||
|
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
|
||||||
|
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
|
||||||
|
|
||||||
|
for i := chachaRounds; i > 0; i -= 2 {
|
||||||
|
// quarterround(x, 0, 4, 8, 12)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = (x12 << 16) | (x12 >> 16)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = (x4 << 12) | (x4 >> 20)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = (x12 << 8) | (x12 >> 24)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = (x4 << 7) | (x4 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 5, 9, 13)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = (x13 << 16) | (x13 >> 16)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = (x5 << 12) | (x5 >> 20)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = (x13 << 8) | (x13 >> 24)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = (x5 << 7) | (x5 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 6, 10, 14)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = (x14 << 16) | (x14 >> 16)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = (x6 << 12) | (x6 >> 20)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = (x14 << 8) | (x14 >> 24)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = (x6 << 7) | (x6 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 7, 11, 15)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = (x15 << 16) | (x15 >> 16)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = (x7 << 12) | (x7 >> 20)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = (x15 << 8) | (x15 >> 24)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = (x7 << 7) | (x7 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 0, 5, 10, 15)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = (x15 << 16) | (x15 >> 16)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = (x5 << 12) | (x5 >> 20)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = (x15 << 8) | (x15 >> 24)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = (x5 << 7) | (x5 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 6, 11, 12)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = (x12 << 16) | (x12 >> 16)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = (x6 << 12) | (x6 >> 20)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = (x12 << 8) | (x12 >> 24)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = (x6 << 7) | (x6 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 7, 8, 13)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = (x13 << 16) | (x13 >> 16)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = (x7 << 12) | (x7 >> 20)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = (x13 << 8) | (x13 >> 24)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = (x7 << 7) | (x7 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 4, 9, 14)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = (x14 << 16) | (x14 >> 16)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = (x4 << 12) | (x4 >> 20)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = (x14 << 8) | (x14 >> 24)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = (x4 << 7) | (x4 >> 25)
|
||||||
|
}
|
||||||
|
|
||||||
|
// On amd64 at least, this is a rather big boost.
|
||||||
|
if useUnsafe {
|
||||||
|
if in != nil {
|
||||||
|
inArr := (*[16]uint32)(unsafe.Pointer(&in[n*BlockSize]))
|
||||||
|
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
|
||||||
|
outArr[0] = inArr[0] ^ (x0 + sigma0)
|
||||||
|
outArr[1] = inArr[1] ^ (x1 + sigma1)
|
||||||
|
outArr[2] = inArr[2] ^ (x2 + sigma2)
|
||||||
|
outArr[3] = inArr[3] ^ (x3 + sigma3)
|
||||||
|
outArr[4] = inArr[4] ^ (x4 + x[4])
|
||||||
|
outArr[5] = inArr[5] ^ (x5 + x[5])
|
||||||
|
outArr[6] = inArr[6] ^ (x6 + x[6])
|
||||||
|
outArr[7] = inArr[7] ^ (x7 + x[7])
|
||||||
|
outArr[8] = inArr[8] ^ (x8 + x[8])
|
||||||
|
outArr[9] = inArr[9] ^ (x9 + x[9])
|
||||||
|
outArr[10] = inArr[10] ^ (x10 + x[10])
|
||||||
|
outArr[11] = inArr[11] ^ (x11 + x[11])
|
||||||
|
outArr[12] = inArr[12] ^ (x12 + x[12])
|
||||||
|
outArr[13] = inArr[13] ^ (x13 + x[13])
|
||||||
|
outArr[14] = inArr[14] ^ (x14 + x[14])
|
||||||
|
outArr[15] = inArr[15] ^ (x15 + x[15])
|
||||||
|
} else {
|
||||||
|
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
|
||||||
|
outArr[0] = x0 + sigma0
|
||||||
|
outArr[1] = x1 + sigma1
|
||||||
|
outArr[2] = x2 + sigma2
|
||||||
|
outArr[3] = x3 + sigma3
|
||||||
|
outArr[4] = x4 + x[4]
|
||||||
|
outArr[5] = x5 + x[5]
|
||||||
|
outArr[6] = x6 + x[6]
|
||||||
|
outArr[7] = x7 + x[7]
|
||||||
|
outArr[8] = x8 + x[8]
|
||||||
|
outArr[9] = x9 + x[9]
|
||||||
|
outArr[10] = x10 + x[10]
|
||||||
|
outArr[11] = x11 + x[11]
|
||||||
|
outArr[12] = x12 + x[12]
|
||||||
|
outArr[13] = x13 + x[13]
|
||||||
|
outArr[14] = x14 + x[14]
|
||||||
|
outArr[15] = x15 + x[15]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Slow path, either the architecture cares about alignment, or is not little endian.
|
||||||
|
x0 += sigma0
|
||||||
|
x1 += sigma1
|
||||||
|
x2 += sigma2
|
||||||
|
x3 += sigma3
|
||||||
|
x4 += x[4]
|
||||||
|
x5 += x[5]
|
||||||
|
x6 += x[6]
|
||||||
|
x7 += x[7]
|
||||||
|
x8 += x[8]
|
||||||
|
x9 += x[9]
|
||||||
|
x10 += x[10]
|
||||||
|
x11 += x[11]
|
||||||
|
x12 += x[12]
|
||||||
|
x13 += x[13]
|
||||||
|
x14 += x[14]
|
||||||
|
x15 += x[15]
|
||||||
|
if in != nil {
|
||||||
|
binary.LittleEndian.PutUint32(out[0:4], binary.LittleEndian.Uint32(in[0:4])^x0)
|
||||||
|
binary.LittleEndian.PutUint32(out[4:8], binary.LittleEndian.Uint32(in[4:8])^x1)
|
||||||
|
binary.LittleEndian.PutUint32(out[8:12], binary.LittleEndian.Uint32(in[8:12])^x2)
|
||||||
|
binary.LittleEndian.PutUint32(out[12:16], binary.LittleEndian.Uint32(in[12:16])^x3)
|
||||||
|
binary.LittleEndian.PutUint32(out[16:20], binary.LittleEndian.Uint32(in[16:20])^x4)
|
||||||
|
binary.LittleEndian.PutUint32(out[20:24], binary.LittleEndian.Uint32(in[20:24])^x5)
|
||||||
|
binary.LittleEndian.PutUint32(out[24:28], binary.LittleEndian.Uint32(in[24:28])^x6)
|
||||||
|
binary.LittleEndian.PutUint32(out[28:32], binary.LittleEndian.Uint32(in[28:32])^x7)
|
||||||
|
binary.LittleEndian.PutUint32(out[32:36], binary.LittleEndian.Uint32(in[32:36])^x8)
|
||||||
|
binary.LittleEndian.PutUint32(out[36:40], binary.LittleEndian.Uint32(in[36:40])^x9)
|
||||||
|
binary.LittleEndian.PutUint32(out[40:44], binary.LittleEndian.Uint32(in[40:44])^x10)
|
||||||
|
binary.LittleEndian.PutUint32(out[44:48], binary.LittleEndian.Uint32(in[44:48])^x11)
|
||||||
|
binary.LittleEndian.PutUint32(out[48:52], binary.LittleEndian.Uint32(in[48:52])^x12)
|
||||||
|
binary.LittleEndian.PutUint32(out[52:56], binary.LittleEndian.Uint32(in[52:56])^x13)
|
||||||
|
binary.LittleEndian.PutUint32(out[56:60], binary.LittleEndian.Uint32(in[56:60])^x14)
|
||||||
|
binary.LittleEndian.PutUint32(out[60:64], binary.LittleEndian.Uint32(in[60:64])^x15)
|
||||||
|
in = in[BlockSize:]
|
||||||
|
} else {
|
||||||
|
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||||
|
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||||
|
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||||
|
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||||
|
binary.LittleEndian.PutUint32(out[16:20], x4)
|
||||||
|
binary.LittleEndian.PutUint32(out[20:24], x5)
|
||||||
|
binary.LittleEndian.PutUint32(out[24:28], x6)
|
||||||
|
binary.LittleEndian.PutUint32(out[28:32], x7)
|
||||||
|
binary.LittleEndian.PutUint32(out[32:36], x8)
|
||||||
|
binary.LittleEndian.PutUint32(out[36:40], x9)
|
||||||
|
binary.LittleEndian.PutUint32(out[40:44], x10)
|
||||||
|
binary.LittleEndian.PutUint32(out[44:48], x11)
|
||||||
|
binary.LittleEndian.PutUint32(out[48:52], x12)
|
||||||
|
binary.LittleEndian.PutUint32(out[52:56], x13)
|
||||||
|
binary.LittleEndian.PutUint32(out[56:60], x14)
|
||||||
|
binary.LittleEndian.PutUint32(out[60:64], x15)
|
||||||
|
}
|
||||||
|
out = out[BlockSize:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stoping at 2^70 bytes per nonce is the user's responsibility.
|
||||||
|
ctr := uint64(x[13])<<32 | uint64(x[12])
|
||||||
|
ctr++
|
||||||
|
x[12] = uint32(ctr)
|
||||||
|
x[13] = uint32(ctr >> 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hChaChaRef(x *[stateSize]uint32, out *[32]byte) {
|
||||||
|
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
|
||||||
|
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11]
|
||||||
|
|
||||||
|
for i := chachaRounds; i > 0; i -= 2 {
|
||||||
|
// quarterround(x, 0, 4, 8, 12)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = (x12 << 16) | (x12 >> 16)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = (x4 << 12) | (x4 >> 20)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = (x12 << 8) | (x12 >> 24)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = (x4 << 7) | (x4 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 5, 9, 13)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = (x13 << 16) | (x13 >> 16)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = (x5 << 12) | (x5 >> 20)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = (x13 << 8) | (x13 >> 24)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = (x5 << 7) | (x5 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 6, 10, 14)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = (x14 << 16) | (x14 >> 16)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = (x6 << 12) | (x6 >> 20)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = (x14 << 8) | (x14 >> 24)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = (x6 << 7) | (x6 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 7, 11, 15)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = (x15 << 16) | (x15 >> 16)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = (x7 << 12) | (x7 >> 20)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = (x15 << 8) | (x15 >> 24)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = (x7 << 7) | (x7 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 0, 5, 10, 15)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = (x15 << 16) | (x15 >> 16)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = (x5 << 12) | (x5 >> 20)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = (x15 << 8) | (x15 >> 24)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = (x5 << 7) | (x5 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 6, 11, 12)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = (x12 << 16) | (x12 >> 16)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = (x6 << 12) | (x6 >> 20)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = (x12 << 8) | (x12 >> 24)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = (x6 << 7) | (x6 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 7, 8, 13)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = (x13 << 16) | (x13 >> 16)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = (x7 << 12) | (x7 >> 20)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = (x13 << 8) | (x13 >> 24)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = (x7 << 7) | (x7 >> 25)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 4, 9, 14)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = (x14 << 16) | (x14 >> 16)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = (x4 << 12) | (x4 >> 20)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = (x14 << 8) | (x14 >> 24)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = (x4 << 7) | (x4 >> 25)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HChaCha returns x0...x3 | x12...x15, which corresponds to the
|
||||||
|
// indexes of the ChaCha constant and the indexes of the IV.
|
||||||
|
if useUnsafe {
|
||||||
|
outArr := (*[16]uint32)(unsafe.Pointer(&out[0]))
|
||||||
|
outArr[0] = x0
|
||||||
|
outArr[1] = x1
|
||||||
|
outArr[2] = x2
|
||||||
|
outArr[3] = x3
|
||||||
|
outArr[4] = x12
|
||||||
|
outArr[5] = x13
|
||||||
|
outArr[6] = x14
|
||||||
|
outArr[7] = x15
|
||||||
|
} else {
|
||||||
|
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||||
|
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||||
|
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||||
|
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||||
|
binary.LittleEndian.PutUint32(out[16:20], x12)
|
||||||
|
binary.LittleEndian.PutUint32(out[20:24], x13)
|
||||||
|
binary.LittleEndian.PutUint32(out[24:28], x14)
|
||||||
|
binary.LittleEndian.PutUint32(out[28:32], x15)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
395
vendor/github.com/Yawning/chacha20/chacha20_ref_go19.go
generated
vendored
Normal file
395
vendor/github.com/Yawning/chacha20/chacha20_ref_go19.go
generated
vendored
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
// chacha20_ref.go - Reference ChaCha20.
|
||||||
|
//
|
||||||
|
// To the extent possible under law, Yawning Angel has waived all copyright
|
||||||
|
// and related or neighboring rights to chacha20, using the Creative
|
||||||
|
// Commons "CC0" public domain dedication. See LICENSE or
|
||||||
|
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package chacha20
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"math"
|
||||||
|
"math/bits"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func blocksRef(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
|
||||||
|
if isIetf {
|
||||||
|
var totalBlocks uint64
|
||||||
|
totalBlocks = uint64(x[12]) + uint64(nrBlocks)
|
||||||
|
if totalBlocks > math.MaxUint32 {
|
||||||
|
panic("chacha20: Exceeded keystream per nonce limit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This routine ignores x[0]...x[4] in favor the const values since it's
|
||||||
|
// ever so slightly faster.
|
||||||
|
|
||||||
|
for n := 0; n < nrBlocks; n++ {
|
||||||
|
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
|
||||||
|
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
|
||||||
|
|
||||||
|
for i := chachaRounds; i > 0; i -= 2 {
|
||||||
|
// quarterround(x, 0, 4, 8, 12)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = bits.RotateLeft32(x12, 16)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = bits.RotateLeft32(x4, 12)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = bits.RotateLeft32(x12, 8)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = bits.RotateLeft32(x4, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 5, 9, 13)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = bits.RotateLeft32(x13, 16)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = bits.RotateLeft32(x5, 12)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = bits.RotateLeft32(x13, 8)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = bits.RotateLeft32(x5, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 6, 10, 14)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = bits.RotateLeft32(x14, 16)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = bits.RotateLeft32(x6, 12)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = bits.RotateLeft32(x14, 8)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = bits.RotateLeft32(x6, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 7, 11, 15)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = bits.RotateLeft32(x15, 16)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = bits.RotateLeft32(x7, 12)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = bits.RotateLeft32(x15, 8)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = bits.RotateLeft32(x7, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 0, 5, 10, 15)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = bits.RotateLeft32(x15, 16)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = bits.RotateLeft32(x5, 12)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = bits.RotateLeft32(x15, 8)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = bits.RotateLeft32(x5, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 6, 11, 12)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = bits.RotateLeft32(x12, 16)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = bits.RotateLeft32(x6, 12)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = bits.RotateLeft32(x12, 8)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = bits.RotateLeft32(x6, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 7, 8, 13)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = bits.RotateLeft32(x13, 16)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = bits.RotateLeft32(x7, 12)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = bits.RotateLeft32(x13, 8)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = bits.RotateLeft32(x7, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 4, 9, 14)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = bits.RotateLeft32(x14, 16)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = bits.RotateLeft32(x4, 12)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = bits.RotateLeft32(x14, 8)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = bits.RotateLeft32(x4, 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
// On amd64 at least, this is a rather big boost.
|
||||||
|
if useUnsafe {
|
||||||
|
if in != nil {
|
||||||
|
inArr := (*[16]uint32)(unsafe.Pointer(&in[n*BlockSize]))
|
||||||
|
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
|
||||||
|
outArr[0] = inArr[0] ^ (x0 + sigma0)
|
||||||
|
outArr[1] = inArr[1] ^ (x1 + sigma1)
|
||||||
|
outArr[2] = inArr[2] ^ (x2 + sigma2)
|
||||||
|
outArr[3] = inArr[3] ^ (x3 + sigma3)
|
||||||
|
outArr[4] = inArr[4] ^ (x4 + x[4])
|
||||||
|
outArr[5] = inArr[5] ^ (x5 + x[5])
|
||||||
|
outArr[6] = inArr[6] ^ (x6 + x[6])
|
||||||
|
outArr[7] = inArr[7] ^ (x7 + x[7])
|
||||||
|
outArr[8] = inArr[8] ^ (x8 + x[8])
|
||||||
|
outArr[9] = inArr[9] ^ (x9 + x[9])
|
||||||
|
outArr[10] = inArr[10] ^ (x10 + x[10])
|
||||||
|
outArr[11] = inArr[11] ^ (x11 + x[11])
|
||||||
|
outArr[12] = inArr[12] ^ (x12 + x[12])
|
||||||
|
outArr[13] = inArr[13] ^ (x13 + x[13])
|
||||||
|
outArr[14] = inArr[14] ^ (x14 + x[14])
|
||||||
|
outArr[15] = inArr[15] ^ (x15 + x[15])
|
||||||
|
} else {
|
||||||
|
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
|
||||||
|
outArr[0] = x0 + sigma0
|
||||||
|
outArr[1] = x1 + sigma1
|
||||||
|
outArr[2] = x2 + sigma2
|
||||||
|
outArr[3] = x3 + sigma3
|
||||||
|
outArr[4] = x4 + x[4]
|
||||||
|
outArr[5] = x5 + x[5]
|
||||||
|
outArr[6] = x6 + x[6]
|
||||||
|
outArr[7] = x7 + x[7]
|
||||||
|
outArr[8] = x8 + x[8]
|
||||||
|
outArr[9] = x9 + x[9]
|
||||||
|
outArr[10] = x10 + x[10]
|
||||||
|
outArr[11] = x11 + x[11]
|
||||||
|
outArr[12] = x12 + x[12]
|
||||||
|
outArr[13] = x13 + x[13]
|
||||||
|
outArr[14] = x14 + x[14]
|
||||||
|
outArr[15] = x15 + x[15]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Slow path, either the architecture cares about alignment, or is not little endian.
|
||||||
|
x0 += sigma0
|
||||||
|
x1 += sigma1
|
||||||
|
x2 += sigma2
|
||||||
|
x3 += sigma3
|
||||||
|
x4 += x[4]
|
||||||
|
x5 += x[5]
|
||||||
|
x6 += x[6]
|
||||||
|
x7 += x[7]
|
||||||
|
x8 += x[8]
|
||||||
|
x9 += x[9]
|
||||||
|
x10 += x[10]
|
||||||
|
x11 += x[11]
|
||||||
|
x12 += x[12]
|
||||||
|
x13 += x[13]
|
||||||
|
x14 += x[14]
|
||||||
|
x15 += x[15]
|
||||||
|
if in != nil {
|
||||||
|
binary.LittleEndian.PutUint32(out[0:4], binary.LittleEndian.Uint32(in[0:4])^x0)
|
||||||
|
binary.LittleEndian.PutUint32(out[4:8], binary.LittleEndian.Uint32(in[4:8])^x1)
|
||||||
|
binary.LittleEndian.PutUint32(out[8:12], binary.LittleEndian.Uint32(in[8:12])^x2)
|
||||||
|
binary.LittleEndian.PutUint32(out[12:16], binary.LittleEndian.Uint32(in[12:16])^x3)
|
||||||
|
binary.LittleEndian.PutUint32(out[16:20], binary.LittleEndian.Uint32(in[16:20])^x4)
|
||||||
|
binary.LittleEndian.PutUint32(out[20:24], binary.LittleEndian.Uint32(in[20:24])^x5)
|
||||||
|
binary.LittleEndian.PutUint32(out[24:28], binary.LittleEndian.Uint32(in[24:28])^x6)
|
||||||
|
binary.LittleEndian.PutUint32(out[28:32], binary.LittleEndian.Uint32(in[28:32])^x7)
|
||||||
|
binary.LittleEndian.PutUint32(out[32:36], binary.LittleEndian.Uint32(in[32:36])^x8)
|
||||||
|
binary.LittleEndian.PutUint32(out[36:40], binary.LittleEndian.Uint32(in[36:40])^x9)
|
||||||
|
binary.LittleEndian.PutUint32(out[40:44], binary.LittleEndian.Uint32(in[40:44])^x10)
|
||||||
|
binary.LittleEndian.PutUint32(out[44:48], binary.LittleEndian.Uint32(in[44:48])^x11)
|
||||||
|
binary.LittleEndian.PutUint32(out[48:52], binary.LittleEndian.Uint32(in[48:52])^x12)
|
||||||
|
binary.LittleEndian.PutUint32(out[52:56], binary.LittleEndian.Uint32(in[52:56])^x13)
|
||||||
|
binary.LittleEndian.PutUint32(out[56:60], binary.LittleEndian.Uint32(in[56:60])^x14)
|
||||||
|
binary.LittleEndian.PutUint32(out[60:64], binary.LittleEndian.Uint32(in[60:64])^x15)
|
||||||
|
in = in[BlockSize:]
|
||||||
|
} else {
|
||||||
|
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||||
|
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||||
|
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||||
|
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||||
|
binary.LittleEndian.PutUint32(out[16:20], x4)
|
||||||
|
binary.LittleEndian.PutUint32(out[20:24], x5)
|
||||||
|
binary.LittleEndian.PutUint32(out[24:28], x6)
|
||||||
|
binary.LittleEndian.PutUint32(out[28:32], x7)
|
||||||
|
binary.LittleEndian.PutUint32(out[32:36], x8)
|
||||||
|
binary.LittleEndian.PutUint32(out[36:40], x9)
|
||||||
|
binary.LittleEndian.PutUint32(out[40:44], x10)
|
||||||
|
binary.LittleEndian.PutUint32(out[44:48], x11)
|
||||||
|
binary.LittleEndian.PutUint32(out[48:52], x12)
|
||||||
|
binary.LittleEndian.PutUint32(out[52:56], x13)
|
||||||
|
binary.LittleEndian.PutUint32(out[56:60], x14)
|
||||||
|
binary.LittleEndian.PutUint32(out[60:64], x15)
|
||||||
|
}
|
||||||
|
out = out[BlockSize:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stoping at 2^70 bytes per nonce is the user's responsibility.
|
||||||
|
ctr := uint64(x[13])<<32 | uint64(x[12])
|
||||||
|
ctr++
|
||||||
|
x[12] = uint32(ctr)
|
||||||
|
x[13] = uint32(ctr >> 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hChaChaRef(x *[stateSize]uint32, out *[32]byte) {
|
||||||
|
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
|
||||||
|
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11]
|
||||||
|
|
||||||
|
for i := chachaRounds; i > 0; i -= 2 {
|
||||||
|
// quarterround(x, 0, 4, 8, 12)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = bits.RotateLeft32(x12, 16)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = bits.RotateLeft32(x4, 12)
|
||||||
|
x0 += x4
|
||||||
|
x12 ^= x0
|
||||||
|
x12 = bits.RotateLeft32(x12, 8)
|
||||||
|
x8 += x12
|
||||||
|
x4 ^= x8
|
||||||
|
x4 = bits.RotateLeft32(x4, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 5, 9, 13)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = bits.RotateLeft32(x13, 16)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = bits.RotateLeft32(x5, 12)
|
||||||
|
x1 += x5
|
||||||
|
x13 ^= x1
|
||||||
|
x13 = bits.RotateLeft32(x13, 8)
|
||||||
|
x9 += x13
|
||||||
|
x5 ^= x9
|
||||||
|
x5 = bits.RotateLeft32(x5, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 6, 10, 14)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = bits.RotateLeft32(x14, 16)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = bits.RotateLeft32(x6, 12)
|
||||||
|
x2 += x6
|
||||||
|
x14 ^= x2
|
||||||
|
x14 = bits.RotateLeft32(x14, 8)
|
||||||
|
x10 += x14
|
||||||
|
x6 ^= x10
|
||||||
|
x6 = bits.RotateLeft32(x6, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 7, 11, 15)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = bits.RotateLeft32(x15, 16)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = bits.RotateLeft32(x7, 12)
|
||||||
|
x3 += x7
|
||||||
|
x15 ^= x3
|
||||||
|
x15 = bits.RotateLeft32(x15, 8)
|
||||||
|
x11 += x15
|
||||||
|
x7 ^= x11
|
||||||
|
x7 = bits.RotateLeft32(x7, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 0, 5, 10, 15)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = bits.RotateLeft32(x15, 16)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = bits.RotateLeft32(x5, 12)
|
||||||
|
x0 += x5
|
||||||
|
x15 ^= x0
|
||||||
|
x15 = bits.RotateLeft32(x15, 8)
|
||||||
|
x10 += x15
|
||||||
|
x5 ^= x10
|
||||||
|
x5 = bits.RotateLeft32(x5, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 1, 6, 11, 12)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = bits.RotateLeft32(x12, 16)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = bits.RotateLeft32(x6, 12)
|
||||||
|
x1 += x6
|
||||||
|
x12 ^= x1
|
||||||
|
x12 = bits.RotateLeft32(x12, 8)
|
||||||
|
x11 += x12
|
||||||
|
x6 ^= x11
|
||||||
|
x6 = bits.RotateLeft32(x6, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 2, 7, 8, 13)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = bits.RotateLeft32(x13, 16)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = bits.RotateLeft32(x7, 12)
|
||||||
|
x2 += x7
|
||||||
|
x13 ^= x2
|
||||||
|
x13 = bits.RotateLeft32(x13, 8)
|
||||||
|
x8 += x13
|
||||||
|
x7 ^= x8
|
||||||
|
x7 = bits.RotateLeft32(x7, 7)
|
||||||
|
|
||||||
|
// quarterround(x, 3, 4, 9, 14)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = bits.RotateLeft32(x14, 16)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = bits.RotateLeft32(x4, 12)
|
||||||
|
x3 += x4
|
||||||
|
x14 ^= x3
|
||||||
|
x14 = bits.RotateLeft32(x14, 8)
|
||||||
|
x9 += x14
|
||||||
|
x4 ^= x9
|
||||||
|
x4 = bits.RotateLeft32(x4, 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HChaCha returns x0...x3 | x12...x15, which corresponds to the
|
||||||
|
// indexes of the ChaCha constant and the indexes of the IV.
|
||||||
|
if useUnsafe {
|
||||||
|
outArr := (*[16]uint32)(unsafe.Pointer(&out[0]))
|
||||||
|
outArr[0] = x0
|
||||||
|
outArr[1] = x1
|
||||||
|
outArr[2] = x2
|
||||||
|
outArr[3] = x3
|
||||||
|
outArr[4] = x12
|
||||||
|
outArr[5] = x13
|
||||||
|
outArr[6] = x14
|
||||||
|
outArr[7] = x15
|
||||||
|
} else {
|
||||||
|
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||||
|
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||||
|
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||||
|
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||||
|
binary.LittleEndian.PutUint32(out[16:20], x12)
|
||||||
|
binary.LittleEndian.PutUint32(out[20:24], x13)
|
||||||
|
binary.LittleEndian.PutUint32(out[24:28], x14)
|
||||||
|
binary.LittleEndian.PutUint32(out[28:32], x15)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user