多平台签名认证算法

签名认证

我们会为每位公有云用户分配一个API KEY和一个API SECRET。为了保证安全性,用户的每次访问都需要上传一个签名(基于API KEY和API SECRET获取)。

具体签名方法:

  • 用户自己生成 timestamp(Unix 时间戳), 以及一个随机 nonce,外加自己的 API_KEY。
  • 将timestamp、nonce、API_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII码),并join成一个字符串,然后用API_SECRET对这个字符串做hamc-sha256 签名,以16进制编码。
  • 将上述得到的签名结果作为 signature 的值,与 API_KEY, nonce, timestamp 一起放在HTTP HEADER 的 Authorization 中。

下面以java代码举例:

  • 假设API_KEY = "abcedfg"; API_SECRET =      "1234567890"
  • 获得timestamp(unix时间戳),实现方式:
  • String timestamp = System.currentTimeMillis() + "";

返回timestamp :"1471924244823"

  • 获得随机nonce,最好是32位的uuid,可用下面方式实现:
  • public static synchronized String getUUID(){
  • UUID uuid=UUID.randomUUID();
  • String str = uuid.toString();
  • String nonce=str.replace("-", "");
  • return nonce;
  • }

返回nonce: "86cb646a267c4602913f2034bce0cea4"

  • timestampnonceAPI_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII),并join成一个字符串,可用下面方式实现:
  • public static String genjoinstr(String timestamp,String nonce,String API_KEY){
  •  
  •     ArrayList<String> beforesort = new ArrayList<String>();
  •     beforesort.add(API_KEY);
  •     beforesort.add(timestamp);
  •     beforesort.add(nonce);
  •  
  •     Collections.sort(beforesort, new SpellComparator()); 
  •     StringBuffer aftersort = new StringBuffer();
  •     for (int i = 0; i < beforesort.size(); i++) { 
  •         aftersort.append(beforesort.get(i));
  •     } 
  •  
  •     String join_str = aftersort.toString();
  •     return join_str;
  • }

返回join_str:147192424482386cb646a267c4602913f2034bce0cea4abcdefg

  • API_SECRETjoin_strhamc-sha256签名,且以16进制编码,可用下面方式实现:
  • public static String genEncryptString(String join_str, String API_SECRET){
  •  
  •     Key sk = new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256");
  •     Mac mac = Mac.getInstance(sk.getAlgorithm());
  •     mac.init(sk);
  •     final byte[] hmac = mac.doFinal(join_str.getBytes());//完成hamc-sha256签名
  •     StringBuilder sb = new StringBuilder(hmac.length * 2); 
  •     Formatter formatter = new Formatter(sb);  
  •         for (byte b : hmac) { 
  •             formatter.format("%02x", b); 
  •         } 
  •     String signature = sb.toString();//完成16进制编码
  •     return signature;
  • }

返回经过16进制编码的hamc-sha256签名signature:

eea4300393cd859421fa8eb074781df93ca95d120e9ed0b7b4a92b4537fbccd1

  • 将上述的值按照 #{k}=#{v} 并以 ',' join在一起,可用下面方式实现:
  • public static String genauthorization(String API_KEY, String timestamp, String nonce, String signature){
  •  
  •     String authorization = "key=" + API_KEY
  •                  +",timestamp=" + timestamp
  •                      +",nonce=" + nonce
  •                  +",signature=" + signature;
  •     return authorization;
  • }

返回签名认证字符串:key=abcdefg,timestamp=1471924244823,nonce=86cb646a267c4602913f2034bce0cea4,signature=eea4300393cd859421fa8eb074781df93ca95d120e9ed0b7b4a92b4537fbccd1

  • 将该签名认证字符串赋值给HTTP HEADER  Authorization 中,完成一次接口访问。

C++ 样例

#include <stdio.h> 

#include <string.h> 

#include <iostream> 

#include <algorithm> 

#include <string>

#include <time.h>

#include <stdlib.h>

#include <sstream>

#include <objbase.h>

 

#include<fstream>

 

#include <openssl/hmac.h> 

 

#define GUID_LEN 33

 

using namespace std;

 

int HmacEncode(const char * key, unsigned int key_length,const char * input, unsigned int input_length,

unsigned char * &output, unsigned int &output_length) {

    const EVP_MD * engine = NULL;

 

    engine = EVP_sha256();

    output = (unsigned char*)malloc(EVP_MAX_MD_SIZE);

 

    HMAC_CTX ctx;

    HMAC_CTX_init(&ctx);

    HMAC_Init_ex(&ctx, key, strlen(key), engine, NULL);

    HMAC_Update(&ctx, (unsigned char*)input, strlen(input));        // input is OK; &input is WRONG !!! 

 

    HMAC_Final(&ctx, output, &output_length);

    HMAC_CTX_cleanup(&ctx);

 

    return 0;

};

