欢迎您来到腾讯云!积分商城

腾讯云腾讯云论坛

 找回密码
 立即注册
快捷导航
搜索
查看: 28010|回复: 18

usersig 生成算法 python 描述

[复制链接]

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2016-3-3 15:40:13 |显示全部楼层
由于我们的用户使用的后台的工具和平台不尽相同,而我们 api 所能适应的平台是有限的,所以在此简要描述下 usersig 的生成算法,以便在用户需要而我们又没有提供时,用户可以自己进行实现。下面是 python 描述的算法(其实直接可以用的),
  1. #! /usr/bin/python
  2. # coding:utf-8

  3. __author__ = "tls@tencent.com"
  4. __date__ = "$Mar 3, 2016 03:00:43 PM"

  5. import OpenSSL
  6. import base64
  7. import zlib
  8. import json
  9. import time

  10. ecdsa_pri_key = """
  11. -----BEGIN EC PARAMETERS-----
  12. BgUrgQQACg==
  13. -----END EC PARAMETERS-----
  14. -----BEGIN EC PRIVATE KEY-----
  15. MHQCAQEEIEJDBDY4KVdj3dPBacADreB772ok45A57YWrUUvc5fMQoAcGBSuBBAAK
  16. oUQDQgAEaPVFHhWqRDnKnVlyU5JIzXOUyOJd/pPUwhLUovf+PYBm7otRBptnvJ4E
  17. oJ4qeSJNG0v4XdiqM3mtChkhUEFT3Q==
  18. -----END EC PRIVATE KEY-----
  19. """

  20. def list_all_curves():
  21.     list = OpenSSL.crypto.get_elliptic_curves()
  22.     for element in list:
  23.         print element

  24. def get_secp256k1():
  25.     print OpenSSL.crypto.get_elliptic_curve('secp256k1');


  26. def base64_encode_url(data):
  27.     base64_data = base64.b64encode(data)
  28.     base64_data = base64_data.replace('+', '*')
  29.     base64_data = base64_data.replace('/', '-')
  30.     base64_data = base64_data.replace('=', '_')
  31.     return base64_data

  32. def base64_decode_url(base64_data):
  33.     base64_data = base64_data.replace('*', '+')
  34.     base64_data = base64_data.replace('-', '/')
  35.     base64_data = base64_data.replace('_', '=')
  36.     raw_data = base64.b64decode(base64_data)
  37.     return raw_data

  38. class TLSSigAPI:
  39.     """"""   
  40.     __acctype = 0
  41.     __identifier = ""
  42.     __appid3rd = ""
  43.     __sdkappid = 0
  44.     __version = 20151204
  45.     __expire = 3600*24*30       # 默认一个月,需要调整请自行修改
  46.     __pri_key = ""
  47.     __pub_key = ""
  48.     _err_msg = "ok"

  49.     def __get_pri_key(self):
  50.         return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, self.__pri_key);

  51.     def __init__(self, sdkappid, pri_key):
  52.         self.__sdkappid = sdkappid
  53.         self.__pri_key = pri_key

  54.     def __create_dict(self):
  55.         m = {}
  56.         m["TLS.account_type"] = "%d" % self.__acctype
  57.         m["TLS.identifier"] = "%s" % self.__identifier
  58.         m["TLS.appid_at_3rd"] = "%s" % self.__appid3rd
  59.         m["TLS.sdk_appid"] = "%d" % self.__sdkappid
  60.         m["TLS.expire_after"] = "%d" % self.__expire
  61.         m["TLS.version"] = "%d" % self.__version
  62.         m["TLS.time"] = "%d" % time.time()
  63.         return m

  64.     def __encode_to_fix_str(self, m):
  65.         fix_str = "TLS.appid_at_3rd:"+m["TLS.appid_at_3rd"]+"\n" \
  66.                   +"TLS.account_type:"+m["TLS.account_type"]+"\n" \
  67.                   +"TLS.identifier:"+m["TLS.identifier"]+"\n" \
  68.                   +"TLS.sdk_appid:"+m["TLS.sdk_appid"]+"\n" \
  69.                   +"TLS.time:"+m["TLS.time"]+"\n" \
  70.                   +"TLS.expire_after:"+m["TLS.expire_after"]+"\n"
  71.         return fix_str

  72.     def tls_gen_sig(self, identifier):
  73.         self.__identifier = identifier

  74.         m = self.__create_dict()
  75.         fix_str = self.__encode_to_fix_str(m)
  76.         pk_loaded = self.__get_pri_key()
  77.         sig_field = OpenSSL.crypto.sign(pk_loaded, fix_str, "sha256");
  78.         sig_field_base64 = base64.b64encode(sig_field)
  79.         m["TLS.sig"] = sig_field_base64
  80.         json_str = json.dumps(m)
  81.         sig_cmpressed = zlib.compress(json_str)
  82.         base64_sig = base64_encode_url(sig_cmpressed)
  83.         return base64_sig

  84. def main():
  85.     api = TLSSigAPI(1400001052, ecdsa_pri_key)
  86.     sig = api.tls_gen_sig("xiaojun")
  87.     print sig

  88. if __name__ == "__main__":
  89.     main()
