From 74ec34597b74586a29a95ec434b8f32ee240e573 Mon Sep 17 00:00:00 2001 From: linquan <349589071@qq.com> Date: Thu, 7 Aug 2025 09:20:37 +0800 Subject: [PATCH] debug --- test/TapOpenId.json => TapOpenId.json | 0 api/v1/game/advertisement.go | 1 - caid.go | 273 +++++++++++ internal/controller/game_pub.go | 1 + internal/serviceGame/advertisement.go | 6 +- .../serviceGame/internal/advertisement.go | 61 ++- internal/serviceGame/internal/caid/caid.go | 331 +++++++++++++ manifest/config/dev_10702/pkcs8_private.pem | 16 + manifest/config/dev_10702/private_key.pem | 18 + manifest/config/dev_10702/pub_for_sdk.cer | 11 + manifest/config/dev_10702/public_for_api.pem | 6 + manifest/config/dev_10702/public_key.der | Bin 0 -> 404 bytes test/caid.go | 436 ++++++++++++++++++ 13 files changed, 1152 insertions(+), 8 deletions(-) rename test/TapOpenId.json => TapOpenId.json (100%) create mode 100644 caid.go create mode 100644 internal/serviceGame/internal/caid/caid.go create mode 100644 manifest/config/dev_10702/pkcs8_private.pem create mode 100644 manifest/config/dev_10702/private_key.pem create mode 100644 manifest/config/dev_10702/pub_for_sdk.cer create mode 100644 manifest/config/dev_10702/public_for_api.pem create mode 100644 manifest/config/dev_10702/public_key.der create mode 100644 test/caid.go diff --git a/test/TapOpenId.json b/TapOpenId.json similarity index 100% rename from test/TapOpenId.json rename to TapOpenId.json diff --git a/api/v1/game/advertisement.go b/api/v1/game/advertisement.go index c36402c..eb9f52b 100644 --- a/api/v1/game/advertisement.go +++ b/api/v1/game/advertisement.go @@ -110,7 +110,6 @@ type AdvertiseHAReq struct { Idfa string `p:"idfa"` PackageName string `p:"package_name"` Properties string `p:"properties"` - UnitId string `p:"unitId"` Caid string `p:"caid"` } diff --git a/caid.go b/caid.go new file mode 100644 index 0000000..0bb9cf4 --- /dev/null +++ b/caid.go @@ -0,0 +1,273 @@ +package main + +import ( + "bytes" + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "fmt" + "github.com/gogf/gf/v2/encoding/gcharset" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "io" + "io/ioutil" + "log" + "math/big" +) + +const pubKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCk2GwklLJO0m4Z5PffSSRlv7jNkQhFyoESukIu2duXN9YaC9G7SCQQnyHYs1Si/W4z/u5a4OXBE5+jZ9W9zmc1wfVelf2vnzTfKABA6AJhlsUXs2UjPQrxNRCgu4rALQ2TlbobqqLpIWtm5rqboXs3yJpRfgaLlJvAdihxx2XYQIDAQAB" +const maxDecryptBlock = 128 + +func main() { + // 设备公共信息 + deviceInfo := map[string]string{ + "bootTimeInSec": "1595643553", + "countryCode": "CN", + "language": "zh-Hans-CN", + "deviceName": "e910dddb2748c36b47fcde5dd720eec1", + "systemVersion": "14.0", + "machine": "iPhone10,3", + "memory": "3955589120", + "disk": "63900340224", + "sysFileTime": "1595214620.383940", + "model": "D22AP", + "timeZone": "28800", + "deviceInitTime": "1632467920.301150749", + } + + // 公钥字符串,注意需要剔除换行符 + //PUBK := pubKeyBase64 // 分配的API接入的公钥字符串 + //privateKey, err := ioutil.ReadFile("manifest/config/dev_10702/public_for_api.pem") + //if err != nil { + // fmt.Println(err) + // return + //} + + // 序列化设备信息为JSON + jsonBytes, err := json.Marshal(deviceInfo) + if err != nil { + fmt.Printf("JSON序列化错误: %v\n", err) + return + } + jsonStr := string(jsonBytes) + + // 加密设备信息 + encryptedDeviceByte, err := encrypt(jsonStr) + if err != nil { + fmt.Printf("加密错误 encrypt: %v\n", err) + return + } + fmt.Printf("加密后的设备信息: encryptedDeviceByte: %s\n", encryptedDeviceByte) + + ctx := context.TODO() + url := "https://caid.china-caa.org/v1.0/get" + data := map[string]interface{}{"dev_id": "10702", "encrypted_device_info": "mbJbTVF1b2m/4i59seIcqAizHHwtt4oMXOXmXKREqaGdVnDKrllvQlNiCt0xpazhcmrzs5aJP9nkEaeuI3omZvdOc1dSJG4oQPPE5X49ErfQL4IT867QzqFPt7AoYtV0DfGarTWwiUPo8JTcIdQBwL7bKgoog93qj8xl/q3y80tgyjVUfQPPWS/UVPfTzMy/lazKm1qY5SIHkm6vJDaUPSC3d4kEQdpicZo1H5cjeCyukP16O5t2PsksTqMJHOg62UIRO6zTNL0Q14+YWfmEaAeUiQrjH8nAfh+Jx3/N3CkcGAJOPrbCRCgfmSIwQ2F6D/pjQd3BNuSKB9W/a+PljRaA54reu0+2L0KJnfhmPXnqltLEclV1PGORYcx5cDK/tbfeXmmvLuPtroH1Dd/+Kc0hz5t2BAHiCh9M6kSqDOXF0muQIM6Mfc473F/uEeiwLZdQ6QbpYdXPYoB+jzQXrDkblpTWhBw4NKdEhR2o2sjVK73YP9BQHmEohzblfHCJ"} + g.Client().SetHeader("Content-Type", "application/json") + g.Client().SetHeader("Cache-Control", "no-cache") + log.Printf("sendMsgHugeAmount - url: %s, data: %s", url, gjson.MustEncodeString(data)) + marshal, _ := json.Marshal(data) + bytes, err := g.Client().Post(ctx, url, string(marshal)) + if err != nil { + return + } + src := string(bytes.ReadAll()) + tmp, err := gcharset.ToUTF8("UTF-8", src) + if err != nil { + return + } + fmt.Println("Deposit - json: ", tmp) + ////tmp, err := SendCaidMsg(ctx, url, data) + //if err != nil { + // fmt.Println("SendCaidMsg err:", err) + // return + //} + //resJson, err := gjson.DecodeToJson(tmp) + //if err != nil { + // fmt.Println("SendCaidMsg DecodeToJson err:", err) + // return + //} + //if resJson != nil && resJson.Get("code").Int() != 0 { + // fmt.Println("SendCaidMsg err:", resJson.Get("message").String()) + // return + //} + caid := "J5LdxnMrcpDiNrn2QLZvCPavphS9nUqu7uwCEjLkEvtP2blwhevgGvQD7AKajkEc+PIC2TuIFxbSGK9Jsm27CrsW446pi+gIIc3OdKB4jqQJoDD77BbJC3I105DnsEwgR8uLvSVy0NgqFq+rf4GRYwp93Jy2eZdDKkS+Y0BgTEQkedK1P29hyYEELLQzvJrq9XlwfYx1QcGGcofZmq56B65IbQQfRvoXAiSl2cm12qFkpD8KbPmvy66xE6yu3SFAMC6iAEdfW4W8hz0Qv9Bht2nhDxsm4c39z1mU41s1oP5lJ5kkUl4yU3NWRO19jIYOm8lMJb19oDc+weBaMkgIbQ==" + + fmt.Println("Deposit - caid: ", caid) + + //encryptedDeviceInfo, err := encryptWithPublicKey(jsonStr, vm.publicKey) + //if err != nil { + // fmt.Printf("加密错误 encryptWithPublicKey: %v\n", err) + // return + //} + + // 将encryptedDeviceInfo填入请求中的encrypted_device_info字段 + + // 解密响应数据示例 + // 假设从响应中获取的data字段值 + + //fmt.Printf("解密后的响应数据: %s\n ,decryptedByte: %s\n", decryptedData, string(decryptedByte)) + +} + +// 使用公钥加密数据 +func encryptWithPublicKey(data string, rsaPubKey *rsa.PublicKey) (string, error) { + //// 解码Base64格式的公钥 + //pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKeyStr) + //if err != nil { + // return "", fmt.Errorf("公钥Base64解码错误: %v", err) + //} + // + //// 解析公钥 + //publicKey, err := x509.ParsePKIXPublicKey(pubKeyBytes) + //if err != nil { + // return "", fmt.Errorf("公钥解析错误: %v", err) + //} + // + //// 断言为RSA公钥 + //rsaPubKey, ok := publicKey.(*rsa.PublicKey) + //if !ok { + // return "", errors.New("不是RSA公钥") + //} + + // 计算最大加密块大小 + maxEncryptBlock := rsaPubKey.Size() - 42 // PKCS#1 OAEP加密需要预留42字节 + + dataBytes := []byte(data) + dataLen := len(dataBytes) + var encryptedBytes []byte + + // 分段加密 + for i := 0; i < dataLen; i += maxEncryptBlock { + end := i + maxEncryptBlock + if end > dataLen { + end = dataLen + } + + // 加密当前块 + encryptedBlock, err := rsa.EncryptOAEP( + nil, + rand.Reader, + rsaPubKey, + dataBytes[i:end], + nil, + ) + if err != nil { + return "", fmt.Errorf("加密错误: %v", err) + } + + encryptedBytes = append(encryptedBytes, encryptedBlock...) + } + + // Base64编码加密结果 + return base64.StdEncoding.EncodeToString(encryptedBytes), nil +} + +func ImportSPKIPublicKeyPEM() *rsa.PublicKey { + pubKeyBytes, err := ioutil.ReadFile("manifest/config/dev_10702/public_for_api.pem") + if err != nil { + fmt.Println(err) + } + fmt.Printf("encrypt pubKeyBytes: %s\n", string(pubKeyBytes)) + body, _ := pem.Decode(pubKeyBytes) + fmt.Printf(" body.Bytes : %s\n byte: %s\n", body.Type, body.Bytes) + publicKey, _ := x509.ParsePKIXPublicKey(body.Bytes) + if publicKey, ok := publicKey.(*rsa.PublicKey); ok { + return publicKey + } else { + return nil + } +} +func encrypt(data string) (string, error) { + //raw, err := base64.StdEncoding.DecodeString(data) + //if err != nil { + // return nil, fmt.Errorf("base64 decode %w: %s", err, data) + //} + + pubKey := ImportSPKIPublicKeyPEM() + fmt.Printf("data: len: %d\n pubkey: %v\n", len(data), pubKey) + maxEncryptBlock := 117 + //ciphertextBytes, _ := base64.StdEncoding.DecodeString(data) + reader := bytes.NewReader([]byte(data)) + var writer bytes.Buffer + ciphertextBytesChunk := make([]byte, maxEncryptBlock) + fmt.Println("chunk: ", len([]byte(data)), len(ciphertextBytesChunk)) + for { + n, _ := io.ReadFull(reader, ciphertextBytesChunk) + if n == 0 { + fmt.Println("chunk: n ", n) + break + } + encryptChunk(ciphertextBytesChunk, &writer, pubKey) + fmt.Println("chunk: ", len(ciphertextBytesChunk)) + } + // Concatenate decrypted signature chunks + decryptedData := writer.String() + fmt.Println(decryptedData) + //reader := bytes.NewReader([]byte(data)) + //var writer bytes.Buffer + //chunk := make([]byte, maxEncryptBlock) + //fmt.Println("chunk: ", len(chunk)) + //for { + // n, err := io.ReadFull(reader, chunk) + // if err != nil && errors.Is(err, io.ErrUnexpectedEOF) { + // return nil, fmt.Errorf("read encrypt data: %w", err) + // } + // if n == 0 { + // break + // } + // encryptChunk(chunk, &writer, pubKey) + //} + output := bytes.TrimRight(bytes.TrimLeft(writer.Bytes(), "\x00"), "\n") + if bytes.Count(output, []byte("\x00")) > 0 { + after := bytes.ReplaceAll(output, []byte("\x00"), []byte{}) + log.Println("WARN: remove \x00 from caid's response", "before", output, "after", after) + output = after + } + //return output, nil + return string(output), nil +} +func encryptChunk(ciphertextBytesChunk []byte, writer *bytes.Buffer, pubKey *rsa.PublicKey) { + // Decrypt each signature chunk + ciphertextInt := new(big.Int) + ciphertextInt.SetBytes(ciphertextBytesChunk) + decryptedPaddedInt := doEncrypt(new(big.Int), pubKey, ciphertextInt) + // Remove padding + decryptedPaddedBytes := make([]byte, pubKey.Size()) + decryptedPaddedInt.FillBytes(decryptedPaddedBytes) + start := bytes.Index(decryptedPaddedBytes[1:], []byte{0}) + 1 // // 0001FF...FF00: Find index after 2nd 0x00 + decryptedBytes := decryptedPaddedBytes[start:] + // Write decrypted signature chunk + writer.Write(decryptedBytes) +} + +func doEncrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int { + // Textbook RSA + e := big.NewInt(int64(pub.E)) + c.Exp(m, e, pub.N) + return c +} + +//func encryptChunk(chunk []byte, writer *bytes.Buffer, pubKey *rsa.PublicKey) { +// // Decrypt each signature chunk +// ciphertextInt := new(big.Int) +// ciphertextInt.SetBytes(chunk) +// decryptedPaddedInt := doEncrypt(new(big.Int), pubKey, ciphertextInt) +// // Remove padding +// decryptedPaddedBytes := make([]byte, pubKey.Size()) +// decryptedPaddedInt.FillBytes(decryptedPaddedBytes) +// start := bytes.Index(decryptedPaddedBytes[1:], []byte{0}) + 1 // // 0001FF...FF00: Find index after 2nd 0x00 +// decryptedBytes := decryptedPaddedBytes[start:] +// // Write decrypted signature chunk +// writer.Write(decryptedBytes) +//} +// +//func doEncrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int { +// // Textbook RSA +// e := big.NewInt(int64(pub.E)) +// c.Exp(m, e, pub.N) +// return c +//} diff --git a/internal/controller/game_pub.go b/internal/controller/game_pub.go index 81a25e2..2c7786e 100644 --- a/internal/controller/game_pub.go +++ b/internal/controller/game_pub.go @@ -138,6 +138,7 @@ func (c *pubController) ConversionHugeAmount(ctx context.Context, req *game.CSHA func (c *pubController) AdvertiseHugeAmount(ctx context.Context, req *game.AdvertiseHAReq) (res *game.AdvertiseHARes, err error) { //log.Print("AdvertiseHugeAmount", gjson.MustEncodeString(req)) + //return res, err = serviceGame.Advertisement().AdvertiseHugeAmount(ctx, req) return } diff --git a/internal/serviceGame/advertisement.go b/internal/serviceGame/advertisement.go index bed99d1..05d104f 100644 --- a/internal/serviceGame/advertisement.go +++ b/internal/serviceGame/advertisement.go @@ -61,7 +61,7 @@ func (g *advertisementImpl) AdvertiseHugeAmount(ctx context.Context, req *game.A return } -func (g *advertisementImpl) AdvertiseHugeAmount1(ctx context.Context, androidId, idfa, os, callBack, timestamp, caidlist, ip string) (err error) { +func (g *advertisementImpl) AdvertiseHugeAmount1(ctx context.Context, androidId, idfa, os, callBack, timestamp, caidList, ip string) (err error) { osInt, err := strconv.Atoi(os) if err != nil { return @@ -76,9 +76,9 @@ func (g *advertisementImpl) AdvertiseHugeAmount1(ctx context.Context, androidId, return } caid := "" - if caidlist != "" { + if caidList != "" { var list []map[string]string - _ = json.Unmarshal([]byte(caidlist), &list) + _ = json.Unmarshal([]byte(caidList), &list) versionNow := int64(0) for _, v := range list { version, _ := strconv.ParseInt(v["version"], 10, 64) diff --git a/internal/serviceGame/internal/advertisement.go b/internal/serviceGame/internal/advertisement.go index 13a83cc..2da7579 100644 --- a/internal/serviceGame/internal/advertisement.go +++ b/internal/serviceGame/internal/advertisement.go @@ -17,6 +17,7 @@ import ( "tyj_admin/internal/dao" "tyj_admin/internal/model/do" "tyj_admin/internal/model/entity" + "tyj_admin/internal/serviceGame/internal/caid" ) func Advertise(ctx context.Context, req *game.ADReq) (res *game.ADRes, err error) { @@ -303,7 +304,9 @@ func ConversionHugeAmount(ctx context.Context, req *game.CSHAReq) (res *game.CSH resJson, err := gjson.DecodeToJson(tmp) if resJson != nil && resJson.Get("code").Int() != 0 { err = errors.New(resJson.Get("message").String()) - } + } /*else if resJson.Get("code").Int() == 0 { + dao.AdvertisementOceanegine.Ctx(ctx).Where("id=?", adData[0].Id).Update(do.AdvertisementOceanegine{}) + }*/ return } @@ -315,19 +318,51 @@ func AdvertiseHugeAmount(ctx context.Context, req *game.AdvertiseHAReq) (res *ga if req.Platform == "iphoneplayer" { req.Platform = "ios" } + go HugeAmount(ctx, req) return } func HugeAmount(ctx context.Context, req *game.AdvertiseHAReq) { + if req.Platform == "ios1" { + //url := "https://caid.china-caa.org/v1.0/get" + //data := map[string]interface{}{"dev_id": "10702", "encrypted_device_info": caid.EncryptDeviceInfo()} + //tmp, err := SendCaidMsg(ctx, url, data) + //if err != nil { + // fmt.Println("SendCaidMsg err:", err) + // return + //} + //resJson, err := gjson.DecodeToJson(tmp) + //if err != nil { + // fmt.Println("SendCaidMsg DecodeToJson err:", err) + // return + //} + //if resJson != nil && resJson.Get("code").Int() != 0 { + // fmt.Println("SendCaidMsg err:", resJson.Get("message").String()) + // return + //} + //req.Caid = resJson.Get("data").String() + if req.Caid != "" { + decryptedByte, err := caid.Decrypt(req.Caid) + if err != nil { + log.Printf("Decrypt err: %s", err.Error()) + return + } + req.Caid = string(decryptedByte) + } + + log.Printf("HugeAmount req2: %s", gjson.MustEncodeString(req)) + return + } + req2 := game.CSHAReq{ Platform: req.Platform, Id: req.Id, Idfa: req.Idfa, EventType: req.EventType, Properties: req.Properties, - UnitId: req.UnitId, Caid: req.Caid, + //UnitId: req.UnitId, } req2.Id = req.Id _, err := ConversionHugeAmount(ctx, &req2) @@ -338,9 +373,9 @@ func HugeAmount(ctx context.Context, req *game.AdvertiseHAReq) { req1 := game.ATHAReq{ Platform: req.Platform, PackageName: req.PackageName, - Idfa: req.Idfa, - UnitId: req.UnitId, Caid: req.Caid, + Idfa: req.Idfa, + //UnitId: req.UnitId, } if req.Platform == "android" { req1.AndroidId = req.Id @@ -468,3 +503,21 @@ func GetCostReport(ctx context.Context, req *game.GetCostReportReq) (res *game.G } return res, err } + +func SendCaidMsg(ctx context.Context, url string, data map[string]interface{}) (string, error) { + g.Client().SetHeader("Content-Type", "application/json") + g.Client().SetHeader("Cache-Control", "no-cache") + log.Printf("sendMsgHugeAmount - url: %s, data: %s", url, gjson.MustEncodeString(data)) + marshal, _ := json.Marshal(data) + bytes, err := g.Client().Post(ctx, url, string(marshal)) + if err != nil { + return "", err + } + src := string(bytes.ReadAll()) + tmp, err := gcharset.ToUTF8("UTF-8", src) + if err != nil { + return "", err + } + fmt.Println("Deposit - json: ", tmp) + return tmp, err +} diff --git a/internal/serviceGame/internal/caid/caid.go b/internal/serviceGame/internal/caid/caid.go new file mode 100644 index 0000000..186266f --- /dev/null +++ b/internal/serviceGame/internal/caid/caid.go @@ -0,0 +1,331 @@ +package caid + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "math/big" +) + +const maxDecryptBlock = 128 + +// +//func Decrypt(data string) ([]byte, error) { +// raw, err := base64.StdEncoding.DecodeString(data) +// if err != nil { +// return nil, fmt.Errorf("base64 decode %w: %s", err, data) +// } +// // 初始化ViewModel +// vm, err := NewViewModel() +// if err != nil { +// log.Printf("初始化失败: %v", err) +// return nil, fmt.Errorf("base64 decode %w: %s", err, data) +// } +// reader := bytes.NewReader(raw) +// var writer bytes.Buffer +// chunk := make([]byte, maxDecryptBlock) +// for { +// n, err := io.ReadFull(reader, chunk) +// if err != nil && errors.Is(err, io.ErrUnexpectedEOF) { +// return nil, fmt.Errorf("read decrypted data: %w", err) +// } +// if n == 0 { +// break +// } +// pubKey := vm.publicKey +// decryptChunk(chunk, &writer, pubKey) +// } +// output := bytes.TrimRight(bytes.TrimLeft(writer.Bytes(), "\x00"), "\n") +// if bytes.Count(output, []byte("\x00")) > 0 { +// after := bytes.ReplaceAll(output, []byte("\x00"), []byte{}) +// log.Println("WARN: remove \x00 from caid's response", "before", output, "after", after) +// output = after +// } +// return output, nil +//} +// +//func decryptChunk(chunk []byte, writer *bytes.Buffer, pubKey *rsa.PublicKey) { +// // Decrypt each signature chunk +// ciphertextInt := new(big.Int) +// ciphertextInt.SetBytes(chunk) +// decryptedPaddedInt := doDecrypt(new(big.Int), pubKey, ciphertextInt) +// // Remove padding +// decryptedPaddedBytes := make([]byte, pubKey.Size()) +// decryptedPaddedInt.FillBytes(decryptedPaddedBytes) +// start := bytes.Index(decryptedPaddedBytes[1:], []byte{0}) + 1 // // 0001FF...FF00: Find index after 2nd 0x00 +// decryptedBytes := decryptedPaddedBytes[start:] +// // Write decrypted signature chunk +// writer.Write(decryptedBytes) +//} +// +//func doDecrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int { +// // Textbook RSA +// e := big.NewInt(int64(pub.E)) +// c.Exp(m, e, pub.N) +// return c +//} + +// ViewModel 处理业务逻辑的视图模型 +type ViewModel struct { + publicKey *rsa.PublicKey + privateKey *rsa.PrivateKey +} + +// NewViewModel 初始化视图模型 +func NewViewModel() (*ViewModel, error) { + pubKeyBytes, err := ioutil.ReadFile("manifest/config/dev_10702/public_for_api.pem") + if err != nil { + fmt.Println(err) + } + fmt.Printf("pubKeyBytes: %s", pubKeyBytes) + block, _ := pem.Decode(pubKeyBytes) + if block != nil { + pubKeyBytes = block.Bytes + } + fmt.Printf("pubKeyBytes: %s", fmt.Sprint(pubKeyBytes)) + pubKey, err := x509.ParsePKIXPublicKey(pubKeyBytes) + if err != nil { + return nil, fmt.Errorf("解析公钥失败: %w", err) + } + rsaPubKey, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, errors.New("无效的RSA公钥类型1") + } + + return &ViewModel{publicKey: rsaPubKey}, nil +} + +// EncryptDeviceInfo 加密设备信息 +func (vm *ViewModel) EncryptDeviceInfo(deviceInfo map[string]string) (string, error) { + jsonData, err := json.Marshal(deviceInfo) + if err != nil { + return "", fmt.Errorf("JSON序列化失败: %w", err) + } + + plaintext := string(jsonData) + maxBlockSize := vm.publicKey.Size() - 11 // PKCS#1 v1.5填充最大块大小 + fmt.Println("EncryptDeviceInfo", maxBlockSize, len(jsonData), len(plaintext)) + var encryptedBlocks [][]byte + + for i := 0; i < len(plaintext); i += maxBlockSize { + end := i + maxBlockSize + if end > len(plaintext) { + end = len(plaintext) + } + + block := []byte(plaintext[i:end]) + encryptedBlock, err := rsa.EncryptPKCS1v15(rand.Reader, vm.publicKey, block) + if err != nil { + return "", fmt.Errorf("RSA加密失败: %w", err) + } + + encryptedBlocks = append(encryptedBlocks, encryptedBlock) + fmt.Printf("EncryptDeviceInfo encryptedBlocks: %s, encryptedBlock: %s, block: %s \n", encryptedBlocks, string(encryptedBlock), string(block)) + } + + return base64.StdEncoding.EncodeToString(bytesJoin(encryptedBlocks)), nil +} + +// DecryptResponse 解密响应数据 +func (vm *ViewModel) DecryptResponse(ciphertextBase64 string) (string, error) { + ciphertextBytes, err := base64.StdEncoding.DecodeString(ciphertextBase64) + if err != nil { + return "", fmt.Errorf("响应数据Base64解码失败: %w", err) + } + + maxBlockSize := vm.privateKey.Size() + var decryptedBlocks [][]byte + + for i := 0; i < len(ciphertextBytes); i += maxBlockSize { + end := i + maxBlockSize + if end > len(ciphertextBytes) { + end = len(ciphertextBytes) + } + + block := ciphertextBytes[i:end] + decryptedBlock, err := rsa.DecryptPKCS1v15(rand.Reader, vm.privateKey, block) + if err != nil { + return "", fmt.Errorf("RSA解密失败: %w", err) + } + decryptedBlocks = append(decryptedBlocks, decryptedBlock) + } + + return string(bytesJoin(decryptedBlocks)), nil +} + +// 辅助函数:合并字节切片 +func bytesJoin(s [][]byte) []byte { + var totalLen int + for _, b := range s { + totalLen += len(b) + } + res := make([]byte, totalLen) + for i, b := range s { + copy(res[i:], b) + } + return res +} + +func EncryptDeviceInfo() string { + // 设备公共信息 + deviceInfo := map[string]string{ + "bootTimeInSec": "1595643553", + "countryCode": "CN", + "language": "zh-Hans-CN", + "deviceName": "e910dddb2748c36b47fcde5dd720eec1", + "systemVersion": "14.0", + "machine": "iPhone10,3", + "memory": "3955589120", + "disk": "63900340224", + "sysFileTime": "1595214620.383940", + "model": "D22AP", + "timeZone": "28800", + "deviceInitTime": "1632467920.301150749", + } + + // 初始化ViewModel + vm, err := NewViewModel() + if err != nil { + log.Printf("初始化失败: %v", err) + return "" + } + + // 加密设备信息 + encryptedDeviceInfo, err := vm.EncryptDeviceInfo(deviceInfo) + if err != nil { + log.Printf("设备信息加密失败: %v", err) + return "" + } + fmt.Printf("加密设备信息: %s\n", encryptedDeviceInfo) + + // 模拟响应解密(使用加密结果模拟响应数据) + //responseData := encryptedDeviceInfo // 实际应从接口获取encrypted_device_info字段 + return encryptedDeviceInfo +} + +func main1() { + // 设备公共信息 + deviceInfo := map[string]string{ + "bootTimeInSec": "1595643553", + "countryCode": "CN", + "language": "zh-Hans-CN", + "deviceName": "e910dddb2748c36b47fcde5dd720eec1", + "systemVersion": "14.0", + "machine": "iPhone10,3", + "memory": "3955589120", + "disk": "63900340224", + "sysFileTime": "1595214620.383940", + "model": "D22AP", + "timeZone": "28800", + "deviceInitTime": "1632467920.301150749", + } + + // 初始化ViewModel + vm, err := NewViewModel() + if err != nil { + log.Fatalf("初始化失败: %v", err) + } + + // 加密设备信息 + encryptedDeviceInfo, err := vm.EncryptDeviceInfo(deviceInfo) + if err != nil { + log.Fatalf("设备信息加密失败: %v", err) + } + fmt.Printf("加密设备信息: %s\n", encryptedDeviceInfo) + + // 模拟响应解密(使用加密结果模拟响应数据) + responseData := encryptedDeviceInfo // 实际应从接口获取encrypted_device_info字段 + + // 解密响应数据 + decryptedData, err := vm.DecryptResponse(responseData) + if err != nil { + log.Fatalf("响应解密失败: %v", err) + } + fmt.Printf("解密后数据: %s\n", decryptedData) + + // 解析JSON数组(示例) + var caidsArray []interface{} + if err := json.Unmarshal([]byte(decryptedData), &caidsArray); err != nil { + log.Fatalf("JSON解析失败: %v", err) + } + fmt.Printf("CAIDs数组: %+v\n", caidsArray) +} + +//const maxDecryptBlock = 128 + +func Decrypt(data string) ([]byte, error) { + raw, err := base64.StdEncoding.DecodeString(data) + if err != nil { + return nil, fmt.Errorf("base64 decode %w: %s", err, data) + } + + reader := bytes.NewReader(raw) + var writer bytes.Buffer + chunk := make([]byte, maxDecryptBlock) + pubKeyBytes, err := ioutil.ReadFile("manifest/config/dev_10702/public_for_api.pem") + if err != nil { + fmt.Println(err) + } + fmt.Printf("pubKeyBytes: %s\n", pubKeyBytes) + block, _ := pem.Decode(pubKeyBytes) + if block != nil { + pubKeyBytes = block.Bytes + } + fmt.Printf("pubKeyBytes: %s\n", fmt.Sprint(pubKeyBytes)) + pubKey, err := x509.ParsePKIXPublicKey(pubKeyBytes) + if err != nil { + return nil, fmt.Errorf("解析公钥失败: %w", err) + } + rsaPubKey, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, errors.New("无效的RSA公钥类型1") + } + for { + n, err := io.ReadFull(reader, chunk) + if err != nil && errors.Is(err, io.ErrUnexpectedEOF) { + return nil, fmt.Errorf("read decrypted data: %w", err) + } + if n == 0 { + break + } + decryptChunk(chunk, &writer, rsaPubKey) + } + output := bytes.TrimRight(bytes.TrimLeft(writer.Bytes(), "\x00"), "\n") + if bytes.Count(output, []byte("\x00")) > 0 { + after := bytes.ReplaceAll(output, []byte("\x00"), []byte{}) + log.Println("WARN: remove \x00 from caid's response", "before", output, "after", after) + output = after + } + fmt.Printf(" output: %s\n", string(output)) + return output, nil +} + +func decryptChunk(chunk []byte, writer *bytes.Buffer, pubKey *rsa.PublicKey) { + // Decrypt each signature chunk + ciphertextInt := new(big.Int) + ciphertextInt.SetBytes(chunk) + decryptedPaddedInt := doDecrypt(new(big.Int), pubKey, ciphertextInt) + // Remove padding + decryptedPaddedBytes := make([]byte, pubKey.Size()) + decryptedPaddedInt.FillBytes(decryptedPaddedBytes) + start := bytes.Index(decryptedPaddedBytes[1:], []byte{0}) + 1 // // 0001FF...FF00: Find index after 2nd 0x00 + decryptedBytes := decryptedPaddedBytes[start:] + // Write decrypted signature chunk + writer.Write(decryptedBytes) +} + +func doDecrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int { + // Textbook RSA + e := big.NewInt(int64(pub.E)) + c.Exp(m, e, pub.N) + return c +} diff --git a/manifest/config/dev_10702/pkcs8_private.pem b/manifest/config/dev_10702/pkcs8_private.pem new file mode 100644 index 0000000..f4bfc54 --- /dev/null +++ b/manifest/config/dev_10702/pkcs8_private.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMKTYbCSUsk7Sbhn +k999JJGW/uM2RCEXKgRK6Qi7Z25c31hoL0btIJBCfIdizVKL9bjP+7lrg5cETn6N +n1b3OZzXB9V6V/a+fNN8oAEDoAmGWxRezZSM9CvE1EKC7isAtDZOVuhuqoukha2b +mupuhezfImlF+BouUm8B2KHHHZdhAgMBAAECgYEAtD9hpPe39zCUF17kTomYYcKW +Npejv1+9DaLzg6JPq54fTL+e5D5xBxKAV87AU/LR27XYBCnEChb0PCon7KEzXSjr +6Mtuv4jeSbL0urTepcHRLzoKpFfwZLC38CrB06DKcJXypxyc482+3heTU3sadkix +nOJhBro4KkyPsErhwo0CQQDlvqlhZhkvHCy+u7vtj6UQGbu7b7UWCX2xZnVpmIa0 +cAWNLOJmWPJali5ee5S5hZGdHUrJyQ8Trp4QCTjXkp/rAkEA2M/TRoQ+fJnw9GLw +4E3I8I+UFqOepJn+uVhM+uX/tHTcugyxJAsk+QOmOXgO4Jkb5al984EKdTcNfTS0 +PUTe4wJANtrvVnIqUTVI+cGZfX9uygla6cYiVsCtYk40eqIQh8S3jp3I8OcL9tUk +/SpEuIdL3VfBI6z+DJUE6I9LIy2/QQJACysphwho76I+d1hhcCyRnVLIHiJvmasV +JBcYYBRZB8K9XBgrR+ALF4jIl01H9unsNfh1NIYBM+iSGVENt9pEYQJAZHHQ/xwz ++QBFsH8lUKTwP1KyZXAadnfDEBlaaoiT6OsgnuD+JWQv2ztha42nv+49qZfACttY +Nz+3XXhd9HNbgw== +-----END PRIVATE KEY----- diff --git a/manifest/config/dev_10702/private_key.pem b/manifest/config/dev_10702/private_key.pem new file mode 100644 index 0000000..543fb3d --- /dev/null +++ b/manifest/config/dev_10702/private_key.pem @@ -0,0 +1,18 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI42H/iuHd7KYCAggA +MB0GCWCGSAFlAwQBKgQQtgiHI4QGJWDAP/M32pd7EASCAoAOaP/S8G1+W6oHybzr +aQB2bfCFmFHKD7D5yf5t7gP9aWlG4EPWuIKMpmnXYZenSwE6ZKaezlI4SCmP0qEK +oQ1EAbPMSWS6zfmsXpChTYVUsG+n1049RiQnlqIp+axmSwXJ9yRXCYU3sGtSDDOe +BfCj2CYj1gpVDhjQDwE7TKI2Vk1Pl5Qv2LxpNza71axliU3arLtq7voRsreHK2dQ +8gqAOZle3xpGhk62aoC6B+jQJ8Ha36Uex1HH7nG/eVUfqkocyVfCe1rYaEbf2IbM +xRCF29lPFhBi96ACQm0YMDJJakJ5zYtBJIN1a1fUFxeZI2OLkrb7goIC7vrU1Ffu +q3nVrFtBgYXdOcExzXR7hK0yW/NYE+UsIi1Mr76x+od9tkWkfIuDnUyRsJMkskFv +doKw0xOdo9SINlC+mEJctrNtqBM1DqyaahWqSSh/6LXfF7hYoMXAO07v/mglXP9l +GeJGUE4/wISO8t6N1o21Xl4pHu6XpuFM77lLRP9mL7bD3MKRaHtmk8/uh4wDamSf +GEakQaJ4le1te01NaynAPGbVJpk9EEEvEiqeFPCtgW8fFUuCdq0QdXEbvN3PX3wp +38k9Yc4rTAc51+7+6l1VTLlIz1xGKPAhzOOfqDzH4kCXuilFyXJwhI/h4s2vZ56P +mp0DKHGZ+nim5VPVOs5IYpG5RBTMikmrb5NQZGEHRzYUD3cFx4ehnWAnyptjlS5R +hzlb/1ofuhiwm7STQuYiE+1CgvB8xmLPWNbYv0JNdDqVk63fvyj1GTZsI7F5MTx1 +EZ0s0plncM4IfdZlvv06ZtXVd2M6OxxMYjPyN7nFQo5kLolEmAwQDxJdFGJo/n4C +9UZ1 +-----END ENCRYPTED PRIVATE KEY----- diff --git a/manifest/config/dev_10702/pub_for_sdk.cer b/manifest/config/dev_10702/pub_for_sdk.cer new file mode 100644 index 0000000..dc66c75 --- /dev/null +++ b/manifest/config/dev_10702/pub_for_sdk.cer @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBkDCB+gIJAJhAVB+RxnKbMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNVBAYTAkNO +MB4XDTI1MDMxMDA5MzUxNFoXDTI1MDQwOTA5MzUxNFowDTELMAkGA1UEBhMCQ04w +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMKTYbCSUsk7Sbhnk999JJGW/uM2 +RCEXKgRK6Qi7Z25c31hoL0btIJBCfIdizVKL9bjP+7lrg5cETn6Nn1b3OZzXB9V6 +V/a+fNN8oAEDoAmGWxRezZSM9CvE1EKC7isAtDZOVuhuqoukha2bmupuhezfImlF ++BouUm8B2KHHHZdhAgMBAAEwDQYJKoZIhvcNAQELBQADgYEATv0xjo7a/opVlI2e +GmKa7o/xi9SXwgPFjo/70JT7UHLlS13s3h6iFMRw+z7M4Jxe/MeiA28YbzDeQHDp +p4czxirvBOjfGEnuqc8nwZBLX1CaIGaooyzoS60zrGVdS9xPU5ICysq/IkF1Af/5 +719PDABMAAVH5I62Lmzn6pyWCEo= +-----END CERTIFICATE----- diff --git a/manifest/config/dev_10702/public_for_api.pem b/manifest/config/dev_10702/public_for_api.pem new file mode 100644 index 0000000..96972c5 --- /dev/null +++ b/manifest/config/dev_10702/public_for_api.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCk2GwklLJO0m4Z5PffSSRlv7j +NkQhFyoESukIu2duXN9YaC9G7SCQQnyHYs1Si/W4z/u5a4OXBE5+jZ9W9zmc1wfV +elf2vnzTfKABA6AJhlsUXs2UjPQrxNRCgu4rALQ2TlbobqqLpIWtm5rqboXs3yJp +RfgaLlJvAdihxx2XYQIDAQAB +-----END PUBLIC KEY----- diff --git a/manifest/config/dev_10702/public_key.der b/manifest/config/dev_10702/public_key.der new file mode 100644 index 0000000000000000000000000000000000000000..085425af5906179173ac316f17d05f713928ffe7 GIT binary patch literal 404 zcmXqLVw_;m_=|~?VTMD9{KR8LvkiFJIJMe5+P?ELGIFyr81Nc$8*s8QhqABm_n;M!#fw?9ImQXIb^2Yhd<}tD|FgNxx7&LY=H8wIFnw+>{QqW0j z&mHNL@7JnKoc8arnTw*h7K_(Qj@{{bG4~@f^xfVnOmM1cPdXda{dLFr-#fFLr?dFg z_0A9bZaL>V`_-!OZ~JO4*DPRUUclKFEfRNjO3xSVBUhZ7-f1&zG4l(1k+-UQN$c9# zvtH%3zPYcI>H0%TFDRe!#=_&W(-WDP85tOnod@(TGtgare+~QkZvE>Dozgo`Drwfc z{*T>PrXONH+SmX4!j#_uMNhqB-`ta1ByyzSx80csbK?FSU&Nd*k#BI%q2T56cH?7O z?^#~lm+*YI^1S-N3EuGmvlP-+EY^A9z1Db5YOMDi|KLeXr%vrxax7*1|MPvkKM#Ws T1FQR!zHNFr&tJ`%#^D73v>TxY literal 0 HcmV?d00001 diff --git a/test/caid.go b/test/caid.go new file mode 100644 index 0000000..976043a --- /dev/null +++ b/test/caid.go @@ -0,0 +1,436 @@ +package main + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "math/big" +) + +const pubKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCk2GwklLJO0m4Z5PffSSRlv7jNkQhFyoESukIu2duXN9YaC9G7SCQQnyHYs1Si/W4z/u5a4OXBE5+jZ9W9zmc1wfVelf2vnzTfKABA6AJhlsUXs2UjPQrxNRCgu4rALQ2TlbobqqLpIWtm5rqboXs3yJpRfgaLlJvAdihxx2XYQIDAQAB" +const maxDecryptBlock = 256 + +func decrypt(data string) ([]byte, error) { + raw, err := base64.StdEncoding.DecodeString(data) + if err != nil { + return nil, fmt.Errorf("base64 decode %w: %s", err, data) + } + + // 初始化ViewModel + vm, err := NewViewModel() + if err != nil { + //log.Fatalf("初始化失败: %v", err) + //} + //// 初始化ViewModel + //vm, err := NewViewModel(pubKeyBase64) + //if err != nil { + log.Printf("初始化失败: %v", err) + return nil, fmt.Errorf("base64 decode %w: %s", err, data) + } + reader := bytes.NewReader(raw) + var writer bytes.Buffer + chunk := make([]byte, maxDecryptBlock) + for { + n, err := io.ReadFull(reader, chunk) + if err != nil && errors.Is(err, io.ErrUnexpectedEOF) { + return nil, fmt.Errorf("read decrypted data: %w", err) + } + if n == 0 { + break + } + pubKey := vm.publicKey + decryptChunk(chunk, &writer, pubKey) + } + output := bytes.TrimRight(bytes.TrimLeft(writer.Bytes(), "\x00"), "\n") + if bytes.Count(output, []byte("\x00")) > 0 { + after := bytes.ReplaceAll(output, []byte("\x00"), []byte{}) + log.Println("WARN: remove \x00 from caid's response", "before", output, "after", after) + output = after + } + return output, nil +} + +func decryptChunk(chunk []byte, writer *bytes.Buffer, pubKey *rsa.PublicKey) { + // Decrypt each signature chunk + ciphertextInt := new(big.Int) + ciphertextInt.SetBytes(chunk) + decryptedPaddedInt := doDecrypt(new(big.Int), pubKey, ciphertextInt) + // Remove padding + decryptedPaddedBytes := make([]byte, pubKey.Size()) + decryptedPaddedInt.FillBytes(decryptedPaddedBytes) + start := bytes.Index(decryptedPaddedBytes[1:], []byte{0}) + 1 // // 0001FF...FF00: Find index after 2nd 0x00 + decryptedBytes := decryptedPaddedBytes[start:] + // Write decrypted signature chunk + writer.Write(decryptedBytes) +} + +func doDecrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int { + // Textbook RSA + e := big.NewInt(int64(pub.E)) + c.Exp(m, e, pub.N) + return c +} + +// ViewModel 处理业务逻辑的视图模型 +type ViewModel struct { + publicKey *rsa.PublicKey + privateKey *rsa.PrivateKey +} + +// NewViewModel 初始化视图模型 +func NewViewModel() (*ViewModel, error) { + pubKeyBytes, err := ioutil.ReadFile("manifest/config/dev_10702/public_for_api.pem") + if err != nil { + fmt.Println(err) + } + fmt.Printf("pubKeyBytes: %s", pubKeyBytes) + block, _ := pem.Decode(pubKeyBytes) + if block != nil { + pubKeyBytes = block.Bytes + } + fmt.Printf("pubKeyBytes: %s", fmt.Sprint(pubKeyBytes)) + pubKey, err := x509.ParsePKIXPublicKey(pubKeyBytes) + if err != nil { + return nil, fmt.Errorf("解析公钥失败: %w", err) + } + rsaPubKey, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, errors.New("无效的RSA公钥类型1") + } + priKeyBytes, err := ioutil.ReadFile("manifest/config/dev_10702/pkcs8_private.pem") + if err != nil { + fmt.Println(err) + } + fmt.Printf("priKeyBytes: %s", priKeyBytes) + block1, _ := pem.Decode(priKeyBytes) + if block1 != nil { + priKeyBytes = block1.Bytes + } + fmt.Printf("priKeyBytes: %s", fmt.Sprint(priKeyBytes)) + priKey, err := x509.ParsePKCS8PrivateKey(priKeyBytes) + if err != nil { + return nil, fmt.Errorf("解析私钥失败: %w", err) + } + + rsaPriKey, ok := priKey.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("无效的RSA私钥类型2") + } + + return &ViewModel{publicKey: rsaPubKey, privateKey: rsaPriKey}, nil +} + +// EncryptDeviceInfo 加密设备信息 +func (vm *ViewModel) EncryptDeviceInfo(deviceInfo map[string]string) (string, error) { + jsonData, err := json.Marshal(deviceInfo) + if err != nil { + return "", fmt.Errorf("JSON序列化失败: %w", err) + } + + plaintext := string(jsonData) + maxBlockSize := vm.publicKey.Size() - 11 // PKCS#1 v1.5填充最大块大小 + var encryptedBlocks [][]byte + + for i := 0; i < len(plaintext); i += maxBlockSize { + end := i + maxBlockSize + if end > len(plaintext) { + end = len(plaintext) + } + + block := []byte(plaintext[i:end]) + encryptedBlock, err := rsa.EncryptPKCS1v15(rand.Reader, vm.publicKey, block) + if err != nil { + return "", fmt.Errorf("RSA加密失败: %w", err) + } + encryptedBlocks = append(encryptedBlocks, encryptedBlock) + } + + return base64.StdEncoding.EncodeToString(bytesJoin(encryptedBlocks)), nil +} + +// DecryptResponse 解密响应数据 +func (vm *ViewModel) DecryptResponse(ciphertextBase64 string) (string, error) { + ciphertextBytes, err := base64.StdEncoding.DecodeString(ciphertextBase64) + if err != nil { + return "", fmt.Errorf("响应数据Base64解码失败: %w", err) + } + + maxBlockSize := vm.privateKey.Size() + var decryptedBlocks [][]byte + + for i := 0; i < len(ciphertextBytes); i += maxBlockSize { + end := i + maxBlockSize + if end > len(ciphertextBytes) { + end = len(ciphertextBytes) + } + + block := ciphertextBytes[i:end] + decryptedBlock, err := rsa.DecryptPKCS1v15(rand.Reader, vm.privateKey, block) + if err != nil { + return "", fmt.Errorf("RSA解密失败: %w", err) + } + decryptedBlocks = append(decryptedBlocks, decryptedBlock) + } + + return string(bytesJoin(decryptedBlocks)), nil +} + +// 辅助函数:合并字节切片 +func bytesJoin(s [][]byte) []byte { + var totalLen int + for _, b := range s { + totalLen += len(b) + } + res := make([]byte, totalLen) + for i, b := range s { + copy(res[i:], b) + } + return res +} + +func EncryptDeviceInfo() string { + // 设备公共信息 + deviceInfo := map[string]string{ + "bootTimeInSec": "1595643553", + "countryCode": "CN", + "language": "zh-Hans-CN", + "deviceName": "e910dddb2748c36b47fcde5dd720eec1", + "systemVersion": "14.0", + "machine": "iPhone10,3", + "memory": "3955589120", + "disk": "63900340224", + "sysFileTime": "1595214620.383940", + "model": "D22AP", + "timeZone": "28800", + "deviceInitTime": "1632467920.301150749", + } + + // 初始化ViewModel + vm, err := NewViewModel() + if err != nil { + log.Printf("初始化失败: %v", err) + return "" + } + + // 加密设备信息 + encryptedDeviceInfo, err := vm.EncryptDeviceInfo(deviceInfo) + if err != nil { + log.Printf("设备信息加密失败: %v", err) + return "" + } + fmt.Printf("加密设备信息: %s\n", encryptedDeviceInfo) + + // 模拟响应解密(使用加密结果模拟响应数据) + //responseData := encryptedDeviceInfo // 实际应从接口获取encrypted_device_info字段 + return encryptedDeviceInfo +} + +func main() { + // 设备公共信息 + deviceInfo := map[string]string{ + "bootTimeInSec": "1595643553", + "countryCode": "CN", + "language": "zh-Hans-CN", + "deviceName": "e910dddb2748c36b47fcde5dd720eec1", + "systemVersion": "14.0", + "machine": "iPhone10,3", + "memory": "3955589120", + "disk": "63900340224", + "sysFileTime": "1595214620.383940", + "model": "D22AP", + "timeZone": "28800", + "deviceInitTime": "1632467920.301150749", + } + + // 替换为实际公钥(需去除换行符) + pubKeyBase64 := "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCk2GwklLJO0m4Z5PffSSRlv7jNkQhFyoESukIu2duXN9YaC9G7SCQQnyHYs1Si/W4z/u5a4OXBE5+jZ9W9zmc1wfVelf2vnzTfKABA6AJhlsUXs2UjPQrxNRCgu4rALQ2TlbobqqLpIWtm5rqboXs3yJpRfgaLlJvAdihxx2XYQIDAQAB" + + // 初始化ViewModel + //vm, err := NewViewModel() + //if err != nil { + // log.Fatalf("初始化失败: %v", err) + //} + // + //// 加密设备信息 + //encryptedDeviceInfo, err := vm.EncryptDeviceInfo(deviceInfo) + //if err != nil { + // log.Fatalf("设备信息加密失败: %v", err) + //} + //fmt.Printf("加密设备信息: %s\n", encryptedDeviceInfo) + // + //// 模拟响应解密(使用加密结果模拟响应数据) + //responseData := encryptedDeviceInfo // 实际应从接口获取encrypted_device_info字段 + ////decrypt(responseData) decrypt(responseData) // + //// 解密响应数据 + //decryptedData, err := vm.DecryptResponse(responseData) + //if err != nil { + // log.Fatalf("响应解密失败: %v", err) + //} + //fmt.Printf("解密后数据: %s\n", decryptedData) + // + //// 解析JSON数组(示例) + //var caidsArray []interface{} + //if err := json.Unmarshal([]byte(decryptedData), &caidsArray); err != nil { + // log.Fatalf("JSON解析失败: %v", err) + //} + //fmt.Printf("CAIDs数组: %+v\n", caidsArray) + //} + + // 公钥字符串,注意需要剔除换行符 + PUBK := pubKeyBase64 // 分配的API接入的公钥字符串 + // 序列化设备信息为JSON + jsonBytes, err := json.Marshal(deviceInfo) + if err != nil { + fmt.Printf("JSON序列化错误: %v\n", err) + return + } + jsonStr := string(jsonBytes) + + decrypt(jsonStr) + fmt.Printf("PUBK: %s\n", PUBK) + //// 加密设备信息 + //encryptedDeviceInfo, err := encryptWithPublicKey(jsonStr, PUBK) + //if err != nil { + // fmt.Printf("加密错误: %v\n", err) + // return + //} + // + //fmt.Printf("加密后的设备信息: %s\n", encryptedDeviceInfo) + //// 将encryptedDeviceInfo填入请求中的encrypted_device_info字段 + // + //// 解密响应数据示例 + //// 假设从响应中获取的data字段值 + //responseData := "" + //decryptedData, err := decryptWithPrivateKey(responseData, PUBK) + //if err != nil { + // fmt.Printf("解密错误: %v\n", err) + // return + //} + // + //fmt.Printf("解密后的响应数据: %s\n", decryptedData) + //// 解析为JSON数组 + //var caidsArray []interface{} + //if err := json.Unmarshal([]byte(decryptedData), &caidsArray); err != nil { + // fmt.Printf("JSON解析错误: %v\n", err) + // return + //} + //fmt.Printf("解析后的CAIDS数组: %v\n", caidsArray) +} + +// 使用公钥加密数据 +func encryptWithPublicKey(data string, pubKeyStr string) (string, error) { + // 解码Base64格式的公钥 + pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKeyStr) + if err != nil { + return "", fmt.Errorf("公钥Base64解码错误: %v", err) + } + + // 解析公钥 + publicKey, err := x509.ParsePKIXPublicKey(pubKeyBytes) + if err != nil { + return "", fmt.Errorf("公钥解析错误: %v", err) + } + + // 断言为RSA公钥 + rsaPubKey, ok := publicKey.(*rsa.PublicKey) + if !ok { + return "", errors.New("不是RSA公钥") + } + + // 计算最大加密块大小 + maxEncryptBlock := rsaPubKey.Size() - 42 // PKCS#1 OAEP加密需要预留42字节 + + dataBytes := []byte(data) + dataLen := len(dataBytes) + var encryptedBytes []byte + + // 分段加密 + for i := 0; i < dataLen; i += maxEncryptBlock { + end := i + maxEncryptBlock + if end > dataLen { + end = dataLen + } + + // 加密当前块 + encryptedBlock, err := rsa.EncryptOAEP( + nil, + rand.Reader, + rsaPubKey, + dataBytes[i:end], + nil, + ) + if err != nil { + return "", fmt.Errorf("加密错误: %v", err) + } + + encryptedBytes = append(encryptedBytes, encryptedBlock...) + } + + // Base64编码加密结果 + return base64.StdEncoding.EncodeToString(encryptedBytes), nil +} + +// 使用私钥解密数据(完整修正版函数) +func decryptWithPrivateKey(encryptedData string, privKeyStr string) (string, error) { + // 解码Base64格式的加密数据 + encryptedBytes, err := base64.StdEncoding.DecodeString(encryptedData) + if err != nil { + return "", fmt.Errorf("加密数据Base64解码错误: %v", err) + } + + // 解码Base64格式的私钥 + privKeyBytes, err := base64.StdEncoding.DecodeString(privKeyStr) + if err != nil { + return "", fmt.Errorf("私钥Base64解码错误: %v", err) + } + + // 解析私钥 + privateKey, err := x509.ParsePKCS8PrivateKey(privKeyBytes) + if err != nil { + return "", fmt.Errorf("私钥解析错误: %v", err) + } + + // 断言为RSA私钥 + rsaPrivKey, ok := privateKey.(*rsa.PrivateKey) + if !ok { + return "", errors.New("不是RSA私钥") + } + + // 计算最大解密块大小 + maxDecryptBlock := rsaPrivKey.Size() + encryptedLen := len(encryptedBytes) + var decryptedBytes []byte + + // 分段解密 + for i := 0; i < encryptedLen; i += maxDecryptBlock { + end := i + maxDecryptBlock + if end > encryptedLen { + end = encryptedLen + } + + // 使用私钥进行解密(这是RSA的标准做法) + decryptedBlock, err := rsa.DecryptOAEP( + nil, + rand.Reader, + rsaPrivKey, + encryptedBytes[i:end], + nil, + ) + if err != nil { + return "", fmt.Errorf("解密错误: %v", err) + } + + decryptedBytes = append(decryptedBytes, decryptedBlock...) + } + + return string(decryptedBytes), nil +}