int main()

{

 

    //--------获取timestamp

    time_t tick;   

    tick = time(NULL);

    char ntimestamp[512] = { 0 };

    _snprintf_s(ntimestamp, sizeof(ntimestamp), "%ld", (long)tick);

 

    //--------获取nonce  

    char nonce[512] = {0};

    GUID guid;

    if (CoCreateGuid(&guid))

    {

        fprintf(stderr, "create guid error\n");

        return -1;

    }

    _snprintf_s(nonce, sizeof(nonce),

        "%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x",

        guid.Data1, guid.Data2, guid.Data3,

        guid.Data4[0], guid.Data4[1], guid.Data4[2],

        guid.Data4[3], guid.Data4[4], guid.Data4[5],

        guid.Data4[6], guid.Data4[7]);

 

    //--------赋值API_KEY

    char api_key[512] = "XXXXXX";

 

    //--------

    char pre_authority[100] = { 0 };

    _snprintf_s(pre_authority, sizeof(pre_authority),

        "key=%s,timestamp=%s,nonce=%s", api_key, ntimestamp, nonce);

    //--------pre_authority

 

    //--------timestampnonceAPI_KEY进行排序连接为str1

    char *str1 = &ntimestamp[0];//timestamp

    char *str2 = &nonce[0];//nonce

    char *str3 = &api_key[0];//api_key

    if (str1[0] > str2[0])

    {

        swap(str1, str2);

    }

    if (str2[0] > str3[0])

    {

        swap(str2, str3);

    }

    if (str1[0] > str2[0])

    {

        swap(str1, str2);

    }

 

 

    strcat_s(str1, 128, str2);

    strcat_s(str1, 128, str3);

 

    //---------赋值API_SECRET

    char secret[] = "xxxxxx";//API_SECRET

 

    //---------API_SECRETstr1hamc-sha256签名

    unsigned int mac_int[32];

    unsigned char mac_char64[100];

    unsigned int mac_mid;

    unsigned char * mac = NULL;

    unsigned int mac_length = 0;

    int j = 0;

 

    int ret = HmacEncode(secret, strlen(secret), str1, strlen(str1), mac, mac_length);

 

 

    //将签名结果转为16进制字符串,存到mac_char64数组作为signature

    for (int i = 0; i < mac_length; i++) {

 

        printf("%-03x", (unsigned int)mac[i]);

        mac_int[i] = (unsigned int)mac[i];

    }

    printf("\n");

 

    for (int i = 0; i < mac_length; i++) {

 

 

        mac_mid = ((mac_int[i] & 0x00f0) >> 4);

 

        if (mac_mid >= 10)

        {

            mac_char64[j++] = mac_mid + 87;

        }

        else

        {

            mac_char64[j++] = mac_mid + 48;

        }

        mac_mid = (mac_int[i] & 0x000f);

        if (mac_mid >= 10)

        {

            mac_char64[j++] = mac_mid + 87;

        }

        else

        {

            mac_char64[j++] = mac_mid + 48;

        }

 

    }

 

    mac_char64[64] = '\0';

 

    //---------key,timestamp,nonce,mac_char64组合成指定格式的字符串赋值给authority

    char authority[256] = {0};

 

    _snprintf_s(authority, sizeof(authority),

        "%s,signature=%s", pre_authority, mac_char64);

 

 

    free(mac);

 

    system("pause");

 

    return 0;

}

Java 样例

package auth_new;

 

import java.util.Comparator;

 

public class SpellComparator implements Comparator<Object> { 

    public int compare(Object o1, Object o2) { 

        try

            String s1 = new String(o1.toString().getBytes("GB2312"), "ISO-8859-1"); 

            String s2 = new String(o2.toString().getBytes("GB2312"), "ISO-8859-1");  

            return s1.compareTo(s2); 

         }catch (Exception e){

             e.printStackTrace(); 

         } 

         return 0; 

    }

}

package auth_new;

 

import java.io.IOException;

import java.security.InvalidKeyException;

import java.security.Key;

import java.security.NoSuchAlgorithmException;

import java.security.SignatureException;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Formatter;

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang.RandomStringUtils;

import org.apache.http.client.ClientProtocolException;

 

import resources.Constants;

 

public class GenerateString {

 

    public static final String id = Constants.ID;

    public static final String secret = Constants.SECRET;

    private static final String HASH_ALGORITHM = "HmacSHA256";

 

    static String api_key = "xxxx";

    static String api_secret = "xxxx";

    static String timestamp = Long.toString(System.currentTimeMillis());

    static String nonce = RandomStringUtils.randomAlphanumeric(16);

 

