Skip to content

Commit

Permalink
add request encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
triamazikamno committed Dec 6, 2023
1 parent 391253a commit 5bb253c
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 14 deletions.
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"appkey": "93D72E60331ABDCDC7B39ADC2D1F32B3",
"appkey": "B0455FBE7AA0328DB57B59AA729F05D8",
"config": "",
"debug": false,
"host": "https://augateway.isolarcloud.com",
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/MickMake/GoSungrow

go 1.19

replace github.com/MickMake/GoUnify => ../../GoUnify
//replace github.com/MickMake/GoUnify => ../../GoUnify

//replace github.com/MickMake/GoUnify/cmdConfig => ../../GoUnify/cmdConfig
//replace github.com/MickMake/GoUnify/cmdLog => ../../GoUnify/cmdLog
Expand All @@ -17,7 +17,6 @@ replace github.com/MickMake/GoUnify => ../../GoUnify
//replace github.com/MickMake/GoUnify/cmdPath => ../../GoUnify/cmdPath

require (
github.com/MickMake/GoUnify v0.0.0-00010101000000-000000000000
github.com/agrison/go-tablib v0.0.0-20160310143025-4930582c22ee
github.com/agrison/mxj v0.0.0-20160310142625-1269f8afb3b4
github.com/eclipse/paho.mqtt.golang v1.4.3
Expand All @@ -35,12 +34,15 @@ require (
gopkg.in/yaml.v2 v2.4.0
)

require github.com/MickMake/GoUnify v1.0.3-0.20230904042338-0db745f1bada

require (
github.com/MichaelMure/go-term-markdown v0.1.4 // indirect
github.com/MichaelMure/go-term-text v0.3.1 // indirect
github.com/abiosoft/ishell/v2 v2.0.2 // indirect
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect
github.com/alecthomas/chroma v0.7.1 // indirect
github.com/andreburgaud/crypt2go v1.4.0 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blend/go-sdk v1.20220411.3 // indirect
github.com/bndr/gotabulate v1.1.2 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ github.com/MichaelMure/go-term-markdown v0.1.4 h1:Ir3kBXDUtOX7dEv0EaQV8CNPpH+T7A
github.com/MichaelMure/go-term-markdown v0.1.4/go.mod h1:EhcA3+pKYnlUsxYKBJ5Sn1cTQmmBMjeNlpV8nRb+JxA=
github.com/MichaelMure/go-term-text v0.3.1 h1:Kw9kZanyZWiCHOYu9v/8pWEgDQ6UVN9/ix2Vd2zzWf0=
github.com/MichaelMure/go-term-text v0.3.1/go.mod h1:QgVjAEDUnRMlzpS6ky5CGblux7ebeiLnuy9dAaFZu8o=
github.com/MickMake/GoUnify v1.0.3-0.20230904042338-0db745f1bada h1:5eNyQ1v0vKn1KvkodbJ00mrFeIrVr5mi3hReFthmJiU=
github.com/MickMake/GoUnify v1.0.3-0.20230904042338-0db745f1bada/go.mod h1:FrPAWZco+Tk44Vhp7juiRdhQyb81bCneLRAhf8asi2E=
github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw=
github.com/abiosoft/ishell/v2 v2.0.2 h1:5qVfGiQISaYM8TkbBl7RFO6MddABoXpATrsFbVI+SNo=
github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs=
Expand All @@ -60,6 +62,8 @@ github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBo
github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/andreburgaud/crypt2go v1.4.0 h1:i2zy+SmjKlQ22eGMR8pIOgrp8OJwbEYp/TVKIcJJBY4=
github.com/andreburgaud/crypt2go v1.4.0/go.mod h1:MVXF4rq1q0igLFpdb+XW1DfIIgvbSsswGRUwwFbzcnc=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blend/go-sdk v1.20220411.3 h1:GFV4/FQX5UzXLPwWV03gP811pj7B8J2sbuq+GJQofXc=
Expand Down
6 changes: 5 additions & 1 deletion iSolarCloud/AppService/login/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ func (e *EndPoint) Login(auth *SunGrowAuth) error {
UserPassword: valueTypes.SetStringValue(auth.UserPassword),
}
e.Request.RequestCommon = api.RequestCommon{
Appkey: auth.AppKey,
Appkey: auth.AppKey,
ApiKeyParam: api.ApiKeyParam{
Timestamp: time.Now().UnixMilli(),
Nonce: api.GenerateRandomWord(32),
},
SysCode: "900",
}

Expand Down
21 changes: 13 additions & 8 deletions iSolarCloud/api/struct_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,26 @@ import (
"strings"
)


type Request struct {
RequestCommon
}

type ApiKeyParam struct {
Timestamp int64 `json:"timestamp" required:"true"`
Nonce string `json:"nonce" required:"true"`
}

type RequestCommon struct {
Appkey string `json:"appkey" required:"true"`
Lang string `json:"lang"`
SysCode string `json:"sys_code" required:"true"`
Token string `json:"token"`
UserId string `json:"user_id"`
ValidFlag string `json:"valid_flag"`
Appkey string `json:"appkey" required:"true"`
Lang string `json:"lang"`
SysCode string `json:"sys_code" required:"true"`
Token string `json:"token"`
UserId string `json:"user_id"`
ValidFlag string `json:"valid_flag"`
ApiKeyParam ApiKeyParam `json:"api_key_param"`
// DeviceType string `json:"device_type"`
}


func (req RequestCommon) IsValid() error {
var err error
for range Only.Once {
Expand Down Expand Up @@ -62,6 +66,7 @@ func (req RequestCommon) String() string {
ret += fmt.Sprintf("Lang:\t%s\n", req.Lang)
ret += fmt.Sprintf("SysCode:\t%s\n", req.SysCode)
ret += fmt.Sprintf("ValidFlag:\t%s\n", req.ValidFlag)
ret += fmt.Sprintf("ApiKeyParam:\t%+v\n", req.ApiKeyParam)
return ret
}

Expand Down
152 changes: 150 additions & 2 deletions iSolarCloud/api/web.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
package api

import (
"crypto/aes"
cryptorand "crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"github.com/MickMake/GoSungrow/iSolarCloud/api/GoStruct"
"github.com/MickMake/GoSungrow/iSolarCloud/api/GoStruct/output"
"github.com/MickMake/GoUnify/Only"
"github.com/MickMake/GoUnify/cmdPath"
"github.com/andreburgaud/crypt2go/ecb"
"github.com/andreburgaud/crypt2go/padding"
"io"
"math/rand"
"path/filepath"
"reflect"
"strings"
"time"
"unsafe"

"bytes"
"encoding/json"
Expand Down Expand Up @@ -102,7 +114,116 @@ func (w *Web) Get(endpoint EndPoint) EndPoint {
return endpoint
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)

var src = rand.NewSource(time.Now().UnixNano())

func GenerateRandomWord(n int) string {
b := make([]byte, n)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}

return *(*string)(unsafe.Pointer(&b))
}

func encryptAES(data, key []byte) ([]byte, error) {

if len(key) != 16 {
return nil, fmt.Errorf("key must be 16 characters long")
}

cipher, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("unable to create cipher: %w", err)
}

enc := ecb.NewECBEncrypter(cipher)
padder := padding.NewPkcs7Padding(cipher.BlockSize())
data, err = padder.Pad(data)
if err != nil {
return nil, fmt.Errorf("unable to pad data: %w", err)
}
result := make([]byte, len(data))
enc.CryptBlocks(result, data)
hexResult := make([]byte, hex.EncodedLen(len(result)))
hex.Encode(hexResult, result)

return hexResult, nil
}

func decryptAES(data, key []byte) ([]byte, error) {
encrypted := make([]byte, hex.DecodedLen(len(data)))
if _, err := hex.Decode(encrypted, data); err != nil {
return nil, fmt.Errorf("failed to decode hex: %w", err)
}
cipher, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("unable to create cipher: %w", err)
}
dec := ecb.NewECBDecrypter(cipher)
plaintext := make([]byte, len(encrypted))
dec.CryptBlocks(plaintext, encrypted)
padder := padding.NewPkcs7Padding(cipher.BlockSize())
plaintext, err = padder.Unpad(plaintext)
if err != nil {
return nil, fmt.Errorf("unable to unpad data: %w", err)
}
return plaintext, nil
}

func encryptRSA(value []byte, key *rsa.PublicKey) (string, error) {
encrypted, err := rsa.EncryptPKCS1v15(cryptorand.Reader, key, value)
if err != nil {
return "", fmt.Errorf("failed to encrypt: %w", err)
}
return base64.URLEncoding.EncodeToString(encrypted), nil
}

func extractUserToken(endpoint EndPoint) (string, error) {
r := reflect.ValueOf(endpoint.RequestRef())
token := reflect.Indirect(r).FieldByName("Token").String()
if token == "" {
return "", errors.New("empty token")
}
i := strings.Index(token, "_")
if i == -1 || i > len(token)-1 {
return "", errors.New("malformed token")
}
return token[:i], nil
}

const PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkecphb6vgsBx4LJknKKes-eyj7-RKQ3fikF5B67EObZ3t4moFZyMGuuJPiadYdaxvRqtxyblIlVM7omAasROtKRhtgKwwRxo2a6878qBhTgUVlsqugpI_7ZC9RmO2Rpmr8WzDeAapGANfHN5bVr7G7GYGwIrjvyxMrAVit_oM4wIDAQAB"
const ACCESS_KEY = "9grzgbmxdsp3arfmmgq347xjbza4ysps"

func (w *Web) getApi(endpoint EndPoint) ([]byte, error) {
parsedKey, err := base64.URLEncoding.DecodeString(PUB_KEY)
if err != nil {
return nil, fmt.Errorf("failed to parse pem: %w", err)
}
publicKeyInterface, err := x509.ParsePKIXPublicKey(parsedKey)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}
publicKey, isRSAPublicKey := publicKeyInterface.(*rsa.PublicKey)
if !isRSAPublicKey {
return nil, fmt.Errorf("failed to assert public key: %w", err)
}

for range Only.Once {
request := endpoint.RequestRef()
w.Error = GoStruct.VerifyOptionsRequired(request)
Expand All @@ -127,11 +248,36 @@ func (w *Web) getApi(endpoint EndPoint) ([]byte, error) {
if w.Error != nil {
break
}

w.httpResponse, w.Error = http.Post(postUrl, "application/json", bytes.NewBuffer(j))
randomKey := []byte("web" + GenerateRandomWord(13))
var data []byte
data, w.Error = encryptAES(j, randomKey)
if w.Error != nil {
break
}
var req *http.Request
req, w.Error = http.NewRequest(http.MethodPost, postUrl, bytes.NewBuffer(data))
if w.Error != nil {
break
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-access-key", ACCESS_KEY)
var secretKey string
secretKey, w.Error = encryptRSA(randomKey, publicKey)
if w.Error != nil {
break
}
req.Header.Set("x-random-secret-key", secretKey)

if token, err := extractUserToken(endpoint); err == nil {
var limitObj string
limitObj, w.Error = encryptRSA([]byte(token), publicKey)
if w.Error != nil {
break
}
req.Header.Set("x-limit-obj", limitObj)
}

w.httpResponse, w.Error = w.client.Do(req)

if w.httpResponse.StatusCode == 401 {
w.Error = errors.New(w.httpResponse.Status)
Expand All @@ -153,6 +299,8 @@ func (w *Web) getApi(endpoint EndPoint) ([]byte, error) {
if w.Error != nil {
break
}
w.Body, w.Error = decryptAES(w.Body, randomKey)
w.Body = bytes.TrimSpace(w.Body)
}

return w.Body, w.Error
Expand Down
4 changes: 4 additions & 0 deletions iSolarCloud/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ func (sg *SunGrow) GetEndpoint(ae string) api.EndPoint {
Token: sg.GetToken(),
UserId: sg.GetUserId(),
ValidFlag: "1,3",
ApiKeyParam: api.ApiKeyParam{
Timestamp: time.Now().UnixMilli(),
Nonce: api.GenerateRandomWord(32),
},
})
}
}
Expand Down

0 comments on commit 5bb253c

Please sign in to comment.