使用时,将服务器提供的activation_file.bin base64解码为activation_file.json,修改后运行此工具签名即可
(需要提前生成好自己的acronis_onprem_override_privkey.pem,格式为开头是
----BEGIN RSA PRIVATE KEY-----
的)package main import ( "log" "io/ioutil" "encoding/base64" "encoding/json" "encoding/pem" "encoding/hex" "crypto" "crypto/sha256" "crypto/rsa" "crypto/x509" "crypto/rand" ) type ActivationRequest struct { Header struct { AakoreID string `json:"aakore_id,omitempty"` AakoreClientID string `json:"aakore_client_id"` InstallationID string `json:"installation_id,omitempty"` InstallationHwid string `json:"installation_hwid,omitempty"` MachineName string `json:"machine_name,omitempty"` OwnerTenantID int64 `json:"owner_tenant_id,omitempty"` CreatedAt string `json:"created_at,omitempty"` } `json:"header,omitempty"` Operations []struct { Type string `json:"type,omitempty"` Params *struct { // import_agent_registration RegistrationResult *struct { EmergencyUpdateURL string `json:"emergency_update_url,omitempty"` Gateway struct { Address string `json:"address,omitempty"` Secure bool `json:"secure,omitempty"` Transports []string `json:"transports,omitempty"` } `json:"gateway,omitempty"` Idp struct { Address string `json:"address,omitempty"` Name string `json:"name,omitempty"` } `json:"idp,omitempty"` Oauth struct { ClientID string `json:"client_id,omitempty"` ClientSecret string `json:"client_secret,omitempty"` } `json:"oauth,omitempty"` RegistrationID string `json:"registration_id,omitempty"` Services []struct { API []string `json:"api,omitempty"` Name string `json:"name,omitempty"` } `json:"services,omitempty"` Tenant struct { ID string `json:"id,omitempty"` Locator string `json:"locator,omitempty"` Name string `json:"name,omitempty"` } `json:"tenant,omitempty"` } `json:"registrationResult,omitempty"` Server string `json:"server,omitempty"` Units []string `json:"units,omitempty"` // update_cloud_registration AakoreID string `json:"aakore_id,omitempty"` Login string `json:"login,omitempty"` Mode string `json:"mode,omitempty"` Status string `json:"status,omitempty"` // update_installation_licenses Data *struct { Items []struct { Distributor int64 `json:"distributor"` ExpirationDate *string `json:"expiration_date"` IsTrial bool `json:"is_trial"` Key string `json:"key"` Language string `json:"language"` MaintenanceExpirationDate interface{} `json:"maintenance_expiration_date"` OfferingItem string `json:"offering_item"` PurchaseDate interface{} `json:"purchase_date"` Quota int64 `json:"quota"` RegistrationDate string `json:"registration_date"` TenantUUID string `json:"tenant_uuid"` Used int64 `json:"used"` UUID string `json:"uuid"` } `json:"items,omitempty"` } `json:"data,omitempty"` TenantUUID string `json:"tenant_uuid,omitempty"` } `json:"params"` } `json:"operations,omitempty"` Meta struct { ValidUntil string `json:"valid_until,omitempty"` FileType string `json:"file_type,omitempty"` StopOnFail bool `json:"stop_on_fail,omitempty"` } `json:"meta,omitempty"` Sign string `json:"sign,omitempty"` } func main() { activationFileContent, err := ioutil.ReadFile("activation_file.json") if err != nil { rawActivationFile, err := ioutil.ReadFile("activation_file.bin") if err != nil { log.Fatal("Fuck can't read activation_file.bin") } activationFileContent, err = base64.StdEncoding.DecodeString(string(rawActivationFile)) if err != nil { log.Fatal("Fuck can't base64 decode") } } var objmap ActivationRequest if err := json.Unmarshal(activationFileContent, &objmap); err != nil { log.Fatal("Fuck can't json decode") } //delete(objmap, "sign") //objmap.Delete("sign") objmap.Sign = "" for i, _ := range objmap.Operations { op := &objmap.Operations[i] // something like "registrationResult":{"gateway":{},"idp":{},"oauth":{},"tenant":{}} if op.Params == nil { continue } rr := op.Params.RegistrationResult if rr != nil && rr.Gateway.Address == "" && rr.Idp.Address == "" && rr.Oauth.ClientID == "" && rr.Tenant.ID == "" { op.Params.RegistrationResult = nil } dat := op.Params.Data if dat != nil && dat.Items == nil { op.Params.Data = nil } if dat != nil { for i := 0; i < len(dat.Items); i++ { if dat.Items[i].ExpirationDate != nil && *dat.Items[i].ExpirationDate == "" { dat.Items[i].ExpirationDate = nil } } } } hashContent, err := json.Marshal(objmap) log.Printf("Signing content: %s", string(hashContent)) h := sha256.New() h.Reset() h.Write(hashContent) checksum := h.Sum(nil) log.Printf("Got checksum of json: %s", hex.EncodeToString(checksum)) privKeyContent, err := ioutil.ReadFile("acronis_onprem_override_privkey.pem") if err != nil { log.Fatal("Fuck can't read privkey") } block, _ := pem.Decode(privKeyContent) if block.Type != "RSA PRIVATE KEY" { log.Fatal("Fuck must use RSA PRIVATE KEY") } privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { log.Fatal("Fuck can't parse privkey") } sig, err := rsa.SignPSS(rand.Reader, privKey, crypto.SHA256, checksum, nil) if err != nil { log.Fatal("Fuck can't sign") } sig_encoded := hex.EncodeToString(sig) //objmap.Set("sign", sig_encoded) objmap.Sign = sig_encoded log.Printf("New sign: %s", sig_encoded) newJsonBuf, err := json.Marshal(objmap) if err != nil { log.Fatal("Fuck can't re-encode json") } newBase64Str := base64.StdEncoding.EncodeToString(newJsonBuf) if err := ioutil.WriteFile("activation_file.bin", []byte(newBase64Str), 0666); err != nil { log.Fatal("Fuck can't write new file") } log.Println("Successfully signed activation_file") }