// 依赖: Go 1.18+ (仅标准库)
package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

const (
	baseURL   = "{{BASE}}"
	pubURL    = "{{PUBKEY}}"
	verifyURL = "{{VERIFY}}"
	cardCode  = "YOUR-CARD-KEY"
)

func encrypt(plain string, pub *rsa.PublicKey) (string, error) {
	data := []byte(plain)
	var parts []string
	for len(data) > 0 {
		n := 190
		if len(data) < n {
			n = len(data)
		}
		enc, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, pub, data[:n], nil)
		if err != nil {
			return "", err
		}
		parts = append(parts, base64.StdEncoding.EncodeToString(enc))
		data = data[n:]
	}
	return strings.Join(parts, "|"), nil
}

func decrypt(cipher string, priv *rsa.PrivateKey) (string, error) {
	var sb strings.Builder
	for _, p := range strings.Split(cipher, "|") {
		raw, _ := base64.StdEncoding.DecodeString(p)
		dec, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, priv, raw, nil)
		if err != nil {
			return "", err
		}
		sb.Write(dec)
	}
	return sb.String(), nil
}

func main() {
	// 1. 获取服务器公钥
	resp, _ := http.Get(pubURL)
	raw, _ := io.ReadAll(resp.Body)
	var pubResp struct {
		Data struct {
			PublicKey string `json:"public_key"`
		} `json:"data"`
	}
	json.Unmarshal(raw, &pubResp)
	block, _ := pem.Decode([]byte(pubResp.Data.PublicKey))
	pubAny, _ := x509.ParsePKIXPublicKey(block.Bytes)
	serverPub := pubAny.(*rsa.PublicKey)

	// 2. 生成客户端密钥对
	clientPriv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pubDER, _ := x509.MarshalPKIXPublicKey(&clientPriv.PublicKey)
	clientPub := string(pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubDER}))

	// 3. 组装并加密请求
	payload, _ := json.Marshal(map[string]interface{}{
		"code":              cardCode,
		"timestamp":         time.Now().Unix(),
		"client_public_key": clientPub,
	})
	cipher, _ := encrypt(string(payload), serverPub)
	body, _ := json.Marshal(map[string]string{"encrypted": cipher})

	// 4. 发送请求
	httpResp, _ := http.Post(verifyURL, "application/json", bytes.NewReader(body))
	respBody, _ := io.ReadAll(httpResp.Body)

	// 5. 解密响应
	var out map[string]interface{}
	json.Unmarshal(respBody, &out)
	if enc, ok := out["encrypted"].(string); ok {
		plain, _ := decrypt(enc, clientPriv)
		fmt.Println(plain)
	} else {
		fmt.Println(string(respBody))
	}
}
