jwt的解密和RSA签名验证

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : jwt_base64_test.py
@Contact : [email protected]
@MTime : 2020-04-26 11:32 
@Author: buweiqiang
@Version: 1.0
@Desciption:
标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。
为解决此问题,可采用一种用于URL的改进Base64编码,它去除了在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“-”和“_”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。
本脚本示例如何把url友好的改进型Base64编码,转为标准的base64

另外,jwt的签名算法JWT 的签名算法有三种:
1.对称加密HMAC【哈希消息验证码】  HS256/HS384/HS512   
2.非对称加密RSASSA【RSA签名算法】RS256/RS384/RS512
3.ECDSA【椭圆曲线数据签名算法】 ES256/ES384/ES512,RSA签名
这里实验的是RSA签名算法验签的过程

注意:本文中用的jwt是:https://pypi.org/project/jwt/,安装方法为:pip3 install jwt
注意与python-jwt区别:https://pypi.org/project/python-jwt/,安装方法为:pip install python_jwt
'''
print('-----------base64解密jwt中的header和payload--------------')
import base64

jwt_token = 'eyJhbGciOiJSUzI1NiJ9.eyJvcGVyYXRpb25Vc2VySWQiOiJlZTgzMjYyYThkNGIxMWU3YTdiMzZjOTJiZjMxNjA3YiIsInBob25lIjoiMTU3NTcxNjA1MzEiLCJsb2dpbk5hbWUiOiIxNTc1NzE2MDUzMSIsIm5hbWUiOiLmtYvor5XmlLkxIiwiZXhwIjoxNTg3NzA5OTY3LCJyb2xlTmFtZXMiOiJjY-i_kOiQpeS6uuWRmCzku5PnrqHlkZgs5ZWG5ZOB566h55CG5ZGYLOacuuaehOi0n-i0o-S6uizmtYvor5XlkZgs57O757uf566h55CG5ZGYLOiuouWNleeuoeeQhizotYTmlpnnrqHnkIblkZgifQ.Ugzrowz1TD38IK5yuHAxoCURGxByBm0Ep9JtvitijhFw3MGqooaRDxKIOUk6aAFVuV6zfpY7y23oCk3-KsBvVR1oVLIAWSxiRJlVs-sne2vTEplH2xuzQv2N1HuAGvrbYlhMu2rIqitP7D5xQjVruBTmalO9TZUgsc8ONIMBZH4'
jwt_token_parts = jwt_token.split('.')

# jwt分为三个部分,header, payload, signature
header = jwt_token_parts[0]
payload = jwt_token_parts[1]
signature = jwt_token_parts[2]
print('header:', header)
print('payload:', payload)
# python中有urlsafe_b64decode方法,里面封装了对从-到+,从_到/的转换
print(base64.urlsafe_b64decode(header + '=' * (4 - len(header) % 4)))
print(base64.urlsafe_b64decode(payload + '=' * (4 - len(header) % 4)))
print('--------------------------------')

# 转化为标准base64编码
standard_base64_str_header = header.replace('-', '+').replace('_', '/') + '=' * (4 - len(header) % 4)
print('header_std:', standard_base64_str_header)

standard_base64_str_payload = payload.replace('-', '+').replace('_', '/') + '=' * (4 - len(payload) % 4)
print('payload_std', standard_base64_str_payload)
print('--------------------------------')

# base64解密
text_header = base64.b64decode(standard_base64_str_header.encode('utf-8'))
print('header_text:', text_header.decode('utf-8'))

text_payload = base64.b64decode(standard_base64_str_payload.encode('utf-8'))
print('payload_text:', text_payload.decode('utf-8'))
print('--------------------------------')

print('-----------用公钥验证jwt--------------')
from Crypto.PublicKey import RSA

rsa_public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC84nyOnK4BGDuk/EsKNxgTjoeLqSmHWR++H0VgLdfk+as8tuBLD0HSv42wYWfBi+ICqwo+ylHFD9TM6Xx2J2ojxO6uHirCgmsdD9WzCAqannNU3YuNjFYBJI+b7N23IaAfB4ZRQKr4h0ZO2f4ruW8JUUSbMZunhtBTErurRfqK7QIDAQAB'
if isinstance(rsa_public_key, str):
    rsa_public_key = rsa_public_key.encode()
if not rsa_public_key.startswith(b'-----'):
    rsa_public_key = b'-----BEGIN RSA PUBLIC KEY-----\n' + rsa_public_key
    rsa_public_key += b'\n-----END RSA PUBLIC KEY-----'
try:
    rsa_public_key_obj = RSA.importKey(rsa_public_key)
except Exception as err:
    print('字符串密钥转rsa格式密钥错误:', err)

print('1. 用jwt库里封装好的方法解密和验签')
from jwt import JWT, jwk_from_pem

jwt = JWT()
key = jwk_from_pem(rsa_public_key_obj.export_key())
try:
    payload_json = jwt.decode(jwt_token, key=key, do_time_check=False)
    print('payload json:', payload_json)
except Exception as e:
    print(e)

print('2. 自行用RSA验证')
from Crypto import Hash
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5

# 用utf-8和ascii都可以,base64中没有双字节的字符,所以encode出来的都是一样的
message = '{}.{}'.format(header, payload)
print('message(header.payload):', message)
print('signature:', signature)
message_bytes = message.encode('ascii')
signature_bytes = base64.urlsafe_b64decode(signature.encode('ascii') + b'=' * (4 - len(signature) % 4))

verifier = PKCS1_v1_5.new(rsa_public_key_obj)
message_hash = Hash.SHA256.new(message_bytes)
verify_result = verifier.verify(message_hash, signature_bytes)
print('RSA验签结果:', verify_result)

 

你可能感兴趣的:(技术)