Python + PHP + RSA 实现加密(解决Python-RSA无法解密一般字符串的问题)

摘要

微信校园卡需要一个能够加密的Python中继和PHP后台,由于是对短字符串的加密,并且考虑到效率,所以想要使用一种非对称加密的方法进行加密,RSA就是其中一种

最终实现的效果是:PHP后台对数据进行加密后生成二维码,通过扫码枪输入到Python中继后,通过与后台通信判定当前二维码合法性(当然,这只是个DEMO,生产环境下,私钥应该是放在Python端的)

严重的问题

(1) RSA模块使用base64转码后的密文进行解密操作
问题在于在PHP中用了base64进行解码 T.T
具体参考下文中的:《Python base64编码的问题》

(2) Python-RSA 模块使用的public key 开头是—–BEGIN RSA PUBLIC KEY—–,而有些模块,如PHP的,文件开头就不是这个,这会导致public key文件读取失败:

Python + PHP + RSA 实现加密(解决Python-RSA无法解密一般字符串的问题)_第1张图片

需要注意的问题

  1. url转码(urlencode)
  2. RSA加密等级对系统速度的影响
  3. 最好用POST传递哦,安全又方便

PHP实现

参考: http://blog.csdn.net/wsliangjian/article/details/45867351


加密信息,并生成二维码

public function gen_qr(){
    $uid = "201621060701";
    $time = $this->get_time();

    $text = $uid.$time;
    $text = $this->rsa->encrypt_public($text);

    if(FALSE == $text){
        echoJSON(500,"加密失败");
    }

    $data = [
        'en_text' => $text,
        'text' => $uid.$time
    ];
    /* 生成二维码并显示 */
    show_QR();
}

RSA封装



/* 使用openssl实现非对称加密 */
class RSA{

    private $private_key = '-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgQC8bNv2gSyf60muXcXkrOsAo3DkONaDSCFccu6WsvKrHHuXTEmZ
UdfvyrTFj1oLEK9yqgBOPTb9aVpejPAyhYDwECUF/KHOWjaPMHhgSqfrfLEag/V+
dfasdffasdfdfefadvBTsNmxnNPa/CCFC11Lbch2GvEE1aWx8VsQx+f91x3sq3sq
vKHJjqQD+ZOLKaoh6zWeQhHn9nNPNUVsQx+f91x3sqVsQx+f91x3sqVsQx+f91xs
BTsNmxnNPa/CCFC11Lbch2GvEE1aWx8VsQx+f91x3sqwefgsdgadg234g234gega
vKHJjqQD+ZOLKaoh6zWeQhHn9nNPNUJBTsNmxnNPa/CCFC11Lbch2GvEE1aWx8fd
vKHJjqQD+ZOLKaoh6zf91x3sqBTsNmxnNPa/CCsdscssFC11Lbch2GvEE1aWx8Vs
vKHJjqQD+ZOLKaoh6zWeQhHn9nNPNUgT47jtJGL+EFuHmQI/LBTsNmxnNPa/CCFC
vKHJjqQD+ZOLKaoh6zWeQhHn9nNPNUR8+ZuqJzgo
-----END RSA PRIVATE KEY-----';

    private $public_key = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8bNv2gSyf60muXcXkrOsAo3Dk
ONaDSCFccu6WsvKrHHuXTEmZUdfvyrTFj1oLEK9yqgBOPTb9aVpejPAyhYDwECUF
/KHOWjaPMHhgSqfrfLEag/V+rT86qdpj0HVgMDPw4ctfpHBe6rTMJnC+mUbfaWLO
S8fsEDAfIwWEf5/jGQIDAQAB
-----END PUBLIC KEY-----
';


