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文件读取失败:

这里写图片描述

需要注意的问题

  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封装

<?php

/* 使用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中时,出现了字符串冲突的问题:

这里写图片描述

在网上搜索了以下资料,发现并没用什么可用的讯息。 然后,通过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))

实现效果

这里写图片描述

这里写图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
里提供了三种Python中常用的加密解密字符串的方法:DES、RSA和AES。 1. DES加密解密使用Crypto.Cipher库中的DES模块,需要注意的是,密钥必须为8位或16位bytes类型,加密文本必须为8的倍数。具体代码实现可以参考引用中的DesUtil类。 2. RSA加密解密使用rsa库进行加密解密,需要生成公钥和私钥,具体代码实现可以参考引用中的rsacrypt类。 3. AES加密解密使用pycryptodome库中的AES模块,需要注意的是,密钥必须为16、24或32位bytes类型,加密文本可以为任意长度。具体代码实现可以参考以下示例: ``` from Crypto.Cipher import AES import base64 class AesUtil(): """ AES加密解密 """ key = b'1234567890123456' # 密钥 16、24或32位bytes类型 iv = b'1234567890123456' # 初始向量 16位bytes类型 def __init__(self): self.aes = AES.new(self.key, AES.MODE_CBC, self.iv) # 创建一个AES实例 def pad(self, text): """ 加密函数,如果text不是16的倍数,那就补足为16的倍数 :param text: :return: """ while len(text) % 16 != 0: text += b' ' return text def encrypt(self, text): padded_text = self.pad(text) encrypted_text = self.aes.encrypt(padded_text) # 把加密后的字符串转化为base64编码的字符串 return base64.b64encode(encrypted_text).decode() def decrypt(self, text): # 先把base64编码的字符串转化为bytes类型 encrypted_text = base64.b64decode(text.encode()) decrypted_text = self.aes.decrypt(encrypted_text).rstrip(b' ') return decrypted_text.decode() aes = AesUtil() enc = aes.encrypt(b"我是一个兵!") print("加密后:%s" % enc) dec = aes.decrypt(enc) print("解密后:%s" % dec) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值