使用 HMAC SHA512 从 API 获取数据 - Swift

Posted

技术标签:

【中文标题】使用 HMAC SHA512 从 API 获取数据 - Swift【英文标题】:Fetching data from API with HMAC SHA512 - Swift 【发布时间】:2017-01-11 07:10:38 【问题描述】:

我正在尝试使用here 描述的 API。它使用基于密钥的 HMAC SHA512 授权。

有一个php实现的例子:

function bitmarket_api($method, $params = array())

  $key = "klucz_jawny";
  $secret = "klucz_tajny";

  $params["method"] = $method;
  $params["tonce"] = time();

  $post = http_build_query($params, "", "&");
  $sign = hash_hmac("sha512", $post, $secret);
  $headers = array(
      "API-Key: " . $key,
      "API-Hash: " . $sign,
  );

  $curl = curl_init();
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_URL, "https://www.bitmarket.pl/api2/");
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  $ret = curl_exec($curl);

  return json_decode($ret);

然后我尝试在 Swift 中实现它:

import Alamofire
import CryptoSwift

func getRawJSON(method: String, params: [String]) -> String 
    let publicKey = "publicKeyHere"
    let secretKey = "secretKeyHere"
    let APIURL = "https://www.bitmarket.pl/api2/"

    var params = [
        "method": method,
        "tonce:": NSDate().timeIntervalSince1970
        ] as [String : Any]

    let hmac: Array<UInt8> = try! HMAC(key: secretKey.utf8.map($0), variant: .sha512).authenticate(params)

    var headers = [
        "API-Key": publicKey,
        "API-Hash": hmac
    ] as [String : Any]

您可能已经注意到,目前还没有使用 Alamofire 来获取数据,因为我在准备要发送的数据时遇到了问题。我的意思是我用 CryptoSwift 搞砸了一些东西,因为我得到了这个错误:Cannot convert value of type '[String : Any]' to expected argument type 'Array&lt;UInt8&gt;' 当我试图声明 hmac 变量时。

如何解决? 我可能必须以某种方式将params 数组转换为Array&lt;UInt8,但我不知道该怎么做。我也不确定一切是否正确。

编辑: 感谢 Martin R,实际代码是:

func getRawJSON(method: String, paramether: String) 
    let publicKey = "publicKeyHere"
    let secretKey = "secretKeyHere"
    let APIURL = "https://www.bitmarket.pl/api2/"

    let query = NSURLComponents()
    query.queryItems = [NSURLQueryItem(name: "method", value: method) as URLQueryItem,
                        NSURLQueryItem(name: "tonce", value: String(Int(NSDate().timeIntervalSince1970))) as URLQueryItem]

    let requestString = query.query!
    let requestData = Array(requestString.utf8)

    let params = [
        "method": method,
        "tonce:": String(Int(NSDate().timeIntervalSince1970))
        ] as [String : Any]

    let hmac: Array<UInt8> = try! HMAC(key: secretKey.utf8.map($0), variant: .sha512).authenticate(requestData)

    let hmacData = Data(bytes: hmac)
    let hmacString = hmacData.base64EncodedString()

    let headers = [
        "API-Key": publicKey,
        "API-Hash": hmacString
    ] as [String : String]

    Alamofire.request(APIURL, withMethod: .post, parameters: params, encoding: .url, headers: headers)
        .responseJSON  response in
        print(response)
    

不幸的是,在调用函数 (getRawJSON(method: "info", paramether: "")) 后,我正在获取一个错误的 JSON:


error = 502;
errorMsg = "Invalid message hash";
time = 1472910139;

我的哈希有什么问题?

【问题讨论】:

【参考方案1】:

您的 Swift 代码缺少什么

$post = http_build_query($params, "", "&");

在 PHP 版本中的作用:从给定的参数创建一个查询字符串。 您可以“手动”构建该字符串,也可以使用 NSURLComponents:

let comps = NSURLComponents()
comps.queryItems = [ NSURLQueryItem(name: "method",
                                    value: "YOUR_METHOD"),
                     NSURLQueryItem(name: "tonce",
                                    value: String(Int(NSDate().timeIntervalSince1970))) ]
let requestString = comps.query!
print(requestString) // method=YOUR_METHOD&tonce=1472893376

最后将此字符串转换为 HMAC 的 [UInt8] 数组 功能:

let requestData = Array(requestString.utf8)
print(requestData) // [109, 101, 116, ..., 54]

【讨论】:

非常感谢,帮了大忙。现在我遇到了哈希问题,用更多细节编辑了我的问题。 @kkarol:将 PHP 代码中的 $post$sign 值与 Swift 代码中的 requestStringhmac 进行比较。 requestString 等于$post,但$sign 不同于hmachmacStringhmacString 是 base64 而 $sign 包含例如450043310da274122369bfc0ca621e47fb0b03857746c096a944748585fcd3280744ee4633711f98bbfe3bf0c199deec329a64b723799e597304cfd683ac40e6。不知道如何将Array&lt;UInt8&gt; 转换为正确的格式。 @kkarol:您必须将数据转换为 十六进制字符串,而不是 Base64 编码字符串。参见例如***.com/a/38131414/1187415。

以上是关于使用 HMAC SHA512 从 API 获取数据 - Swift的主要内容,如果未能解决你的问题,请参考以下文章

PBKDF2-HMAC-SHA-512 测试向量

网络安全——Base64编码MD5SHA1-SHA512HMAC(SHA1-SHA512)哈希

Axios加密的POST参数

hmac sha256和sha256的区别

hashilib模块和hmac模块

HMAC加密的消息摘要码