You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
8.9 KiB
274 lines
8.9 KiB
|
4 months ago
|
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
|
||
|
|
//}
|