Skip to content

Commit

Permalink
feature: support signature key Rsa and ed25519 (adshao#579)
Browse files Browse the repository at this point in the history
  • Loading branch information
xyq-c-cpp authored Jun 24, 2024
1 parent 1ba84a6 commit c2c4643
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 24 deletions.
19 changes: 13 additions & 6 deletions v2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package binance
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"crypto/tls"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -323,6 +321,7 @@ func NewClient(apiKey, secretKey string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getAPIEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: http.DefaultClient,
Expand All @@ -343,6 +342,7 @@ func NewProxiedClient(apiKey, secretKey, proxyUrl string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getAPIEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: &http.Client{
Expand Down Expand Up @@ -373,6 +373,7 @@ type doFunc func(req *http.Request) (*http.Response, error)
type Client struct {
APIKey string
SecretKey string
KeyType string
BaseURL string
UserAgent string
HTTPClient *http.Client
Expand Down Expand Up @@ -419,16 +420,22 @@ func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) {
if r.secType == secTypeAPIKey || r.secType == secTypeSigned {
header.Set("X-MBX-APIKEY", c.APIKey)
}

kt := c.KeyType
if kt == "" {
kt = common.KeyTypeHmac
}
sf, err := common.SignFunc(kt)
if err != nil {
return err
}
if r.secType == secTypeSigned {
raw := fmt.Sprintf("%s%s", queryString, bodyString)
mac := hmac.New(sha256.New, []byte(c.SecretKey))
_, err = mac.Write([]byte(raw))
sign, err := sf(c.SecretKey, raw)
if err != nil {
return err
}
v := url.Values{}
v.Set(signatureKey, fmt.Sprintf("%x", (mac.Sum(nil))))
v.Set(signatureKey, *sign)
if queryString == "" {
queryString = v.Encode()
} else {
Expand Down
85 changes: 85 additions & 0 deletions v2/common/sign.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package common

import (
"crypto"
"crypto/ed25519"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
)

const (
KeyTypeHmac = "HMAC"
KeyTypeRsa = "RSA"
KeyTypeEd25519 = "ED25519"
)

func SignFunc(keyType string) (func(string, string) (*string, error), error) {
switch {
case keyType == KeyTypeHmac:
return Hmac, nil
case keyType == KeyTypeRsa:
return Rsa, nil
case keyType == KeyTypeEd25519:
return Ed25519, nil
default:
return nil, fmt.Errorf("unsupported keyType=%s", keyType)
}
}

func Hmac(secretKey string, data string) (*string, error) {
mac := hmac.New(sha256.New, []byte(secretKey))
_, err := mac.Write([]byte(data))
if err != nil {
return nil, err
}
encodeData := fmt.Sprintf("%x", (mac.Sum(nil)))
return &encodeData, nil
}

func Rsa(secretKey string, data string) (*string, error) {
block, _ := pem.Decode([]byte(secretKey))
if block == nil {
return nil, errors.New("Rsa pem.Decode failed, invalid pem format secretKey")
}
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("Rsa ParsePKCS8PrivateKey failed, error=%v", err.Error())
}
rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("Rsa convert PrivateKey failed")
}
hashed := sha256.Sum256([]byte(data))
signature, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey, crypto.SHA256, hashed[:])
if err != nil {
return nil, err
}
encodedSignature := base64.StdEncoding.EncodeToString(signature)
return &encodedSignature, nil
}

func Ed25519(secretKey string, data string) (*string, error) {
block, _ := pem.Decode([]byte(secretKey))
if block == nil {
return nil, fmt.Errorf("Ed25519 pem.Decode failed, invalid pem format secretKey")
}
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("Ed25519 call ParsePKCS8PrivateKey failed, error=%v", err.Error())
}
ed25519PrivateKey, ok := privateKey.(ed25519.PrivateKey)
if !ok {
return nil, fmt.Errorf("Ed25519 convert PrivateKey failed")
}
pk := ed25519.PrivateKey(ed25519PrivateKey)
signature := ed25519.Sign(pk, []byte(data))
encodedSignature := base64.StdEncoding.EncodeToString(signature)
return &encodedSignature, nil
}
41 changes: 35 additions & 6 deletions v2/delivery/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ package delivery
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -190,19 +189,43 @@ func NewClient(apiKey, secretKey string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getApiEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: http.DefaultClient,
Logger: log.New(os.Stderr, "Binance-golang ", log.LstdFlags),
}
}

func NewProxiedClient(apiKey, secretKey, proxyUrl string) *Client {
proxy, err := url.Parse(proxyUrl)
if err != nil {
log.Fatal(err)
}
tr := &http.Transport{
Proxy: http.ProxyURL(proxy),
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getApiEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: &http.Client{
Transport: tr,
},
Logger: log.New(os.Stderr, "Binance-golang ", log.LstdFlags),
}
}

type doFunc func(req *http.Request) (*http.Response, error)

// Client define API client
type Client struct {
APIKey string
SecretKey string
KeyType string
BaseURL string
UserAgent string
HTTPClient *http.Client
Expand Down Expand Up @@ -249,16 +272,22 @@ func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) {
if r.secType == secTypeAPIKey || r.secType == secTypeSigned {
header.Set("X-MBX-APIKEY", c.APIKey)
}

kt := c.KeyType
if kt == "" {
kt = common.KeyTypeHmac
}
sf, err := common.SignFunc(kt)
if err != nil {
return err
}
if r.secType == secTypeSigned {
raw := fmt.Sprintf("%s%s", queryString, bodyString)
mac := hmac.New(sha256.New, []byte(c.SecretKey))
_, err = mac.Write([]byte(raw))
sign, err := sf(c.SecretKey, raw)
if err != nil {
return err
}
v := url.Values{}
v.Set(signatureKey, fmt.Sprintf("%x", (mac.Sum(nil))))
v.Set(signatureKey, *sign)
if queryString == "" {
queryString = v.Encode()
} else {
Expand Down
19 changes: 13 additions & 6 deletions v2/futures/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package futures
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"crypto/tls"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -205,6 +203,7 @@ func NewClient(apiKey, secretKey string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getApiEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: http.DefaultClient,
Expand All @@ -225,6 +224,7 @@ func NewProxiedClient(apiKey, secretKey, proxyUrl string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getApiEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: &http.Client{
Expand All @@ -240,6 +240,7 @@ type doFunc func(req *http.Request) (*http.Response, error)
type Client struct {
APIKey string
SecretKey string
KeyType string
BaseURL string
UserAgent string
HTTPClient *http.Client
Expand Down Expand Up @@ -286,16 +287,22 @@ func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) {
if r.secType == secTypeAPIKey || r.secType == secTypeSigned {
header.Set("X-MBX-APIKEY", c.APIKey)
}

kt := c.KeyType
if kt == "" {
kt = common.KeyTypeHmac
}
sf, err := common.SignFunc(kt)
if err != nil {
return err
}
if r.secType == secTypeSigned {
raw := fmt.Sprintf("%s%s", queryString, bodyString)
mac := hmac.New(sha256.New, []byte(c.SecretKey))
_, err = mac.Write([]byte(raw))
sign, err := sf(c.SecretKey, raw)
if err != nil {
return err
}
v := url.Values{}
v.Set(signatureKey, fmt.Sprintf("%x", (mac.Sum(nil))))
v.Set(signatureKey, *sign)
if queryString == "" {
queryString = v.Encode()
} else {
Expand Down
19 changes: 13 additions & 6 deletions v2/options/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package options
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
"crypto/tls"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -208,6 +206,7 @@ func NewClient(apiKey, secretKey string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getApiEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: http.DefaultClient,
Expand All @@ -228,6 +227,7 @@ func NewProxiedClient(apiKey, secretKey, proxyUrl string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
KeyType: common.KeyTypeHmac,
BaseURL: getApiEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: &http.Client{
Expand All @@ -243,6 +243,7 @@ type doFunc func(req *http.Request) (*http.Response, error)
type Client struct {
APIKey string
SecretKey string
KeyType string
BaseURL string
UserAgent string
HTTPClient *http.Client
Expand Down Expand Up @@ -289,16 +290,22 @@ func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) {
if r.secType == secTypeAPIKey || r.secType == secTypeSigned {
header.Set("X-MBX-APIKEY", c.APIKey)
}

kt := c.KeyType
if kt == "" {
kt = common.KeyTypeHmac
}
sf, err := common.SignFunc(kt)
if err != nil {
return err
}
if r.secType == secTypeSigned {
raw := fmt.Sprintf("%s%s", queryString, bodyString)
mac := hmac.New(sha256.New, []byte(c.SecretKey))
_, err = mac.Write([]byte(raw))
sign, err := sf(c.SecretKey, raw)
if err != nil {
return err
}
v := url.Values{}
v.Set(signatureKey, fmt.Sprintf("%x", (mac.Sum(nil))))
v.Set(signatureKey, *sign)
if queryString == "" {
queryString = v.Encode()
} else {
Expand Down

0 comments on commit c2c4643

Please sign in to comment.