加密方式:AES算法,基本变换包括SubBytes(字节替代)、ShiftRows(行移位)、MixColumns(列混淆)、AddRoundKey(轮密钥加)。
加密模式:
CBC模式:通过密钥和salt(起扰乱作用)按固定算法(md5)产生key和iv。然后用key和iv(初始向量,加密第一块明文)加密(明文)和解密(密文)。
ECB模式:不需要iv偏移量
python中使用到的库:
from Crypto.Cipher import AES
安装:
**Linux**下使用AES时要安装的是pycrypto模块 pip install pycrypto
**Windows**下使用AES时要安装的是pycryptodome 模块 pip install pycryptodome
实际使用:
1、准备key,可以理解成加密解密的密码
2、加密后还会使用base64再次加密,当然解密时先用base64先进行第一次解密
3、还可以将base64第二次加密换成ASCII码进行加密,使用到的包如下:from binascii import b2a_hex, a2b_hex
class AESCryptoHelper():
def encrypt(data, key):
"""
加密时使用的key,只能是长度16,24和32的字符串
data: 要加密的内容,bytes
key:密钥,len必须是16, 24, 32之一 bytes
result:加密内容,bytes
"""
keySzie = len(key)
if keySzie == 16 or keySzie == 24 or keySzie == 32:
cipher = AES.new(key, AES.MODE_ECB)
padData = AESCryptoHelper._padData(data)
encrypted = cipher.encrypt(padData)
result = base64.b64encode(encrypted)
return result
else:
# 加密失败,返回原数据
return data
# 解密后,去掉补足的空格用strip() 去掉
def decrypt(data, key):
"""
加密时使用的key,只能是长度16,24和32的字符串
data: 要解密的内容,bytes
key:密钥,bytes
result:解密的内容,bytes
"""
keySzie = len(key)
if keySzie == 16 or keySzie == 24 or keySzie == 32:
cipher = AES.new(key, AES.MODE_ECB)
tmpData = base64.b64decode(data)
decrypted = cipher.decrypt(tmpData)
result = AESCryptoHelper._unpadData(decrypted)
return result
else:
# 解密失败,返回原数据
return data
def _padData(data):
"""
按AES加密的要求,填充内容,使其为block_size的整数倍
"""
block_size = 16
padding = b"\0"
padData = data + (block_size - len(data) % block_size) * padding
return padData
def _unpadData(data):
"""
删除填充数据
"""
padding = b"\0"
index = -1
while data[index] == padding[0]:
index += -1
if index != -1:
return data[0: index+1]
else:
return data
实际加密步骤:
1、生成公钥、私钥(服务器)
2、公钥加密数据得到密文,在使用base64加密密文(客户端)
3、base64逆向解码,私钥解密密文(服务器)
# -*- coding: UTF-8 -*-
# ! /usr/bin/env python
import base64
import rsa
from rsa import common
PUBLIC_KEY_PATH = '/Users/anonyper/Desktop/key/company_rsa_public_key.pem' # 公钥
PRIVATE_KEY_PATH = '/Users/anonyper/Desktop/key/company_rsa_private_key.pem' # 私钥
# -------------------------- 生成公私钥 --------------------------
class CreateKeys:
def __init__(self):
public_key, private_key = rsa.newkeys(1024)
public_pkcs1 = public_key.save_pkcs1().decode()
private_pkcs1 = private_key.save_pkcs1().decode()
# 生成公钥和私钥
with open(PUBLIC_KEY_PATH, 'w') as pub_f, open(PRIVATE_KEY_PATH, 'w') as pri_f:
pub_f.write(public_pkcs1)
pri_f.write(private_pkcs1)
print('>> 生成公私钥成功')
def __str__(self):
pass
# -------------------------- RSA签名和加解密 --------------------------
class RsaUtil(object):
# 初始化key
def __init__(self,
company_pub_file=PUBLIC_KEY_PATH,
company_pri_file=PRIVATE_KEY_PATH):
if company_pub_file:
self.company_public_key = rsa.PublicKey.load_pkcs1(open(company_pub_file).read())
if company_pri_file:
self.company_private_key = rsa.PrivateKey.load_pkcs1(open(company_pri_file).read())
def get_max_length(self, rsa_key, encrypt=True):
"""加密内容过长时 需要分段加密 换算每一段的长度.
:param rsa_key: 钥匙.
:param encrypt: 是否是加密.
"""
blocksize = common.byte_size(rsa_key.n)
reserve_size = 11 # 预留位为11
if not encrypt: # 解密时不需要考虑预留位
reserve_size = 0
maxlength = blocksize - reserve_size
return maxlength
# 加密 支付方公钥
def encrypt_by_public_key(self, message):
"""使用公钥加密.
:param message: 需要加密的内容.
加密之后需要对接过进行base64转码
"""
encrypt_result = b''
max_length = self.get_max_length(self.company_public_key)
while message:
input = message[:max_length]
message = message[max_length:]
out = rsa.encrypt(input, self.company_public_key)
encrypt_result += out
encrypt_result = base64.b64encode(encrypt_result)
return encrypt_result
def decrypt_by_private_key(self, message):
"""使用私钥解密.
:param message: 需要加密的内容.
解密之后的内容直接是字符串,不需要在进行转义
"""
decrypt_result = b""
max_length = self.get_max_length(self.company_private_key, False)
decrypt_message = base64.b64decode(message)
while decrypt_message:
input = decrypt_message[:max_length]
decrypt_message = decrypt_message[max_length:]
out = rsa.decrypt(input, self.company_private_key)
decrypt_result += out
return decrypt_result
# 签名 商户私钥 base64转码
def sign_by_private_key(self, data):
"""私钥签名.
:param data: 需要签名的内容.
使用SHA-1 方法进行签名(也可以使用MD5)
签名之后,需要转义后输出
"""
signature = rsa.sign(str(data), priv_key=self.company_private_key, hash='SHA-1')
return base64.b64encode(signature)
def verify_by_public_key(self, message, signature):
"""公钥验签.
:param message: 验签的内容.
:param signature: 对验签内容签名的值(签名之后,会进行b64encode转码,所以验签前也需转码).
"""
signature = base64.b64decode(signature)
return rsa.verify(message, signature, self.company_public_key)
CreateKeys()
message = 'hell world'
print("明文内容:>>> ")
print(message)
rsaUtil = RsaUtil()
encrypy_result = rsaUtil.encrypt_by_public_key(message)
print("加密结果:>>> ")
print(encrypy_result)
decrypt_result = rsaUtil.decrypt_by_private_key(encrypy_result)
print("解密结果:>>> ")
print(decrypt_result)
sign = rsaUtil.sign_by_private_key(message)
print("签名结果:>>> ")
print(sign)
print("验签结果:>>> ")
print(rsaUtil.verify_by_public_key(message, sign))
使用缓存机制可以实现后端两个接口的开关控制,如实现以下功能:
浏览器获取手机上传的数据,当获取到数据后不刷新界面。
在程序中实现如下:
1、**浏览器**不断请求存放数据的接口(浏览器无法判断数据是否是新数据还是旧数据,所以只要有数据页面就会不断刷新),
2、**手机**上传数据,调用存放数据的接口,
很明显手机上传数据的接口与浏览器下载数据的接口不是同一个,所以两个接口数据无法连接起来。
使用缓存可以实现两个接口数据的传输,步骤如下:
1、手机将数据存储到给某个id分配的缓存内,当浏览器发送请求时,从缓存提取这个id的缓存数据。
数据通信实现了,那么如何实现旧数据不刷新,新数据才刷新呢。
1、很简单,设置一个update的键值对,手机上传说明有新数据设置为True,当浏览器获取了数据就将update设置为False,这样就实现了开关功能。
使用缓存最大的好处是可以定时删除数据。