13 changed files with 1152 additions and 8 deletions
@ -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<data>: 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<data>: 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
|
||||||
|
//}
|
||||||
@ -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<data>: 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<data>: 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 |
||||||
|
} |
||||||
@ -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----- |
||||||
@ -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----- |
||||||
@ -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----- |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
-----BEGIN PUBLIC KEY----- |
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCk2GwklLJO0m4Z5PffSSRlv7j |
||||||
|
NkQhFyoESukIu2duXN9YaC9G7SCQQnyHYs1Si/W4z/u5a4OXBE5+jZ9W9zmc1wfV |
||||||
|
elf2vnzTfKABA6AJhlsUXs2UjPQrxNRCgu4rALQ2TlbobqqLpIWtm5rqboXs3yJp |
||||||
|
RfgaLlJvAdihxx2XYQIDAQAB |
||||||
|
-----END PUBLIC KEY----- |
||||||
Binary file not shown.
@ -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<data>: 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 |
||||||
|
} |
||||||
Loading…
Reference in new issue