Browse Source

add support rsa

kerryzhang 5 years ago
parent
commit
ca630d867f
8 changed files with 370 additions and 121 deletions
  1. 28 0
      README.md
  2. 8 0
      byteutil.go
  3. 158 0
      jrebelhandler.go
  4. 30 16
      jrebelprivatekey.go
  5. 7 5
      jrebelsign.go
  6. 111 0
      jrebelstruct.go
  7. 11 100
      main.go
  8. 17 0
      util.go

+ 28 - 0
README.md

@@ -0,0 +1,28 @@
+
+
+
+```json
+{
+    "serverVersion": "3.2.4",
+    "serverProtocolVersion": "1.1",
+    "serverGuid": "a1b4aea8-b031-4302-b602-670a990272cb",
+    "groupType": "managed",
+    "id": 1,
+    "licenseType": 1,
+    "evaluationLicense": false,
+    "signature": "OJE9wGg2xncSb+VgnYT+9HGCFaLOk28tneMFhCbpVMKoC/Iq4LuaDKPirBjG4o394/UjCDGgTBpIrzcXNPdVxVr8PnQzpy7ZSToGO8wv/KIWZT9/ba7bDbA8/RZ4B37YkCeXhjaixpmoyz/CIZMnei4q7oWR7DYUOlOcEWDQhiY=",
+    "serverRandomness": "H2ulzLlh7E0=",
+    "seatPoolType": "standalone",
+    "statusCode": "SUCCESS",
+    "offline": false,
+    "validFrom": null,
+    "validUntil": null,
+    "company": "Administrator",
+    "orderId": "",
+    "zeroIds": [
+        
+    ],
+    "licenseValidFrom": 1490544001000,
+    "licenseValidUntil": 1691839999000
+}
+```

+ 8 - 0
byteutil.go

@@ -14,3 +14,11 @@ func decodeBase64(str string) (res []byte) {
 	}
 	return
 }
+
+func encodeBase64(data []byte) (res string) {
+	if data == nil {
+		return
+	}
+	res = base64.StdEncoding.EncodeToString(data)
+	return
+}

+ 158 - 0
jrebelhandler.go