    /* 使用公钥加密 */
    public function encrypt_public($data){
        /* 判断公钥是否是可用的 */
        $pu_key = openssl_pkey_get_public($this->public_key);
        if($pu_key==FALSE) {
            return FALSE;
        }else{
            $encrypted = "";
            openssl_public_encrypt($data,$encrypted,$pu_key);//公钥加密
            $encrypted = base64_encode($encrypted);
            return $encrypted;
        }
    }

    /* 使用密钥解密 */
    public function decrypt_private($encrypted_data){
        /* 判断私钥是否是可用的 */
        $pi_key =  openssl_pkey_get_private($this->private_key);
        if($pi_key==FALSE) {
            return FALSE;
        }else{
            $decrypted = "";
            openssl_private_decrypt(base64_decode($encrypted_data),$decrypted,$pi_key);//私钥解密
            return $decrypted;
        }
    }
}
?>

Python base64编码的问题

Python环境下RSA编解码请参考:
https://stuvel.eu/files/python-rsa-doc/usage.html
http://www.cnblogs.com/renfanzi/p/6062261.html

但是,在将PHP中所生成的加密字符串传入Python中时,出现了字符串冲突的问题:

Python + PHP + RSA 实现加密(解决Python-RSA无法解密一般字符串的问题)_第2张图片

在网上搜索了以下资料,发现并没用什么可用的讯息。 然后,通过debug RSA模块的加密函数的返回值后发现,输出的大概是这么个东西:

b"%k\xd9\xb6\xc5\xde\x19\x86\xf00#\x80s\x17\x9b\xb5\x04]\x96\x93\xf9\xd6\x96\xb5j\\\xbb\xbf\xbd\x8f\x07^+\xdfL8=\xee\xf .......

那么答案就很明显了:这TM是个base64 encode过的bytes字符串

因此,我们需要对从PHP处生成的字符串做一些些转码,整个实现的代码如下:

import rsa
import base64

# Warning : 这里必须用'rb'模式打开,或者在f.read()后使用encode()函数进行转码
with open('./rsa_key/rsa_private_key.pem','rb') as f:
    privkey = rsa.PrivateKey.load_pkcs1(f.read())
    # ALTER : 
    # privkey = rsa.PrivateKey.load_pkcs1(f.read().encode())


while(1):
    try:
        encrypted_str = input(">>")
        # 将str转码成bytes
        encrypted_str = encrypted_str.encode()
        # 将bytes进行base64编码
        encrypted_str = base64.b64decode(encrypted_str)

        # 进行RSA解码
        decrypted_str = rsa.decrypt(encrypted_str, privkey)

    except Exception as e:
        print("FAIL, Try Again PLS")
        continue

    # 将bytes转为str
    decrypted_str = decrypted_str.decode()

    print(decrypted_str)

Python 通过POST与web后台交互

import web # 参考web.py
import time

while(1):
    text = input('>>')
    url = "http://www.wunyungsumu.cn/WechatCard/u"
    values = {
        'text' : text
    }
    result     = web.post(url=url, values=values)
    result_str = str(result, encoding="utf-8")

    if(result_str=='0'):
        print("Failed, Try Again Please !")
        continue

    uid = result_str[:12]
    tim = result_str[12:]
    print("uid:",uid," time:",tim)

Python 网络web封装

web.py

import urllib.parse as up
import urllib.request as ur

def get(url):
    req = ur.Request(url)
    response = ur.urlopen(req)
    return response.read()

def post(url,values):
    data = up.urlencode(values).encode(encoding='UTF8')
    req = ur.Request(url, data)
    response = ur.urlopen(req)
    return response.read()



# url = 'http://umbra.nascom.nasa.gov/cgi-bin/eit-catalog.cgi'
# values = {
#         'obs_year': '2011',
#         'obs_month': 'March'
#     }
#
# print(post(url=url, values=values))

实现效果

Python + PHP + RSA 实现加密(解决Python-RSA无法解密一般字符串的问题)_第3张图片

这里写图片描述

你可能感兴趣的:(PHP开发,python,rsa,python,php,加密)