复制代码
下面用文字简要描述下,
1.将用户的信息组装成一个字符串(json格式的,是直接拼装的,因为顺序不能乱),是哪些信息,可以看 __encode_to_fix_str;
2.使用 sha256 将字符串 hash,然后再用私钥签名,一般加密接口都会一把搞定,加密曲线使用的是 secp256k1;
3.把第2步得到的缓冲区进行base64;
4.将所有用户的信息以及第3步得到签名写进一个 json 串,此时可以不论顺序;
5.将 json 进行序列化,再 zlib 压缩,最后 base64(替换了某些字符,具体哪些看代码),出炉。

特别注意,这段代码在 windows 上验证没问题,但是红帽系(rel 和 centos)上不支持我们使用的曲线,list_all_curves 可以打印所有支持的曲线,红帽系的没有 secp256k1。

如果发现系统所带的 openssl 扩展不支持我们选定的曲线,可以参考 http://bbs.qcloud.com/thread-23280-1-1.html


0

主题

0

好友

52

积分

小白[LV1]

Rank: 1

云币
25
威望
25
发表于 2016-5-3 15:20:44 |显示全部楼层
请问有golang的没有
回复

使用道具 举报

1

主题

0

好友

91

积分

小白[LV1]

Rank: 1

云币
45
威望
41
发表于 2016-5-10 02:13:24 |显示全部楼层
第3步说替换了某些字符,但是看代码并没有替换啊。
直接用了base64库函数,并没用到base64_encode_url。
回复

使用道具 举报

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2016-6-1 10:08:04 |显示全部楼层
随风巽 发表于 2016-5-3 15:20
请问有golang的没有

暂时没有
回复

使用道具 举报

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2016-6-1 10:08:09 |显示全部楼层
随风巽 发表于 2016-5-3 15:20
请问有golang的没有

暂时没有
回复

使用道具 举报

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2016-6-1 10:10:42 |显示全部楼层
iNVAiN 发表于 2016-5-10 02:13
第3步说替换了某些字符,但是看代码并没有替换啊。
直接用了base64库函数,并没用到base64_encode_url。 ...

不好意思笔误,已经修改,因为是内部字段,标准 base64 就够了。
回复

使用道具 举报

1

主题

0

好友

283

积分

程序猿[LV2]

Rank: 2Rank: 2

云币
135
威望
135
发表于 2016-6-6 16:43:14 |显示全部楼层
有 python3 的 实现不??
回复

使用道具 举报

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2016-6-12 10:48:34 |显示全部楼层
kelinzhongke 发表于 2016-6-6 16:43
有 python3 的 实现不??

算法本身没有依赖于 python 的版本,尝试使用 openssl 模块 python3 的版本。
回复

使用道具 举报

0

主题

0

好友

32

积分

小白[LV1]

Rank: 1

云币
15
威望
15
发表于 2016-9-8 19:29:00 |显示全部楼层
Go语言Linux系统下的实现已在附件中提供……
回复

使用道具 举报

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2016-10-11 21:33:12 |显示全部楼层
随风巽 发表于 2016-5-3 15:20
请问有golang的没有

有一个 wrapped 版本 http://bbs.qcloud.com/thread-21826-1-1.html
回复

使用道具 举报

0

主题

0

好友

22

积分

小白[LV1]

Rank: 1

云币
10
威望
10
发表于 2017-1-3 17:28:34 |显示全部楼层
TLS帐号支持 发表于 2016-6-12 10:48
算法本身没有依赖于 python 的版本,尝试使用 openssl 模块 python3 的版本。

python3各种编译不过啊
回复

使用道具 举报

0

主题

0

好友

30

积分

小白[LV1]

Rank: 1