    public static String genOriString(String api_key){

 

        ArrayList<String> beforesort = new ArrayList<String>();

        beforesort.add(api_key);

        beforesort.add(timestamp);

        beforesort.add(nonce);

 

        Collections.sort(beforesort, new SpellComparator()); 

        StringBuffer aftersort = new StringBuffer();

        for (int i = 0; i < beforesort.size(); i++) { 

            aftersort.append(beforesort.get(i));

        } 

 

        String OriString = aftersort.toString();

        return OriString;

    }

 

    public static String genEncryptString(String genOriString, String api_secret)throws SignatureException {

        try{

            Key sk = new SecretKeySpec(api_secret.getBytes(), HASH_ALGORITHM);

            Mac mac = Mac.getInstance(sk.getAlgorithm());

            mac.init(sk);

            final byte[] hmac = mac.doFinal(genOriString.getBytes());

            StringBuilder sb = new StringBuilder(hmac.length * 2); 

 

                @SuppressWarnings("resource")

                Formatter formatter = new Formatter(sb); 

                for (byte b : hmac) { 

                    formatter.format("%02x", b);  

                } 

            String EncryptedString = sb.toString();

            return EncryptedString;

        }catch (NoSuchAlgorithmException e1){

            throw new SignatureException("error building signature, no such algorithm in device "+ HASH_ALGORITHM);

        }catch (InvalidKeyException e){

            throw new SignatureException("error building signature, invalid key " + HASH_ALGORITHM);

        }

    }

 

    public static String genHeaderParam(String api_key, String api_secret) throws SignatureException{

 

        String GenOriString = genOriString(api_key);

        String EncryptedString = genEncryptString(GenOriString, api_secret);

 

        String HeaderParam = "key=" + api_key

                     +",timestamp=" + timestamp

                         +",nonce=" + nonce

                     +",signature=" + EncryptedString;

        System.out.println(HeaderParam);

        return HeaderParam;

    }

 

    public static void main(String[] args) throws ClientProtocolException, IOException, SignatureException{

        genHeaderParam(id, secret);

    }

}

Ruby 样例

# -*- coding: UTF-8 -*-

require 'openssl'

require 'rubygems'

require 'uuidtools'

 

seq=["","",""]

 

timestamp=Time.now.to_i #获取timestamp

 

nonce=UUIDTools::UUID.timestamp_create().to_s

nonce.gsub!('-','') #获取nonce

 

API_KEY="xxxxxx"

API_SECRET="xxxxxx"

 

seq[0]=timestamp.to_s

seq[1]=nonce.to_s

seq[2]=API_KEY

 

0.upto(seq.length-1) do |i|

  exchange = false

   0.upto(seq.length-1-i-1) do|j|

     if seq[j]>=seq[j+1]

       tmp = seq[j+1]

       seq[j+1] = seq[j]

       seq[j] = tmp

       exchange = true

     end

   end

 

  if !exchange

    break

  end

end

 

seq.each {|num| puts num}

str=seq[0]+seq[1]+seq[2] #获取timestamp,nonce,API_KEY的排序串联字符串

 

puts str

 

signature  = OpenSSL::HMAC.hexdigest('sha256', API_SECRET, str) #API_SECRET对串联字符串做签名

 

authority='key='+API_KEY+',nonce='+nonce.to_s+',timestamp='+timestamp.to_s+',signature='+signature #组成authority

PHP 样例

<?php

define("API_KEY", "Your API_KEY");

define("API_SECRET", "Your API_SECRET");

 

function signString($string_to_sign, $API_SECRET) {

    //对两个字符串做hamc-sha256 签名

    return hash_hmac("sha256", $string_to_sign, $API_SECRET);

}

 

function makeNonce( $length) { 

    // 生成随机 nonce。位数可以自己定

    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 

    $nonce = ''; 

    for ( $i = 0; $i < $length; $i++ )  { 

        $nonce .= $chars[ mt_rand(0, strlen($chars) - 1) ]; 

    } 

    return $nonce;

}

 

function makeStringSignature($nonce,$timestamp,$API_KEY){

    //timestampnonceAPI_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII),并join成一个字符串

    $payload = array(

    'API_KEY' => API_KEY,

    'nonce' => $nonce,

    'timestamp' => $timestamp

    );

    //对首字母排序

    sort($payload);

    //join到一个字符串

    $signature = join($payload);

    return $signature;

}

//生成nonce

$nonce = makeNonce(16);

//生成unix 时间戳timestamp

$timestamp = (string) time();

//timestampnonceAPI_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII),并join成一个字符串stringSignature

$stringSignature = makeStringSignature($nonce,$timestamp,API_KEY);

//stringSignatureAPI_SECREThamc-sha256 签名,生成signature

$signature = signString($stringSignature, API_SECRET);

//将签名认证字符串赋值给HTTP HEADER Authorization

$Authorization = "key=".API_KEY.",timestamp=".$timestamp.",nonce=".$nonce.",signature=".$signature;

