python实现aes加密解密,RSA签名和验签,RSA加密解密,并调用接口

来源:互联网 发布:淘宝哪个折扣店比较好 编辑:程序博客网 时间:2024/05/11 20:56
用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--*- 
  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--*- 
  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+=
  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":"http://IP/webtest/callback.do"} 
  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方法
0 0
原创粉丝点击