@@ -0,0 +1,158 @@
+package main
+
+import (
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"strconv"
+	"time"
+)
+
+func indexHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("content-type", "text/html; charset=utf-8")
+	w.WriteHeader(200)
+	//port := 1000
+	//_, _ = fmt.Fprintf(w, html)
+}
+
+func jrebelLeasesHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("content-type", "application/json; charset=utf-8")
+
+	parameter, err := getHttpBodyParameter(r)
+	if err != nil {
+		w.WriteHeader(403)
+		_, _ = fmt.Fprintf(w, "%s\n", err)
+		return
+	}
+
+	clientRandomness := parameter.Get("randomness")
+	username := parameter.Get("username")
+	guid := parameter.Get("guid")
+	if clientRandomness == "" || username == "" || guid == "" {
+		w.WriteHeader(403)
+		_, _ = fmt.Fprint(w)
+		return
+	}
+	offline, err := strconv.ParseBool(parameter.Get("offline"))
+	if err != nil {
+		offline = false
+	}
+
+	validFrom := "null"
+	validUntil := "null"
+	if offline {
+		clientTime := parameter.Get("clientTime")
+		_ = parameter.Get("offlineDays")
+
+		startTimeInt, err := strconv.ParseInt(clientTime, 10, 64)
+		if err != nil {
+			startTimeInt = int64(time.Now().Second()) * 1000
+		}
+		// 过期时间
+		expTime := int64(180 * 24 * 60 * 60 * 100)
+		validFrom = clientTime
+		validUntil = strconv.FormatInt(startTimeInt+expTime, 10)
+	}
+	serverRandomness := newServerRandomness()
+	signature := toLeaseCreateJson(clientRandomness, serverRandomness, guid, offline, validFrom, validUntil)
+
+	var responseBody = jRebelLeases
+	responseBody.ServerRandomness = serverRandomness
+	responseBody.Signature = signature
+	responseBody.Company = username
+
+	response(w, &responseBody)
+}
+
+func jrebelLeases1Handler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("content-type", "application/json; charset=utf-8")
+	parameter, err := getHttpBodyParameter(r)
+	if err != nil {
+		w.WriteHeader(403)
+		_, _ = fmt.Fprintf(w, "%s\n", err)
+		return
+	}
+	username := parameter.Get("username")
+
+	var responseBody = jrebelLeases1
+	if username != "" {
+		responseBody.Company = username
+	}
+
+	response(w, &responseBody)
+}
+
+func jrebelValidateHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Add("content-type", "application/json; charset=utf-8")
+	w.WriteHeader(200)
+	_, _ = fmt.Fprintf(w, "%s\n", jrebelValidateJson)
+}
+
+func pingHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Add("content-type", "text/html; charset=utf-8")
+	parameter, err := getHttpBodyParameter(r)
+	if err != nil {
+		w.WriteHeader(403)
+		_, _ = fmt.Fprintf(w, "%s\n", err)
+		return
+	}
+	salt := parameter.Get("salt")
+	if salt == "" {
+		w.WriteHeader(403)
+		_, _ = fmt.Fprint(w)
+	} else {
+		xmlContent := "<PingResponse><message></message><responseCode>OK</responseCode><salt>" + salt + "</salt></PingResponse>"
+		signature, err := signWithMd5([]byte(xmlContent))
+		if err != nil {
+			w.WriteHeader(403)
+			_, _ = fmt.Fprintf(w, "%s\n", err)
+		} else {
+			body := "<!-- " + hex.EncodeToString(signature) + " -->\n" + xmlContent
+			w.WriteHeader(200)
+			_, _ = fmt.Fprintf(w, "%s\n", body)
+		}
+	}
+}
+
+func obtainTicketHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Add("content-type", "application/json; charset=utf-8")
+	w.WriteHeader(200)
+
+}
+func releaseTicketHandler(w http.ResponseWriter, r *http.Request) {
+	fmt.Fprintf(w, "Hello there!\n")
+}
+func response(w http.ResponseWriter, resp interface{}) {
+	bodyData, err := json.Marshal(&resp)
+	if err != nil {
+		w.WriteHeader(403)
+		_, _ = fmt.Fprintf(w, "%s\n", err)
+		return
+	}
+	w.WriteHeader(200)
+	_, _ = fmt.Fprintf(w, "%s\n", string(bodyData))
+}
+
+func getHttpBodyParameter(r *http.Request) (params url.Values, err error) {
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+	s := string(body)
+	ps := url.URL{
+		Scheme:     "",
+		Opaque:     "",
+		User:       nil,
+		Host:       "",
+		Path:       "",
+		RawPath:    "",
+		ForceQuery: false,
+		RawQuery:   s,
+		Fragment:   "",
+	}
+	fmt.Println(s)
+	return ps.Query(), err
+}

+ 30 - 16
jrebelprivatekey.go

@@ -6,8 +6,6 @@ import (
 	"crypto/rsa"
 	"crypto/x509"
 	"encoding/pem"
-	"fmt"
-	"github.com/pkg/errors"
 )
 
 // pem private key