echo "Authorization:";

echo "<br>";

echo($Authorization);

 

$testurl = 'https://v2-auth-api.visioncloudapi.com/info/api'; 

$ch = curl_init();

$header= array(                                                                         

  'Content-Type: application/json',                                                                               

  'Authorization: '.$Authorization

  );

 

curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

curl_setopt($ch, CURLOPT_URL, $testurl);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

//打开SSL验证时,需要安装openssl库。也可以选择关闭,关闭会有风险。

$output = curl_exec($ch);  

var_dump($output);  

$output_array = json_decode($output,true);

curl_close($ch);

?>

C# 样例

using System;

using System.Collections.Generic;

using System.Configuration;

using System.Linq;

using System.Security.Cryptography;

using System.Text;

using System.Threading.Tasks;

 

namespace XXXX

{

    /// <summary>

    /// 授权认证帮助类

    /// </summary>

    public class AuthHelper

    {

        /// <summary>

        /// 获取签名认证字符串

        /// </summary>

        /// <param name="name">登录名</param>

        /// <param name="pwd">密码</param>

        /// <param name="platid">授权平台ID</param>

        /// <returns></returns>

        public static string GetAuthString(string name, string pwd, string platid = null)

        {

            string

                API_KEY = name,

                API_SECRET = pwd,

                timestamp = GetTimestamp(DateTime.Now).ToString(),

                nonce = GetNonce();

 

            string

                join_str = GenJoinStr(timestamp, nonce, API_KEY, platid),

                signature = GenEncryptString(join_str, API_SECRET);

 

            return GenAuthorization(API_KEY, timestamp, nonce, signature, platid);

        }

 

        /// <summary>

        /// 获取时间戳

        /// </summary>

        /// <param name="time">本地时间</param>

        /// <returns>时间戳</returns>

        public static long GetTimestamp(DateTime time)

        {

            return (time.ToUniversalTime().Ticks - 621355968000000000) / 10000000;

        }

 

        /// <summary>

        /// 获取随机nonce

        /// </summary>

        /// <returns></returns>

        public static string GetNonce()

        {

            return Guid.NewGuid().ToString().Replace("-", string.Empty);

        }

 

        /// <summary>

        /// 将timestamp、nonce、API_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII码),并join成一个字符串

        /// </summary>

        /// <param name="timestamp"></param>

        /// <param name="nonce"></param>

        /// <param name="API_KEY"></param>

        /// <param name="platid">授权平台ID</param>

        /// <returns></returns>

        public static string GenJoinStr(string timestamp, string nonce, string API_KEY, string platid = null)

        {

            List<string> beforesort = new List<string>();

            beforesort.Add(API_KEY);

            beforesort.Add(timestamp);

            beforesort.Add(nonce);

 

            if (!string.IsNullOrWhiteSpace(platid))

                beforesort.Add(platid);

 

            beforesort.Sort();

 

            StringBuilder aftersort = new StringBuilder();

            for (int i = 0; i < beforesort.Count; i++)

                aftersort.Append(beforesort[i]);

 

            string join_str = aftersort.ToString();

            return join_str;

        }

 

        /// <summary>

        /// 用API_SECRET对join_str做hamc-sha256签名,且以16进制编码

        /// </summary>

        /// <param name="join_str"></param>

        /// <param name="API_SECRET"></param>

        /// <returns></returns>

        public static string GenEncryptString(string join_str, string API_SECRET)

        {

            StringBuilder sb = new StringBuilder();

 

            var encoding = new ASCIIEncoding();

            byte[] keyByte = encoding.GetBytes(API_SECRET);

            byte[] messageBytes = encoding.GetBytes(join_str);

            using (var hmacsha256 = new HMACSHA256(keyByte))

            {

                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);

 

                foreach (byte b in hashmessage)

                    sb.Append(b.ToString("x2"));

 

                return sb.ToString();

            }

        }

 

        /// <summary>

        /// 将上述的值按照 #{k}=#{v} 并以 ',' join在一起

        /// </summary>

        /// <param name="API_KEY"></param>

        /// <param name="timestamp"></param>

        /// <param name="nonce"></param>

        /// <param name="signature"></param>

        /// <param name="platid">授权平台ID</param>

        /// <returns></returns>

        public static string GenAuthorization(string API_KEY, string timestamp, string nonce, string signature, string platid = null)

        {

            string authorization =

                "key=" + API_KEY

                + ",timestamp=" + timestamp

                + ",nonce=" + nonce

                + ",signature=" + signature;

 

            if (!string.IsNullOrWhiteSpace(platid))

                authorization += ",platid=" + platid;

 

            return authorization;

        }

    }

}

posted @ 2017-08-18 16:53  代码啦  阅读(1059)  评论(0编辑  收藏  举报