From 15fcc9a33809c3c911c83dc6c62b2f5234cb8612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Thu, 30 Oct 2025 23:23:45 +0800 Subject: [PATCH] feat: add log & supporting packages --- aes.go | 8 +-- aes_test.go | 2 +- api/auth/client.go | 29 +++++++++ api/auth/client_test.go | 54 ++++++++++++++++ go.mod | 11 ++++ go.sum | 22 +++++++ internal/hcli/api.go | 18 ++++++ internal/hcli/http.go | 65 +++++++++++++++++++ internal/hson/req.go | 22 +++++++ internal/hson/resp.go | 56 +++++++++++++++++ internal/log/def.go | 3 + internal/log/wrap.go | 103 ++++++++++++++++++++++++++++++ internal/op/chain.go | 8 +++ internal/textio/api.go | 70 +++++++++++++++++++++ internal/textio/api_test.go | 122 ++++++++++++++++++++++++++++++++++++ internal/textio/name.go | 64 +++++++++++++++++++ internal/textio/str.go | 13 ++++ rsa.go | 10 +-- rsa_test.go | 4 +- 19 files changed, 672 insertions(+), 12 deletions(-) create mode 100644 api/auth/client.go create mode 100644 api/auth/client_test.go create mode 100644 go.sum create mode 100644 internal/hcli/api.go create mode 100644 internal/hcli/http.go create mode 100644 internal/hson/req.go create mode 100644 internal/hson/resp.go create mode 100644 internal/log/def.go create mode 100644 internal/log/wrap.go create mode 100644 internal/op/chain.go create mode 100644 internal/textio/api.go create mode 100644 internal/textio/api_test.go create mode 100644 internal/textio/name.go create mode 100644 internal/textio/str.go diff --git a/aes.go b/aes.go index 4acd3a1..553c300 100644 --- a/aes.go +++ b/aes.go @@ -10,9 +10,9 @@ const ( ETPYE_AES_CBC = "2" ) -type TYAES [32]byte +type AES [32]byte -func NewTYAES(rawKey []byte) (tya TYAES) { +func NewAES(rawKey []byte) (tya AES) { if len(rawKey) != 32 { panic("len(key) must == 32") } @@ -40,7 +40,7 @@ func pkcs7Unpadding(data []byte) []byte { return data[:len(data)-padding] } -func (tya TYAES) Encrypt(b []byte) []byte { +func (tya AES) Encrypt(b []byte) []byte { blk, err := aes.NewCipher(tya[:]) if err != nil { panic(err) @@ -55,7 +55,7 @@ func (tya TYAES) Encrypt(b []byte) []byte { return ciphertext } -func (tya TYAES) Decrypt(b []byte) ([]byte, error) { +func (tya AES) Decrypt(b []byte) ([]byte, error) { blk, err := aes.NewCipher(tya[:]) if err != nil { return nil, err diff --git a/aes_test.go b/aes_test.go index a2ac36f..1bb646e 100644 --- a/aes_test.go +++ b/aes_test.go @@ -27,7 +27,7 @@ func TestDecrypt(t *testing.T) { t.Fatal(err) } - dat, err := NewTYAES(key[:]).Decrypt(d) + dat, err := NewAES(key[:]).Decrypt(d) if err != nil { t.Fatal(err) } diff --git a/api/auth/client.go b/api/auth/client.go new file mode 100644 index 0000000..1832281 --- /dev/null +++ b/api/auth/client.go @@ -0,0 +1,29 @@ +package auth + +import ( + "bytes" + + "github.com/fumiama/tienyik/internal/hcli" + "github.com/fumiama/tienyik/internal/hson" + "github.com/fumiama/tienyik/internal/textio" +) + +type RequestNegotiationEncKey struct { + CertData string `json:"certData"` + CertType string `json:"certType"` + Etype string `json:"etype"` +} + +type ResponseNegotiationEncKey struct { + EncData string `json:"encData"` + EncKey string `json:"encKey"` +} + +func NegotiationEncKey(r *RequestNegotiationEncKey) (*ResponseNegotiationEncKey, error) { + resp, err := hcli.Post(textio.API(), bytes.NewReader(hson.Marshal(nil, r))) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return hson.Unmarshal[*ResponseNegotiationEncKey](nil, resp.Body) +} diff --git a/api/auth/client_test.go b/api/auth/client_test.go new file mode 100644 index 0000000..c121f12 --- /dev/null +++ b/api/auth/client_test.go @@ -0,0 +1,54 @@ +package auth + +import ( + "crypto/rand" + "crypto/rsa" + "encoding/base64" + "testing" + + "github.com/fumiama/tienyik" + "github.com/sirupsen/logrus" +) + +func TestNegotiationEncKey(t *testing.T) { + logrus.SetLevel(logrus.DebugLevel) + + k, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + tyr := (*tienyik.RSA)(k) + tyr.E = 0x010001 + + r, err := NegotiationEncKey(&RequestNegotiationEncKey{ + CertData: tyr.PublicKeyToSPKI(), + CertType: tienyik.ETPYE_AES_CBC, + Etype: tienyik.ETPYE_AES_CBC, + }) + if err != nil { + t.Fatal(err) + } + + t.Logf("EncData: %s", r.EncData) + t.Logf("EncKey: %s", r.EncKey) + + v, err := base64.StdEncoding.DecodeString(r.EncKey) + if err != nil { + t.Fatal(err) + } + aesk, err := tyr.Decrypt(v) + if err != nil { + t.Fatal(err) + } + t.Log(string(aesk)) + + v, err = base64.StdEncoding.DecodeString(r.EncData) + if err != nil { + t.Fatal(err) + } + v, err = tienyik.NewAES([]byte(aesk)).Decrypt(v) + if err != nil { + t.Fatal(err) + } + t.Log(string(v)) +} diff --git a/go.mod b/go.mod index 11ba492..2a95693 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,14 @@ module github.com/fumiama/tienyik go 1.24.4 + +require ( + github.com/fumiama/go-base16384 v1.7.1 + github.com/sirupsen/logrus v1.9.3 +) + +require ( + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + golang.org/x/text v0.3.7 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2ee0a67 --- /dev/null +++ b/go.sum @@ -0,0 +1,22 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fumiama/go-base16384 v1.7.1 h1:1P1x6FWRvd7PtbH4idDAGWAjKKcVxggxlROYKRXbw58= +github.com/fumiama/go-base16384 v1.7.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/hcli/api.go b/internal/hcli/api.go new file mode 100644 index 0000000..74a37cb --- /dev/null +++ b/internal/hcli/api.go @@ -0,0 +1,18 @@ +package hcli + +import ( + "strings" + + base14 "github.com/fumiama/go-base16384" + "github.com/fumiama/tienyik/internal/log" +) + +var eps = base14.DecodeString("栝啇俌蠯姙呗宬籣欞敖蚹煮岎冃勀紀㴆") + +func ep(p string) string { + sb := &strings.Builder{} + sb.WriteString(eps) + sb.WriteString(p) + log.Debugln("ep wraps:", sb) + return sb.String() +} diff --git a/internal/hcli/http.go b/internal/hcli/http.go new file mode 100644 index 0000000..fd6c236 --- /dev/null +++ b/internal/hcli/http.go @@ -0,0 +1,65 @@ +package hcli + +import ( + "io" + "net/http" + + base14 "github.com/fumiama/go-base16384" +) + +func setCommonHeaders(req *http.Request) { + req.Header.Set("Accept", "application/json") + req.Header.Set("Pragma", "no-cache") + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Origin", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸㴅")) + req.Header.Set("Referer", base14.DecodeString("栝啇俌蠯姜吲融艹歛烦宸紀㴆")) + req.Header.Set( + "User-Agent", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0", + ) +} + +func Get(path string) (resp *http.Response, err error) { + req, err := http.NewRequest(http.MethodGet, ep(path), nil) + if err != nil { + return nil, err + } + setCommonHeaders(req) + return http.DefaultClient.Do(req) +} + +func Post(path string, body io.Reader) (resp *http.Response, err error) { + req, err := http.NewRequest(http.MethodPost, ep(path), body) + if err != nil { + return nil, err + } + setCommonHeaders(req) + return http.DefaultClient.Do(req) +} + +func Put(path string, body io.Reader) (resp *http.Response, err error) { + req, err := http.NewRequest(http.MethodPut, ep(path), body) + if err != nil { + return nil, err + } + setCommonHeaders(req) + return http.DefaultClient.Do(req) +} + +func Delete(path string) (resp *http.Response, err error) { + req, err := http.NewRequest(http.MethodDelete, ep(path), nil) + if err != nil { + return nil, err + } + setCommonHeaders(req) + return http.DefaultClient.Do(req) +} + +func Patch(path string, body io.Reader) (resp *http.Response, err error) { + req, err := http.NewRequest(http.MethodPatch, ep(path), body) + if err != nil { + return nil, err + } + setCommonHeaders(req) + return http.DefaultClient.Do(req) +} diff --git a/internal/hson/req.go b/internal/hson/req.go new file mode 100644 index 0000000..9600cdd --- /dev/null +++ b/internal/hson/req.go @@ -0,0 +1,22 @@ +package hson + +import ( + "bytes" + "encoding/json" + + "github.com/fumiama/tienyik" + "github.com/fumiama/tienyik/internal/log" +) + +func Marshal(tya *tienyik.AES, v any) []byte { + w := bytes.NewBuffer(make([]byte, 0, 1024)) + err := json.NewEncoder(w).Encode(v) + if err != nil { + panic(err) + } + log.Debugln("Marshal JSON:", w.String()) + if tya != nil { + return tya.Encrypt(w.Bytes()) + } + return w.Bytes() +} diff --git a/internal/hson/resp.go b/internal/hson/resp.go new file mode 100644 index 0000000..80b37a9 --- /dev/null +++ b/internal/hson/resp.go @@ -0,0 +1,56 @@ +package hson + +import ( + "encoding/base64" + "encoding/json" + "errors" + "io" + "strconv" + + "github.com/fumiama/tienyik" + "github.com/fumiama/tienyik/internal/log" +) + +type responseBase[T any] struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data T `json:"data"` + EData string `json:"edata"` +} + +func (rb *responseBase[T]) ok() error { + if rb.Code != 0 { + return errors.New("[" + strconv.Itoa(rb.Code) + "] " + rb.Msg) + } + return nil +} + +func Unmarshal[T any](tya *tienyik.AES, r io.Reader) (data T, err error) { + var rsp responseBase[T] + err = json.NewDecoder(r).Decode(&rsp) + if err == nil { + err = rsp.ok() + } + if err != nil { + return + } + if len(rsp.EData) > 0 && tya != nil { + var d []byte + d, err = base64.StdEncoding.DecodeString(rsp.EData) + if err != nil { + return + } + d, err = tya.Decrypt(d) + if err != nil { + return + } + log.Debugln("decrypted data:", string(d)) + err = json.Unmarshal(d, &rsp) + if err != nil { + return + } + err = rsp.ok() + } + data = rsp.Data + return +} diff --git a/internal/log/def.go b/internal/log/def.go new file mode 100644 index 0000000..e162e06 --- /dev/null +++ b/internal/log/def.go @@ -0,0 +1,3 @@ +package log + +const debug = true diff --git a/internal/log/wrap.go b/internal/log/wrap.go new file mode 100644 index 0000000..8877a78 --- /dev/null +++ b/internal/log/wrap.go @@ -0,0 +1,103 @@ +package log + +import ( + "github.com/sirupsen/logrus" + + "github.com/fumiama/tienyik/internal/textio" +) + +func Debug(args ...any) { + if debug { + args = append([]any{textio.Logger(2)}, args...) + logrus.Debug(args...) + } +} + +func Debugf(format string, args ...any) { + if debug { + args = append([]any{textio.Logger(2)}, args...) + logrus.Debugf(format, args...) + } +} + +func Debugln(args ...any) { + if debug { + args = append([]any{textio.Logger(2)}, args...) + logrus.Debugln(args...) + } +} + +func Info(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Info(args...) +} + +func Infof(format string, args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Infof(format, args...) +} + +func Infoln(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Infoln(args...) +} + +func Warn(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Warn(args...) +} + +func Warnf(format string, args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Warnf(format, args...) +} + +func Warnln(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Warnln(args...) +} + +func Error(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Error(args...) +} + +func Errorf(format string, args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Errorf(format, args...) +} + +func Errorln(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Errorln(args...) +} + +func Fatal(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Fatal(args...) +} + +func Fatalf(format string, args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Fatalf(format, args...) +} + +func Fatalln(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Fatalln(args...) +} + +func Panic(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Panic(args...) +} + +func Panicf(format string, args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Panicf(format, args...) +} + +func Panicln(args ...any) { + args = append([]any{textio.Logger(2)}, args...) + logrus.Panicln(args...) +} diff --git a/internal/op/chain.go b/internal/op/chain.go new file mode 100644 index 0000000..68128a6 --- /dev/null +++ b/internal/op/chain.go @@ -0,0 +1,8 @@ +package op + +func Must[T any](x T, err error) T { + if err != nil { + panic(err) + } + return x +} diff --git a/internal/textio/api.go b/internal/textio/api.go new file mode 100644 index 0000000..a7cb72b --- /dev/null +++ b/internal/textio/api.go @@ -0,0 +1,70 @@ +package textio + +import ( + "errors" + "net/url" + "runtime" + "strings" + + "github.com/fumiama/tienyik" +) + +func API() string { + pc, f, _, ok := runtime.Caller(1) + if !ok { + panic("cannot get api of caller") + } + if strings.Contains(f, "\\") { + f = strings.ReplaceAll(f, "\\", "/") + } + _, p, ok := strings.Cut(f, "/tienyik/") + if !ok { + panic("cannot cut api " + f + " of caller") + } + f = strings.TrimSuffix(p, ".go") + fn := runtime.FuncForPC(pc) + if fn == nil { + panic("cannot get func name of caller, api: " + f) + } + p = fn.Name() + i := strings.LastIndex(p, ".") + if i < 0 { + panic("func name of caller '" + p + " has no '.', api: " + f) + } + p = p[i+1:] + if len(p) <= 1 { + panic("func name of caller '" + p + " too short', api: " + f) + } + sb := strings.Builder{} + sb.WriteString(f) + sb.WriteByte('/') + sb.WriteString(strings.ToLower(p[:1])) + sb.WriteString(p[1:]) + return sb.String() +} + +func EUrlParams(tya *tienyik.AES, params url.Values) string { + return url.Values{ + FuncName(1, true): {BytesToString(tya.Encrypt( + StringToBytes(params.Encode()), + ))}, + }.Encode() +} + +func ParseQuery(tya *tienyik.AES, eparams string) (url.Values, error) { + q, err := url.ParseQuery(eparams) + if err != nil { + return nil, err + } + if len(q) != 1 { + return nil, errors.New("len(q) must be 1") + } + for _, v := range q { + dec, err := tya.Decrypt(StringToBytes(v[0])) + if err != nil { + return nil, err + } + return url.ParseQuery(BytesToString(dec)) + } + panic("unexpected") +} diff --git a/internal/textio/api_test.go b/internal/textio/api_test.go new file mode 100644 index 0000000..c2ff540 --- /dev/null +++ b/internal/textio/api_test.go @@ -0,0 +1,122 @@ +package textio + +import ( + "encoding/binary" + "net/url" + "testing" + + "github.com/fumiama/tienyik" +) + +func TestEUrlParams(t *testing.T) { + const aesplain = "moduleCode=DESKTOP_MSGCENTER" + var ( + rawkey = []uint32{ + 2004378729, 1936745065, 1933079672, 1970627951, + 842425958, 1932686949, 1903374648, 1936290669, + } + key [32]byte + ) + for i, k := range rawkey { + binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k) + } + t.Log(string(key[:])) // wxdispbis8txuueo26ffs2veqs18sism + tya := tienyik.NewAES(key[:]) + params := EUrlParams(&tya, url.Values{ + "moduleCode": {"DESKTOP_MSGCENTER"}, + }) + q, err := ParseQuery(&tya, params) + if err != nil { + t.Fatal(err) + } + for k, v := range q { + plainValue := k + "=" + v[0] + if plainValue != aesplain { + t.Fatal("expect", aesplain, "got", plainValue) + } + } +} + +func TestEUrlParamsMultiple(t *testing.T) { + var ( + rawkey = []uint32{ + 2004378729, 1936745065, 1933079672, 1970627951, + 842425958, 1932686949, 1903374648, 1936290669, + } + key [32]byte + ) + for i, k := range rawkey { + binary.BigEndian.PutUint32(key[i*4:(i+1)*4], k) + } + tya := tienyik.NewAES(key[:]) + + testCases := []struct { + name string + params url.Values + expected map[string]string + }{ + { + name: "single parameter", + params: url.Values{ + "userId": {"12345"}, + }, + expected: map[string]string{ + "userId": "12345", + }, + }, + { + name: "multiple parameters", + params: url.Values{ + "userId": {"12345"}, + "userName": {"testUser"}, + "status": {"active"}, + }, + expected: map[string]string{ + "userId": "12345", + "userName": "testUser", + "status": "active", + }, + }, + { + name: "special characters", + params: url.Values{ + "email": {"test@example.com"}, + "message": {"Hello World!"}, + }, + expected: map[string]string{ + "email": "test@example.com", + "message": "Hello World!", + }, + }, + { + name: "chinese characters", + params: url.Values{ + "name": {"张三"}, + "city": {"北京"}, + }, + expected: map[string]string{ + "name": "张三", + "city": "北京", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + params := EUrlParams(&tya, tc.params) + q, err := ParseQuery(&tya, params) + if err != nil { + t.Fatal(err) + } + for key, expectedValue := range tc.expected { + if vals, ok := q[key]; ok && len(vals) > 0 { + if vals[0] != expectedValue { + t.Fatalf("key %s: expect %s, got %s", key, expectedValue, vals[0]) + } + } else { + t.Fatalf("key %s not found in query", key) + } + } + }) + } +} diff --git a/internal/textio/name.go b/internal/textio/name.go new file mode 100644 index 0000000..49a2d38 --- /dev/null +++ b/internal/textio/name.go @@ -0,0 +1,64 @@ +package textio + +import ( + "runtime" + "strings" +) + +func Logger(skip int) string { + sb := strings.Builder{} + sb.WriteString("[") + sb.WriteString(FileName(skip + 1)) + sb.WriteString("]") + return sb.String() +} + +func FileName(skip int) string { + _, file, _, ok := runtime.Caller(skip) + if !ok { + return "unknown" + } + i := strings.LastIndex(file, "/") + if i < 0 { + i = strings.LastIndex(file, "\\") + if i < 0 { + return file + } + } + nm := file[i+1:] + if len(nm) == 0 { + return file + } + i = strings.LastIndex(nm, ".") + if i <= 0 { + return nm + } + return nm[:i] +} + +func FuncName(skip int, lowerfirst bool) string { + fn, _, _, ok := runtime.Caller(skip) + if !ok { + panic("cannot get func name of caller") + } + f := runtime.FuncForPC(fn) + if f == nil { + panic("invalid func pc") + } + p := f.Name() + i := strings.LastIndex(p, ".") + if i < 0 { + panic("func name of caller '" + p + " has no '.'") + } + p = p[i+1:] + if len(p) <= 1 { + panic("func name of caller '" + p + " too short'") + } + if lowerfirst { + sb := strings.Builder{} + sb.WriteString(strings.ToLower(p[:1])) + sb.WriteString(p[1:]) + return sb.String() + } + return p +} diff --git a/internal/textio/str.go b/internal/textio/str.go new file mode 100644 index 0000000..d09e69f --- /dev/null +++ b/internal/textio/str.go @@ -0,0 +1,13 @@ +package textio + +import "unsafe" + +// BytesToString 没有内存开销的转换 +func BytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// StringToBytes 没有内存开销的转换 +func StringToBytes(s string) (b []byte) { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} diff --git a/rsa.go b/rsa.go index 818dada..6e8b924 100644 --- a/rsa.go +++ b/rsa.go @@ -7,19 +7,19 @@ import ( "encoding/base64" ) -type TYRSA rsa.PrivateKey +type RSA rsa.PrivateKey -func NewTYRSA() *TYRSA { +func NewRSA() *RSA { privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } privateKey.E = 0x010001 - return (*TYRSA)(privateKey) + return (*RSA)(privateKey) } -func (tyr *TYRSA) PublicKeyToSPKI() string { +func (tyr *RSA) PublicKeyToSPKI() string { spkiBytes, err := x509.MarshalPKIXPublicKey(&tyr.PublicKey) if err != nil { panic(err) @@ -27,6 +27,6 @@ func (tyr *TYRSA) PublicKeyToSPKI() string { return base64.StdEncoding.EncodeToString(spkiBytes) } -func (tyr *TYRSA) Decrypt(ciphertext []byte) ([]byte, error) { +func (tyr *RSA) Decrypt(ciphertext []byte) ([]byte, error) { return rsa.DecryptPKCS1v15(rand.Reader, (*rsa.PrivateKey)(tyr), ciphertext) } diff --git a/rsa_test.go b/rsa_test.go index 7e3fbae..0b89c59 100644 --- a/rsa_test.go +++ b/rsa_test.go @@ -33,7 +33,7 @@ func TestRSANegotiationEncKey(t *testing.T) { if err != nil { t.Fatal(err) } - tyr := (*TYRSA)(k.(*rsa.PrivateKey)) + tyr := (*RSA)(k.(*rsa.PrivateKey)) tyr.E = 0x010001 w := bytes.NewBuffer(make([]byte, 0, 1024)) @@ -86,7 +86,7 @@ func TestRSANegotiationEncKey(t *testing.T) { if err != nil { t.Fatal(err) } - v, err = NewTYAES([]byte(aesk)).Decrypt(v) + v, err = NewAES([]byte(aesk)).Decrypt(v) if err != nil { t.Fatal(err) }