@@ -26,14 +24,27 @@ Ljo7A6bzsvfnJpV+lQiOqD/WCw3A2yPwe+1d0X/13fQkgzcbB3K0K81Euo/fkKKiBv0A7yR7wvrN
 jzefE9sKUw==
 -----END PRIVATE KEY-----`
 
-func testSign(data []byte) (signature []byte, err error) {
-	block, _ := pem.Decode([]byte(privateKey))
-	if block == nil {
-		return nil, errors.New("Decode key error, current block is null")
-	}
-	priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+const asmPrivateKey = `
+-----BEGIN PRIVATE KEY-----
+MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAt5yrcHAAjhglnCEn
+6yecMWPeUXcMyo0+itXrLlkpcKIIyqPw546bGThhlb1ppX1ySX/OUA4jSakHekNP
+5eWPawIDAQABAkBbr9pUPTmpuxkcy9m5LYBrkWk02PQEOV/fyE62SEPPP+GRhv4Q
+Fgsu+V2GCwPQ69E3LzKHPsSNpSosIHSO4g3hAiEA54JCn41fF8GZ90b9L5dtFQB2
+/yIcGX4Xo7bCvl8DaPMCIQDLCUN8YiXppydqQ+uYkTQgvyq+47cW2wcGumRS46dd
+qQIhAKp2v5e8AMj9ROFO5B6m4SsVrIkwFICw17c0WzDRxTEBAiAYDmftk990GLcF
+0zhV4lZvztasuWRXE+p4NJtwasLIyQIgVKzknJe8VOt5a3shCMOyysoNEg+YAt02
+O98RPCU0nJg=
+-----END PRIVATE KEY-----`
+
+var (
+	privateKeyBlock, _    = pem.Decode([]byte(privateKey))
+	asnPrivateKeyBlock, _ = pem.Decode([]byte(asmPrivateKey))
+)
+
+// 签名
+func signWithSha1(data []byte) (signature []byte, err error) {
+	priv, err := x509.ParsePKCS8PrivateKey(privateKeyBlock.Bytes)
 	if err != nil {
-		fmt.Println(err)
 		return
 	}
 	h := crypto.Hash.New(crypto.SHA1)
@@ -45,13 +56,16 @@ func testSign(data []byte) (signature []byte, err error) {
 	return
 }
 
-type SHA1withRSA struct {
-	privateKey *rsa.PrivateKey
-}
-
-func sign(privateKey []byte, encryptData []byte) (res []byte, err error) {
-
-	//rsa, err := x509.ParsePKCS8PrivateKey(privateKey)
+//TODO fix
+func signWithMd5(data []byte) (signature []byte, err error) {
+	priv, err := x509.ParsePKCS8PrivateKey(asnPrivateKeyBlock.Bytes)
+	if err != nil {
+		return
+	}
+	h := crypto.Hash.New(crypto.MD5)
+	h.Write([]byte(data))
+	hashed := h.Sum(nil)
 
+	signature, err = rsa.SignPKCS1v15(rand.Reader, priv.(*rsa.PrivateKey), crypto.MD5, hashed)
 	return
 }

+ 7 - 5
jrebelsign.go

@@ -4,15 +4,17 @@ import (
 	"strconv"
 )
 
-//服务端随机数,如果要自己生成,务必将其写到json的serverRandomness中
-const serverRandomness string = "H2ulzLlh7E0="
-
-func toLeaseCreateJson(clientRandomness string, guid string, offline bool, validFrom string, validUntil string) string {
+func toLeaseCreateJson(clientRandomness string, serverRandomness string, guid string, offline bool, validFrom string, validUntil string) (res string) {
 	var s2 string
 	if offline {
 		s2 = clientRandomness + ";" + serverRandomness + ";" + guid + ";" + strconv.FormatBool(offline) + ";" + validFrom + ";" + validUntil
 	} else {
 		s2 = clientRandomness + ";" + serverRandomness + ";" + guid + ";" + strconv.FormatBool(offline)
 	}
-	return s2
+	signature, err := signWithSha1([]byte(s2))
+	if err != nil {
+		return
+	}
+	res = encodeBase64(signature)
+	return
 }

+ 111 - 0
jrebelstruct.go

@@ -0,0 +1,111 @@
+package main
+
+import "encoding/json"
+
+var jRebelLeases JRebelLeasesStruct
+var jrebelLeases1 JrebelLeases1Struct
+var jrebelValidate JrebelValidateStruct
+
+func init() {
+	_ = json.Unmarshal([]byte(jrebelLeasesJson), &jRebelLeases)
+	_ = json.Unmarshal([]byte(jrebelLeases1Json), &jrebelLeases1)
+	_ = json.Unmarshal([]byte(jrebelValidateJson), &jrebelValidate)
+}
+
+//language=JSON
+const jrebelLeasesJson = `{
+    "serverVersion": "3.2.4",
+    "serverProtocolVersion": "1.1",
+    "serverGuid": "a1b4aea8-b031-4302-b602-670a990272cb",
+    "groupType": "managed",
+    "id": 1,
+    "licenseType": 1,
+    "evaluationLicense": false,
+    "signature": "OJE9wGg2xncSb+VgnYT+9HGCFaLOk28tneMFhCbpVMKoC/Iq4LuaDKPirBjG4o394/UjCDGgTBpIrzcXNPdVxVr8PnQzpy7ZSToGO8wv/KIWZT9/ba7bDbA8/RZ4B37YkCeXhjaixpmoyz/CIZMnei4q7oWR7DYUOlOcEWDQhiY=",
+    "serverRandomness": "H2ulzLlh7E0=",
+    "seatPoolType": "standalone",
+    "statusCode": "SUCCESS",
+    "offline": false,
+    "validFrom": null,
+    "validUntil": null,
+    "company": "Administrator",
+    "orderId": "",
+    "zeroIds": [
+        
+    ],
+    "licenseValidFrom": 1490544001000,
+    "licenseValidUntil": 1691839999000
+}`
+
+type JRebelLeasesStruct struct {
+	ServerVersion         string        `json:"serverVersion"`
+	ServerProtocolVersion string        `json:"serverProtocolVersion"`
+	ServerGUID            string        `json:"serverGuid"`
+	GroupType             string        `json:"groupType"`
+	ID                    int           `json:"id"`
+	LicenseType           int           `json:"licenseType"`
+	EvaluationLicense     bool          `json:"evaluationLicense"`
+	Signature             string        `json:"signature"`
+	ServerRandomness      string        `json:"serverRandomness"`
+	SeatPoolType          string        `json:"seatPoolType"`
+	StatusCode            string        `json:"statusCode"`
+	Offline               bool          `json:"offline"`
+	ValidFrom             int64         `json:"validFrom"`
+	ValidUntil            int64         `json:"validUntil"`
+	Company               string        `json:"company"`
+	OrderID               string        `json:"orderId"`
+	ZeroIds               []interface{} `json:"zeroIds"`
+	LicenseValidFrom      int64         `json:"licenseValidFrom"`
+	LicenseValidUntil     int64         `json:"licenseValidUntil"`
+}
+
+//language=JSON
+const jrebelLeases1Json = `{
+    "serverVersion": "3.2.4",
+    "serverProtocolVersion": "1.1",
+    "serverGuid": "a1b4aea8-b031-4302-b602-670a990272cb",
+    "groupType": "managed",
+    "statusCode": "SUCCESS",
+    "msg": null,
+    "statusMessage": null
+}
+`
+
+type JrebelLeases1Struct struct {
+	ServerVersion         string      `json:"serverVersion"`
+	ServerProtocolVersion string      `json:"serverProtocolVersion"`
+	ServerGUID            string      `json:"serverGuid"`
+	GroupType             string      `json:"groupType"`
+	StatusCode            string      `json:"statusCode"`
+	Company               string      `json:"company"`
+	Msg                   interface{} `json:"msg"`
+	StatusMessage         interface{} `json:"statusMessage"`
+}
+
+//language=JSON
+const jrebelValidateJson = `{
+    "serverVersion": "3.2.4",
+    "serverProtocolVersion": "1.1",
+    "serverGuid": "a1b4aea8-b031-4302-b602-670a990272cb",
+    "groupType": "managed",
+    "statusCode": "SUCCESS",
+    "company": "Administrator",
+    "canGetLease": true,
+    "licenseType": 1,
+    "evaluationLicense": false,
+    "seatPoolType": "standalone"
+}
+`
+
+type JrebelValidateStruct struct {
+	ServerVersion         string `json:"serverVersion"`
+	ServerProtocolVersion string `json:"serverProtocolVersion"`
+	ServerGUID            string `json:"serverGuid"`
+	GroupType             string `json:"groupType"`
+	StatusCode            string `json:"statusCode"`
+	Company               string `json:"company"`
+	CanGetLease           bool   `json:"canGetLease"`
+	LicenseType           int    `json:"licenseType"`
+	EvaluationLicense     bool   `json:"evaluationLicense"`
+	SeatPoolType          string `json:"seatPoolType"`
+}

+ 11 - 100
main.go

@@ -1,16 +1,22 @@
 package main
 
 import (
+	"encoding/hex"
 	"fmt"
-	"io/ioutil"
 	"net/http"
-	"net/url"
-	"strconv"
-	"time"
 )
 
 func main() {
-	signature, err := testSign([]byte{0, 0, 0, 0})
+
+	content := "<PingResponse><message></message><responseCode>OK</responseCode><salt>ABCD</salt></PingResponse>"
+
+	signatures, err := signWithMd5([]byte(content))
+	if err != nil {
+		fmt.Println(err)
+	}
+	fmt.Println(hex.EncodeToString(signatures))
+
+	signature, err := signWithSha1([]byte{0, 0, 0, 0})
 	if err != nil {
 		fmt.Println(err)
 	}
@@ -28,98 +34,3 @@ func main() {
 
 	_ = http.ListenAndServe(":12345", nil)
 }
-
-func indexHandler(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("content-type", "text/html; charset=utf-8")
-	w.WriteHeader(200)
-	//port := 1000
-	//_, _ = fmt.Fprintf(w, html)
-}
-
-func jrebelLeasesHandler(w http.ResponseWriter, r *http.Request) {
-	fmt.Println(len(r.PostForm))
-	fmt.Println(len(r.Form))
-	body, err := ioutil.ReadAll(r.Body)
-	if err != nil {
-		fmt.Println(err)
-	} else {
-		parameter := toHttpBodyParameter(body)
-		randomness := parameter.Get("randomness")
-		username := parameter.Get("username")
-		guid := parameter.Get("guid")
-		if randomness == "" || username == "" || guid == "" {
-			w.WriteHeader(403)
-			_, _ = fmt.Fprint(w)
-			return
-		}
-		offline, err := strconv.ParseBool(parameter.Get("offline"))
-		if err != nil {
-			offline = false
-		}
-
-		validFrom := "null"
-		validUntil := "null"
-		if offline {
-			clientTime := parameter.Get("clientTime")
-			_ = parameter.Get("offlineDays")
-
-			startTimeInt, err := strconv.ParseInt(clientTime, 10, 64)
-			if err != nil {
-				startTimeInt = int64(time.Now().Second()) * 1000
-			}
-			// 过期时间
-			expTime := int64(180 * 24 * 60 * 60 * 100)
-			validFrom = clientTime
-			validUntil = strconv.FormatInt(startTimeInt+expTime, 10)
-		}
-
-		fmt.Println(validFrom)
-		fmt.Println(validUntil)
-
-	}
-
-	w.Header().Set("content-type", "application/json; charset=utf-8")
-	w.WriteHeader(200)
-
-	fmt.Fprintf(w, "Hello there!\n")
-}
-
-func jrebelLeases1Handler(w http.ResponseWriter, r *http.Request) {
-	fmt.Println("jrebelLeases1Handler")
-
-	randomness := r.Form.Get("randomness")
-	fmt.Println(randomness)
-
-	fmt.Fprintf(w, "Hello there!\n")
-}
-
-func jrebelValidateHandler(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintf(w, "Hello there!\n")
-}
-func pingHandler(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintf(w, "Hello there!\n")
-}
-
-func obtainTicketHandler(w http.ResponseWriter, r *http.Request) {
-
-}
-func releaseTicketHandler(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintf(w, "Hello there!\n")
-}
-
-func toHttpBodyParameter(body []byte) url.Values {
-	s := string(body)
-	ps := url.URL{
-		Scheme:     "",
-		Opaque:     "",
-		User:       nil,
-		Host:       "",
-		Path:       "",
-		RawPath:    "",
-		ForceQuery: false,
-		RawQuery:   s,
-		Fragment:   "",
-	}
-	fmt.Println(s)
-	return ps.Query()
-}

+ 17 - 0
util.go

@@ -0,0 +1,17 @@
+package main
+
+import (
+	"math/rand"
+)
+
+const randCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
+const allRandCharsetLen = len(randCharset)
+
+func newServerRandomness() (serverRandomness string) {
+	// H2ulzLlh7E0=
+	b := make([]byte, 11)
+	for i := 0; i < 11; i++ {
+		b[i] = randCharset[rand.Intn(allRandCharsetLen)]
+	}
+	return string(b) + "="
+}