Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5119567
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: Python/Ruby

2013-10-21 15:35:01

文章来自:http://blog.csdn.net/kevin6216/article/details/7573753

用python实现调用接口的示例代码,过程涉及到很多的加密算法,值得分享一下。

首先公钥和私钥如何生成,并且能兼容java平台,尝试了很多方法。最终决定用openssl命令
前提,需要安装openssl,Crypto库
生成公钥私钥对过程:
生成私钥:

  1. openssl genrsa -out rsa_private_key.pem 1024
根据私钥生成公钥:

  1. openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
这时候的私钥还不能直接被使用,需要进行PKCS#8编码


  1. openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt

命令中指明了输入私钥文件为rsa_private_key.pem,输出私钥文件为pkcs8_rsa_private_key.pem,不采用任何二次加密(-nocrypt)
这时候就获得了一对公钥和私钥,只要拿到对方的公钥,用自己的公钥的格式替换就可以使用啦~~ 

我们最好把全局变量给提出来,便于管理。这样子就不用改代码都改一遍了


文件Gl.py


  1. #!-*- coding:utf-8 -*-
  2. '''
  3. Created on 2013-6-15
  4.   
  5. @author: shangwei
  6. '''
  7. '''
  8. 全局变量
  9. '''
  10. from Crypto.PublicKey import RSA
  11. '''
  12. publickey为对方的公钥
  13. privatekey为商户自己的私钥
  14. '''
  15. publickey = RSA.importKey(open('rsa_public_key.pem','r').read())
  16. privatekey=RSA.importKey(open('pkcs8_rsa_private_key.pem','r').read())
  17. merchantaccount='YB010000000xx'
  18. URL='xxx.xxx.com'


  1. #!-*- coding:utf-8 -*-
  2.     '''
  3.     Created on 2013-5-24
  4.       
  5.     @author: shangwei
  6.     '''
  7.     from Crypto import Random
  8.     from Crypto.Cipher import PKCS1_v1_5
  9.     from Crypto.Hash import SHA
  10.     from hashlib import sha1
  11.     from rsa import key, common, encrypt
  12.     from urllib import urlencode
  13.     import base64
  14.     import hmac
  15.     from Crypto.PublicKey import RSA
  16.     import urllib
  17.     import urllib2
  18.     import time
  19.     import json
  20.     from Crypto.Signature import PKCS1_v1_5 as pk
  21.     import Gl
  22.     class MerchantAPI:
  23.           
  24.         def doPost(self,url,values):
  25.             '''
  26.             post请求
  27.             参数URL
  28.             字典类型的参数
  29.             '''
  30.             req = urllib2.Request(url)
  31.             data = urllib.urlencode(values)
  32.             res = urllib2.urlopen(req, data)
  33.             ret = res.read()
  34.             return ret
  35.       
  36.           
  37.         def doGet(self,url,values):
  38.             '''
  39.             get请求
  40.             参数URL
  41.             字典类型的参数
  42.             '''
  43.             REQUEST = url + "?" + urllib.urlencode(values)
  44.             ret = urllib2.urlopen(REQUEST).read()
  45.             return ret
  46.             
  47.         @staticmethod
  48.         def _pkcs7padding(data):
  49.             """
  50.             对齐块
  51.             size 16
  52.             999999999=>9999999997777777
  53.             """
  54.             size = AES.block_size
  55.             count = size - len(data)%size
  56.             if count:
  57.                 data+=(chr(count)*count)
  58.             return data
  59.           
  60.           
  61.       
  62.           
  63.           
  64.         @staticmethod
  65.         def _depkcs7padding(data):
  66.             """
  67.             反对齐
  68.             """
  69.             newdata = ''
  70.             for c in data:
  71.                 if ord(c) > AES.block_size:
  72.                     newdata+=c
  73.             return newdata
  74.           
  75.           
  76.         '''
  77.         aes加密base64编码
  78.         '''
  79.         def aes_base64_encrypt(self,data,key):
  80.               
  81.             """
  82.             @summary:
  83.                 1. pkcs7padding
  84.                 2. aes encrypt
  85.                 3. base64 encrypt
  86.             @return:
  87.                 string
  88.             """
  89.             cipher = AES.new(key)
  90.             return base64.b64encode(cipher.encrypt(self._pkcs7padding(data)))
  91.       
  92.       
  93.         def base64_aes_decrypt(self,data,key):
  94.             """
  95.             1. base64 decode
  96.             2. aes decode
  97.             3. dpkcs7padding
  98.             """
  99.             cipher = AES.new(key)
  100.             return self._depkcs7padding(cipher.decrypt(base64.b64decode(data)))
  101.               
  102.         '''
  103.         rsa加密
  104.         '''
  105.         def rsa_base64_encrypt(self,data,key):
  106.             '''
  107.             1. rsa encrypt
  108.             2. base64 encrypt
  109.             '''
  110.             cipher = PKCS1_v1_5.new(key)
  111.             return base64.b64encode(cipher.encrypt(data))
  112.           
  113.         '''
  114.         rsa解密
  115.         '''
  116.         def rsa_base64_decrypt(self,data,key):
  117.             '''
  118.             1. base64 decrypt
  119.             2. rsa decrypt
  120.             示例代码
  121.               
  122.            key = RSA.importKey(open('privkey.der').read())
  123.             >>>
  124.             >>> dsize = SHA.digest_size
  125.             >>> sentinel = Random.new().read(15+dsize) # Let's assume that average data length is 15
  126.             >>>
  127.             >>> cipher = PKCS1_v1_5.new(key)
  128.             >>> message = cipher.decrypt(ciphertext, sentinel)
  129.             >>>
  130.             >>> digest = SHA.new(message[:-dsize]).digest()
  131.             >>> if digest==message[-dsize:]: # Note how we DO NOT look for the sentinel
  132.             >>> print "Encryption was correct."
  133.             >>> else:
  134.             >>> print "Encryption was not correct."
  135.             '''
  136.             cipher = PKCS1_v1_5.new(key)
  137.             return cipher.decrypt(base64.b64decode(data), Random.new().read(15+SHA.digest_size))
  138.               
  139.         '''
  140.         RSA签名
  141.         '''
  142.         def sign(self,signdata):
  143.             '''
  144.             @param signdata: 需要签名的字符串
  145.             '''
  146.               
  147.             h=SHA.new(signdata)
  148.             signer = pk.new(Gl.privatekey)
  149.             signn=signer.sign(h)
  150.             signn=base64.b64encode(signn)
  151.             return signn
  152.              
  153.         '''
  154.         RSA验签
  155.         结果:如果验签通过,则返回The signature is authentic
  156.              如果验签不通过,则返回"The signature is not authentic."
  157.         '''
  158.         def checksign(self,rdata):
  159.               
  160.             signn=base64.b64decode(rdata.pop('sign'))
  161.             signdata=self.sort(rdata)
  162.             verifier = pk.new(Gl.publickey)
  163.             if verifier.verify(SHA.new(signdata), signn):
  164.                 print "The signature is authentic."
  165.             else:
  166.                 print "The signature is not authentic."
  167.                
  168.           
  169.               
  170.               
  171.           
  172.         def sort(self,mes):
  173.             '''
  174.             作用类似与java的treemap,
  175.             取出key值,按照字母排序后将value拼接起来
  176.             返回字符串
  177.             '''
  178.             _par = []
  179.              
  180.             keys=mes.keys()
  181.             keys.sort()
  182.             for v in keys:
  183.                 _par.append(str(mes[v]))
  184.             sep=''
  185.             message=sep.join(_par)
  186.             return message
  187.           
  188.         '''
  189.         请求接口前的加密过程
  190.         '''
  191.         def requestprocess(self,mesdata):
  192.             '''
  193.             加密过程:
  194.             1、将需要的参数mes取出key排序后取出value拼成字符串signdata
  195.             2、用signdata对商户私钥进行rsa签名,生成签名signn,并转base64格式
  196.             3、将签名signn插入到mesdata的最后生成新的data
  197.             4、用encryptkey16位常量对data进行AES加密后转BASE64,生成机密后的data
  198.             5、用对方公钥publickey对encryptkey16位常量进行RSA加密BASE64编码,生成加密后的encryptkey
  199.             '''
  200.             signdata=self.sort(mesdata)
  201.             print '需要签名的排序后的字符串为:'+signdata
  202.             signn=self.sign(signdata)
  203.       
  204.                 
  205.             mesdata['sign']=signn
  206.             print mesdata
  207.             encryptkey = '1234567890123456'
  208.             data=self.aes_base64_encrypt(json.dumps(mesdata),encryptkey)
  209.           
  210.             print '加密后的data='+data
  211.             values={}
  212.             values['merchantaccount']=Gl.merchantaccount
  213.             values['data']=data
  214.             values['encryptkey']=self.rsa_base64_encrypt(encryptkey,Gl.publickey)
  215.             return values
  216.           
  217.           
  218.         '''
  219.         对返回结果进行解密后输出
  220.         '''
  221.         def result_decrypt(self,result):
  222.             '''
  223.             1、返回的结果json传给data和encryptkey两部分,都为加密后的
  224.             2、用商户私钥对encryptkey进行RSA解密,生成解密后的encryptkey。参考方法:rsa_base64_decrypt
  225.             3、用解密后的encryptkey对data进行AES解密。参考方法:base64_aes_decrypt
  226.             '''
  227.             result=json.loads(result)
  228.             kdata=result['data']
  229.             kencryptkey=result['encryptkey']
  230.             print '返回的加密后的data='+kdata
  231.             print '返回的加密后的encryptkey='+kencryptkey
  232.             cryptkey=self.rsa_base64_decrypt(kencryptkey,Gl.privatekey)
  233.             print '解密后的encryptkey='+cryptkey
  234.             rdata=self.base64_aes_decrypt(kdata,cryptkey)
  235.             print '解密后的data='+rdata
  236.             return rdata
  237.          
  238.         def testCreditPayAsync(self):
  239.             '''
  240.             生成公钥私钥对过程:
  241.             生成私钥:openssl genrsa -out rsa_private_key.pem 1024
  242.             根据私钥生成公钥: openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
  243.             这时候的私钥还不能直接被使用,需要进行PKCS#8编码:
  244.             openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt
  245.             命令中指明了输入私钥文件为rsa_private_key.pem,输出私钥文件为pkcs8_rsa_private_key.pem,不采用任何二次加密(-nocrypt)
  246.             加密过程:
  247.             1、将需要的参数mes取出key排序后取出value拼成字符串signdata
  248.             2、用signdata对商户私钥进行rsa签名,生成签名signn,并转base64格式
  249.             3、将签名signn插入到mes的最后生成新的data
  250.             4、用encryptkey16位常量对data进行AES加密后转BASE64,生成机密后的data
  251.             5、用对方公钥publickey对encryptkey16位常量进行RSA加密BASE64编码,生成加密后的encryptkey
  252.             6、将merchantaccount,第四部加密后的data,第五步加密后的encryptkey作为参数post请求给URL http://xxxx/xxx/api/xxx/xxx/xxx/xxx
  253.             7、返回的结果json传给data和encryptkey两部分,都为加密后的
  254.             8、用商户私钥对encryptkey进行RSA解密,生成解密后的encryptkey。参考方法:rsa_base64_decrypt
  255.             9、用解密后的encryptkey对data进行AES解密。参考方法:base64_aes_decrypt
  256.             '''
  257.             transtime=int(time.time())
  258.             od=str(random.randint(10, 100000))
  259.             mesdata={"merchantaccount":Gl.merchantaccount,"cardno":"xxxx758xxxx23xxxx","validthru":"04xx","cvv2":"200","phone":"1581xxxxxxx",
  260.     "orderid":"33hhkssseef3u"+od,"transtime":transtime,"currency":156,"amount":2,"productcatalog":"1","productname":"","productdesc":"",
  261.     "userip":"192.168.5.251","identityid":"ee","identitytype":6,"other":"","callbackurl":""}
  262.             values=self.requestprocess(mesdata)
  263.             url='http://'+Gl.URL+'/xxxx'
  264.             print url
  265.             result=self.doPost(url, values)
  266.             print result
  267.             rdata=json.loads(self.result_decrypt(result))
  268.             self.checksign(rdata)
  269.     if __name__=='__main__

知识点:
调试代码的时候也遇到了一些小问题和技巧
import的时候,如果有同名的类可以起个别名。不然会有报错,告诉这个类找不到某个方法from Crypto.Cipher import PKCS1_v1_5,from Crypto.Signature import PKCS1_v1_5 as pk,这个需要注意一下
另外,如果想将字典内的单引号都变为双引号,可以用json.dumps方法

阅读(3743) | 评论(0) | 转发(0) |
0

上一篇:pycurl的使用

下一篇:python egg

给主人留下些什么吧!~~