From 05abe9b46627e966ac49a64f9a0aa6004df60e2f Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Fri, 6 Mar 2015 14:03:52 +1100 Subject: [PATCH] Refactored common crypto/encoding functions. --- bitfinexhttp.go | 20 +++++++------------ bitstamphttp.go | 7 ++----- btcchinahttp.go | 15 ++------------- btcehttp.go | 7 ++----- common.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++-- huobihttp.go | 10 ++-------- itbithttp.go | 9 ++------- kraken.go | 16 ++++------------ lakebtchttp.go | 14 +++----------- okcoinhttp.go | 14 ++++---------- 10 files changed, 77 insertions(+), 86 deletions(-) diff --git a/bitfinexhttp.go b/bitfinexhttp.go index 46242ef8..4464915a 100644 --- a/bitfinexhttp.go +++ b/bitfinexhttp.go @@ -6,10 +6,7 @@ import ( "fmt" "log" "encoding/json" - "encoding/hex" - "crypto/hmac" "crypto/sha512" - "encoding/base64" "errors" "strings" "strconv" @@ -252,23 +249,20 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[ PayloadJson, err := json.Marshal(request) - if b.Verbose { - log.Printf("Request JSON: %s\n", PayloadJson) - } - if err != nil { return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request") } - PayloadBase64 := base64.StdEncoding.EncodeToString(PayloadJson) - hmac := hmac.New(sha512.New384, []byte(b.APISecret)) - hmac.Write([]byte(PayloadBase64)) - signature := hex.EncodeToString(hmac.Sum(nil)) + if b.Verbose { + log.Printf("Request JSON: %s\n", PayloadJson) + } + PayloadBase64 := Base64Encode(PayloadJson) + hmac := GetHMAC(sha512.New384, []byte(PayloadBase64), []byte(b.APISecret)) req, err := http.NewRequest(method, BITFINEX_API_URL + path, strings.NewReader("")) - req.Header.Set("X-BFX-APIKEY", string(b.APIKey)) + req.Header.Set("X-BFX-APIKEY", b.APIKey) req.Header.Set("X-BFX-PAYLOAD", PayloadBase64) - req.Header.Set("X-BFX-SIGNATURE", signature) + req.Header.Set("X-BFX-SIGNATURE", HexEncodeToString(hmac)) client := &http.Client{} resp, err := client.Do(req) diff --git a/bitstamphttp.go b/bitstamphttp.go index 36900be7..6fac45e8 100644 --- a/bitstamphttp.go +++ b/bitstamphttp.go @@ -5,9 +5,7 @@ import ( "net/url" "io/ioutil" "log" - "encoding/hex" "encoding/json" - "crypto/hmac" "crypto/sha256" "strings" "strconv" @@ -271,9 +269,8 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, values url.Values, nonce := strconv.FormatInt(time.Now().UnixNano(), 10) values.Set("key", b.APIKey) values.Set("nonce", nonce) - hmac := hmac.New(sha256.New, []byte(b.APISecret)) - hmac.Write([]byte(nonce + b.ClientID + b.APIKey)) - values.Set("signature", strings.ToUpper(hex.EncodeToString(hmac.Sum(nil)))) + hmac := GetHMAC(sha256.New, []byte(nonce + b.ClientID + b.APIKey), []byte(b.APISecret)) + values.Set("signature", strings.ToUpper(HexEncodeToString(hmac))) reqBody := strings.NewReader(values.Encode()) path = BITSTAMP_API_URL + path diff --git a/btcchinahttp.go b/btcchinahttp.go index 2b2fb19b..bbf7ea43 100644 --- a/btcchinahttp.go +++ b/btcchinahttp.go @@ -4,10 +4,7 @@ import ( "net/http" "net/url" "strconv" - "crypto/hmac" "crypto/sha1" - "encoding/base64" - "encoding/hex" "encoding/json" "errors" "strings" @@ -167,20 +164,13 @@ func (b *BTCChina) SendAuthenticatedHTTPRequest(method string, params []string) log.Println(encoded) } - hmac := hmac.New(sha1.New, []byte(b.APISecret)) - hmac.Write([]byte(encoded)) - hash := hex.EncodeToString(hmac.Sum(nil)) - + hmac := GetHMAC(sha1.New, []byte(encoded), []byte(b.APISecret)) postData := make(map[string]interface{}) postData["method"] = method postData["params"] = []string{} postData["id"] = 1 data, err := json.Marshal(postData) - if b.Verbose { - log.Println(string(data)) - } - if err != nil { return errors.New("Unable to JSON POST data") } @@ -190,7 +180,6 @@ func (b *BTCChina) SendAuthenticatedHTTPRequest(method string, params []string) } reqBody := strings.NewReader(string(data)) - b64 := base64.StdEncoding.EncodeToString([]byte(b.APIKey + ":" + hash)) req, err := http.NewRequest("POST", "https://api.btcchina.com/api_trade_v1.php", reqBody) @@ -199,7 +188,7 @@ func (b *BTCChina) SendAuthenticatedHTTPRequest(method string, params []string) } req.Header.Add("Content-type", "application/json-rpc") - req.Header.Add("Authorization", "Basic " + b64) + req.Header.Add("Authorization", "Basic " + Base64Encode([]byte(b.APIKey + ":" + HexEncodeToString(hmac)))) req.Header.Add("Json-Rpc-Tonce", nonce) client := &http.Client{} diff --git a/btcehttp.go b/btcehttp.go index 1dc54038..ac18efc5 100644 --- a/btcehttp.go +++ b/btcehttp.go @@ -4,9 +4,7 @@ import ( "net/http" "net/url" "strconv" - "crypto/hmac" "crypto/sha512" - "encoding/hex" "errors" "strings" "time" @@ -174,9 +172,8 @@ func (b *BTCE) SendAuthenticatedHTTPRequest(method string, values url.Values) (e values.Set("nonce", nonce) values.Set("method", method) - hmac := hmac.New(sha512.New, []byte(b.APISecret)) encoded := values.Encode() - hmac.Write([]byte(encoded)) + hmac := GetHMAC(sha512.New, []byte(encoded), []byte(b.APISecret)) if b.Verbose { log.Printf("Sending POST request to %s calling method %s with params %s\n", BTCE_API_URL, method, encoded) @@ -190,7 +187,7 @@ func (b *BTCE) SendAuthenticatedHTTPRequest(method string, values url.Values) (e } req.Header.Add("Key", b.APIKey) - req.Header.Add("Sign", hex.EncodeToString(hmac.Sum(nil))) + req.Header.Add("Sign", HexEncodeToString(hmac)) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") client := &http.Client{} diff --git a/common.go b/common.go index 07ae01e4..72ac1375 100644 --- a/common.go +++ b/common.go @@ -2,14 +2,61 @@ package main import ( "net/http" + "hash" + "crypto/md5" + "crypto/hmac" + "crypto/sha512" + "crypto/sha256" + "encoding/base64" "encoding/json" + "encoding/hex" "io/ioutil" "errors" "math" "log" ) -func roundFloat(x float64, prec int) float64 { +func GetMD5(input []byte) ([]byte) { + hash := md5.New() + hash.Write(input) + return hash.Sum(nil) +} + +func GetSHA512(input []byte) ([]byte) { + sha := sha512.New() + sha.Write(input) + return sha.Sum(nil) +} + +func GetSHA256(input []byte) ([]byte) { + sha := sha256.New() + sha.Write(input) + return sha.Sum(nil) +} + +func GetHMAC(hash func() hash.Hash, input, key []byte) ([]byte) { + hmac := hmac.New(hash, []byte(key)) + hmac.Write(input) + return hmac.Sum(nil) +} + +func HexEncodeToString(input []byte) (string) { + return hex.EncodeToString(input) +} + +func Base64Decode(input string) ([]byte, error) { + result, err := base64.StdEncoding.DecodeString(input) + if err != nil { + return nil, err + } + return result, nil +} + +func Base64Encode(input []byte) (string) { + return base64.StdEncoding.EncodeToString(input) +} + +func RoundFloat(x float64, prec int) float64 { var rounder float64 pow := math.Pow(10, float64(prec)) intermed := x * pow @@ -54,7 +101,7 @@ func SendHTTPRequest(url string, jsonDecode bool, result interface{}) (err error } if res.StatusCode != 200 { - log.Printf("HTTP status code: %d", res.StatusCode) + log.Printf("HTTP status code: %d\n", res.StatusCode) return errors.New("Status code was not 200.") } diff --git a/huobihttp.go b/huobihttp.go index ab66dffe..9ca814d4 100644 --- a/huobihttp.go +++ b/huobihttp.go @@ -3,10 +3,8 @@ package main import ( "net/http" "net/url" - "crypto/md5" "errors" "strings" - "encoding/hex" "io/ioutil" "strconv" "time" @@ -199,15 +197,11 @@ func (h *HUOBI) SendAuthenticatedRequest(method string, v url.Values) (error) { v.Set("access_key", h.AccessKey) v.Set("created", strconv.FormatInt(time.Now().Unix(), 10)) v.Set("method", method) - - hasher := md5.New() - hasher.Write([]byte(v.Encode() + "&secret_key=" + h.SecretKey)) - signature := strings.ToUpper(hex.EncodeToString(hasher.Sum(nil))) - v.Set("sign", signature) + hash := GetMD5([]byte(v.Encode() + "&secret_key=" + h.SecretKey)) + v.Set("sign", strings.ToLower(HexEncodeToString(hash))) encoded := v.Encode() if h.Verbose { - log.Printf("Signature: %s\n", signature) log.Printf("Sending POST request to %s with params %s\n", HUOBI_API_URL, encoded) } diff --git a/itbithttp.go b/itbithttp.go index 0dced0ec..af83dbe0 100644 --- a/itbithttp.go +++ b/itbithttp.go @@ -3,10 +3,7 @@ package main import ( "net/http" "strconv" - "crypto/hmac" "crypto/sha512" - "encoding/base64" - "encoding/hex" "errors" "strings" "time" @@ -271,10 +268,8 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request") } - hmac := hmac.New(sha512.New, []byte(i.APISecret)) - hmac.Write([]byte(nonce + string(PayloadJson))) - hex := hex.EncodeToString(hmac.Sum(nil)) - signature := base64.StdEncoding.EncodeToString([]byte(hex)) + hmac := GetHMAC(sha512.New, []byte(nonce + string(PayloadJson)), []byte(i.APISecret)) + signature := Base64Encode([]byte(HexEncodeToString(hmac))) req, err := http.NewRequest(method, path, strings.NewReader("")) req.Header.Add("Authorization", i.ClientKey + ":" + signature) diff --git a/kraken.go b/kraken.go index f2cc38e5..c2953441 100644 --- a/kraken.go +++ b/kraken.go @@ -4,11 +4,8 @@ import ( "log" "fmt" "strconv" - "encoding/base64" "encoding/json" - "crypto/hmac" "crypto/sha512" - "crypto/sha256" "errors" "time" "strings" @@ -21,7 +18,7 @@ const ( KRAKEN_API_URL = "https://api.kraken.com" KRAKEN_API_VERSION = "0" KRAKEN_SERVER_TIME = "Time" - KRAKEN_ASSETS = "ssets" + KRAKEN_ASSETS = "Assets" KRAKEN_ASSET_PAIRS = "AssetPairs" KRAKEN_TICKER = "Ticker" KRAKEN_OHLC = "OHLC" @@ -501,19 +498,14 @@ func (k *Kraken) CancelOrder(orderID int64) { func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values) (interface{}, error) { path := fmt.Sprintf("/%s/private/%s", KRAKEN_API_VERSION, method) values.Set("nonce", strconv.FormatInt(time.Now().UnixNano(), 10)) - secret, err := base64.StdEncoding.DecodeString(k.APISecret) + secret, err := Base64Decode(k.APISecret) if err != nil { return nil, err } - sha := sha256.New() - sha.Write([]byte(values.Get("nonce") + values.Encode())) - shasum := sha.Sum(nil) - - hmac := hmac.New(sha512.New, []byte(secret)) - hmac.Write(append([]byte(path), shasum...)) - signature := base64.StdEncoding.EncodeToString(hmac.Sum(nil)) + shasum := GetSHA256([]byte(values.Get("nonce") + values.Encode())) + signature := Base64Encode(GetHMAC(sha512.New, append([]byte(path), shasum...), secret)) if k.Verbose { log.Printf("Sending POST request to %s, path: %s.", KRAKEN_API_URL, path) diff --git a/lakebtchttp.go b/lakebtchttp.go index c83cce14..1b2a573c 100644 --- a/lakebtchttp.go +++ b/lakebtchttp.go @@ -4,10 +4,7 @@ import ( "net/http" "net/url" "strconv" - "crypto/hmac" "crypto/sha256" - "encoding/base64" - "encoding/hex" "errors" "strings" "time" @@ -177,26 +174,21 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string) (err error v.Set("method", method) v.Set("params", params) - hmac := hmac.New(sha256.New, []byte(l.APISecret)) encoded := v.Encode() - hmac.Write([]byte(encoded)) + hmac := GetHMAC(sha256.New, []byte(encoded), []byte(l.APISecret)) if l.Verbose { log.Printf("Sending POST request to %s calling method %s with params %s\n", LAKEBTC_API_URL, method, encoded) } - reqBody := strings.NewReader(encoded) - hash := hex.EncodeToString(hmac.Sum(nil)) - b64 := base64.StdEncoding.EncodeToString([]byte(l.Email + ":" + hash)) - - req, err := http.NewRequest("POST", LAKEBTC_API_URL, reqBody) + req, err := http.NewRequest("POST", LAKEBTC_API_URL, strings.NewReader(encoded)) if err != nil { return err } req.Header.Add("Json-Rpc-Tonce", nonce) - req.Header.Add("Authorization: Basic", b64) + req.Header.Add("Authorization: Basic", Base64Encode([]byte(l.Email + ":" + HexEncodeToString(hmac)))) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") client := &http.Client{} diff --git a/okcoinhttp.go b/okcoinhttp.go index 33cdde81..91026522 100644 --- a/okcoinhttp.go +++ b/okcoinhttp.go @@ -3,10 +3,8 @@ package main import ( "net/http" "net/url" - "crypto/md5" "errors" "strings" - "encoding/hex" "io/ioutil" "strconv" "fmt" @@ -407,21 +405,17 @@ func (o *OKCoin) GetFuturesUserPosition4Fix(symbol, contractType string) { } func (o *OKCoin) SendAuthenticatedHTTPRequest(method string, v url.Values) (err error) { - hasher := md5.New() - hasher.Write([]byte(v.Encode() + "&secret_key=" + o.SecretKey)) - signature := strings.ToUpper(hex.EncodeToString(hasher.Sum(nil))) - - v.Set("sign", signature) + hasher := GetMD5([]byte(v.Encode() + "&secret_key=" + o.SecretKey)) + v.Set("sign", strings.ToUpper(HexEncodeToString(hasher))) + encoded := v.Encode() + "&partner=" + o.PartnerID path := o.APIUrl + method if o.Verbose { - log.Printf("Signature: %s\n", signature) log.Printf("Sending POST request to %s with params %s\n", path, encoded) } - reqBody := strings.NewReader(encoded) - req, err := http.NewRequest("POST", path, reqBody) + req, err := http.NewRequest("POST", path, strings.NewReader(encoded)) if err != nil { return err