云币
70
威望
30
发表于 2017-1-11 15:25:14 |显示全部楼层
拿下来,什么都不动,报错,请问是什么问题?
Traceback (most recent call last):
  File "test.py", line 99, in <module>
    main()
  File "test.py", line 95, in main
    sig = api.tls_gen_sig("xiaojun")
  File "test.py", line 84, in tls_gen_sig
    pk_loaded = self.__get_pri_key()
  File "test.py", line 53, in __get_pri_key
    return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, self.__pri_key);
  File "/usr/local/python2.7.12/lib/python2.7/site-packages/OpenSSL/crypto.py", line 2583, in load_privatekey
    _raise_current_error()
  File "/usr/local/python2.7.12/lib/python2.7/site-packages/OpenSSL/_util.py", line 48, in exception_from_error_queue
    raise exception_type(errors)
OpenSSL.crypto.Error: []

回复

使用道具 举报

0

主题

0

好友

40

积分

小白[LV1]

Rank: 1

云币
40
威望
40
发表于 2017-3-9 16:51:32 |显示全部楼层
使用上面客户端生成的sign去登录报如下错误

{"ActionStatus":"FAIL","ErrorCode":70009,"ErrorInfo":"tls_check_signature failed  decrypt sig failed failed iRet:-2
回复

使用道具 举报

0

主题

0

好友

20

积分

小白[LV1]

Rank: 1

云币
70
威望
20
发表于 2017-12-22 14:26:21 |显示全部楼层
  1. #! /usr/bin/python
  2. # coding:utf-8

  3. __author__ = "tls@tencent.com"
  4. __date__ = "$Mar 3, 2016 03:00:43 PM"

  5. import OpenSSL
  6. import base64
  7. import zlib
  8. import json
  9. import time

  10. ecdsa_pri_key = """
  11. -----BEGIN EC PARAMETERS-----
  12. BgUrgQQACg==
  13. -----END EC PARAMETERS-----
  14. -----BEGIN EC PRIVATE KEY-----
  15. MHQCAQEEIEJDBDY4KVdj3dPBacADreB772ok45A57YWrUUvc5fMQoAcGBSuBBAAK
  16. oUQDQgAEaPVFHhWqRDnKnVlyU5JIzXOUyOJd/pPUwhLUovf+PYBm7otRBptnvJ4E
  17. oJ4qeSJNG0v4XdiqM3mtChkhUEFT3Q==
  18. -----END EC PRIVATE KEY-----
  19. """


  20. def list_all_curves():
  21.     list = OpenSSL.crypto.get_elliptic_curves()
  22.     for element in list:
  23.         print(element)


  24. def get_secp256k1():
  25.     print(OpenSSL.crypto.get_elliptic_curve('secp256k1'))


  26. def base64_encode_url(data):
  27.     base64_data = base64.b64encode(data)
  28.     base64_data = base64_data.replace(b'+', b'*')
  29.     base64_data = base64_data.replace(b'/', b'-')
  30.     base64_data = base64_data.replace(b'=', b'_')
  31.     return base64_data


  32. def base64_decode_url(base64_data):
  33.     base64_data = base64_data.replace(b'*', b'+')
  34.     base64_data = base64_data.replace(b'-', b'/')
  35.     base64_data = base64_data.replace(b'_', b'=')
  36.     raw_data = base64.b64decode(base64_data)
  37.     return raw_data


  38. class TLSSigAPI:
  39.     """"""
  40.     __acctype = 0
  41.     __identifier = ""
  42.     __appid3rd = ""
  43.     __sdkappid = 0
  44.     __version = 20151204
  45.     __expire = 3600 * 24 * 30  # 默认一个月,需要调整请自行修改
  46.     __pri_key = ""
  47.     __pub_key = ""
  48.     _err_msg = "ok"

  49.     def __get_pri_key(self):
  50.         return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, self.__pri_key)

  51.     def __init__(self, sdkappid, pri_key):
  52.         self.__sdkappid = sdkappid
  53.         self.__pri_key = pri_key

  54.     def __create_dict(self):
  55.         return {"TLS.account_type": "%d" % self.__acctype, "TLS.identifier": "%s" % self.__identifier,
  56.                 "TLS.appid_at_3rd": "%s" % self.__appid3rd, "TLS.sdk_appid": "%d" % self.__sdkappid,
  57.                 "TLS.expire_after": "%d" % self.__expire, "TLS.version": "%d" % self.__version,
  58.                 "TLS.time": "%d" % time.time()}

  59.     def __encode_to_fix_str(self, m):
  60.         fix_str = "TLS.appid_at_3rd:" + m["TLS.appid_at_3rd"] + "\n" \
  61.                   + "TLS.account_type:" + m["TLS.account_type"] + "\n" \
  62.                   + "TLS.identifier:" + m["TLS.identifier"] + "\n" \
  63.                   + "TLS.sdk_appid:" + m["TLS.sdk_appid"] + "\n" \
  64.                   + "TLS.time:" + m["TLS.time"] + "\n" \
  65.                   + "TLS.expire_after:" + m["TLS.expire_after"] + "\n"
  66.         return fix_str

  67.     def tls_gen_sig(self, identifier):
  68.         self.__identifier = identifier
  69.         m = self.__create_dict()
  70.         fix_str = self.__encode_to_fix_str(m)
  71.         pk_loaded = self.__get_pri_key()
  72.         sig_field = OpenSSL.crypto.sign(pk_loaded, fix_str, "sha256")
  73.         sig_field_base64 = base64.b64encode(sig_field)
  74.         m["TLS.sig"] = sig_field_base64.decode('utf-8')
  75.         json_str = json.dumps(m)
  76.         sig_compressed = zlib.compress(json_str.encode('utf-8'))
  77.         base64_sig = base64_encode_url(sig_compressed)
  78.         return base64_sig


  79. def main():
  80.     api = TLSSigAPI(1400001052, ecdsa_pri_key)
  81.     sig = api.tls_gen_sig("xiaojun")
  82.     print(sig)


  83. if __name__ == "__main__":
  84.     main()
复制代码
python3.5.2 版本。
需要安装 pip install pyOpenSSL

centos  内核
Linux localhost.localdomain 2.6.32-696.10.2.el6.x86_64 #1 SMP Tue Sep 12 14:33:29 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
下测试该代码是Ok的。 windows 10 下测试OK的。 其他没有做测试。。
回复

使用道具 举报

0

主题

0

好友

40

积分

小白[LV1]

Rank: 1

云币
140
威望
40
发表于 2017-12-27 16:58:11 |显示全部楼层
xyCoder 发表于 2017-12-22 14:26
python3.5.2 版本。
需要安装 pip install pyOpenSSL

ecdsa_pri_key是什么呢。是怎么获取的
回复

使用道具 举报

0

主题

0

好友

40

积分

小白[LV1]

Rank: 1

云币
140
威望
40
发表于 2017-12-27 17:02:44 |显示全部楼层
ecdsa_pri_key是什么呢。是怎么获取的
回复

使用道具 举报

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2018-1-9 11:52:06 |显示全部楼层
tom2213 发表于 2017-12-27 17:02
ecdsa_pri_key是什么呢。是怎么获取的

用工具转换的。
回复

使用道具 举报

23

主题

1

好友

1216

积分

版主

Rank: 10Rank: 10Rank: 10Rank: 10

云币
2903
威望
1216
发表于 2018-1-10 10:10:43 |显示全部楼层
TLS帐号支持 发表于 2018-1-9 11:52
用工具转换的。

https://share.weiyun.com/2b3abe0e3f185c440cf455647455f661下载api后里面有个openssl 工具,然后使用     ./openssl ec -outform PEM -inform PEM -in private_key -out private_ec.pem     命令转换即可。
回复

使用道具 举报

0

主题

0

好友

30

积分

小白[LV1]

Rank: 1

云币
120
威望
30
发表于 2018-4-20 12:42:28 |显示全部楼层
xyCoder 发表于 2017-12-22 14:26
python3.5.2 版本。
需要安装 pip install pyOpenSSL

mac os python 3.6 代码可以通过。

但是使用 python 2.7 会出现错误:
Traceback (most recent call last):
    sig_field = OpenSSL.crypto.sign(pk_loaded, fix_str, "sha256");
Error: [('digital envelope routines', 'EVP_SignFinal', 'wrong public key type')]

没有仔细了解 OpenSSL,从https://stackoverflow.com/questions/6887992/problem-using-openssl-net-to-sign-a-certificate找到一个相似问题。可能的解决方案是使用 BouncyCastle代替 OpenSSL。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

联系我们|腾讯云平台|积分商城|腾讯云官方论坛    

GMT+8, 2020-7-14 17:16 , Processed in 1.129843 second(s), 27 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部