加密解密--RSA&AES

一 RSA

RSA加密算法是一种非对称加密算法

非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。
另一方面,甲方可以使用乙方的公钥对机密信息进行签名后再发送给乙方;乙方再用自己的私匙对数据进行验签。
甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。 非对称加密算法的保密性比较好,它消除了最终用户交换密钥的需要。
非对称密码体制的特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了。这样安全性就大了很多。(百度百科)
扫盲:非对称加密算法

RSA的使用

import rsa

# rsa加密
def rsa_encrypt(value):
    # 生成公钥、私钥
    pub_key, priv_key = rsa.newkeys(256)  # 88时能够加密的字节为0,后续每增加8,代表增加一个字节
    # 明文编码格式
    content = value.encode('utf-8')
    # 明文加密
    crypto = rsa.encrypt(content, pub_key)
    # 返回密文和私钥
    return (crypto, priv_key)

# rsa解密
def rsa_decrypt(crypto, pk):
    # 私钥解密
    content = rsa.decrypt(crypto, pk)
    con = content.decode('utf-8')
    return con

if __name__ == '__main__':
    v = '要加密的数据'
    crypto, pk = rsa_encrypt(v)
    print('加密后密文:%s' %crypto)
    content = rsa_decrypt(crypto, pk)
    print('解密后明文:%s' %content)

结合base64使用

import rsa
import base64

# 1. 生成公钥私钥
pub_key_obj, priv_key_obj = rsa.newkeys(256)  # 88时能够加密的字节为0,后续每增加8,代表增加一个字节

pub_key_str = pub_key_obj.save_pkcs1()
pub_key_code = base64.b64encode(pub_key_str)

priv_key_str = priv_key_obj.save_pkcs1()
priv_key_code = base64.b64encode(priv_key_str)

# 2. 加密
def rsa_encrypt(value):
    key_str = base64.b64decode(pub_key_code)
    pk = rsa.PublicKey.load_pkcs1(key_str)
    val = rsa.encrypt(value.encode('utf-8'), pk)
    return val

# 3. 解密
def rsa_decrypt(value):
    key_str = base64.b64decode(priv_key_code)
    pk = rsa.PrivateKey.load_pkcs1(key_str)
    val = rsa.decrypt(value, pk)
    return val

# 使用
if __name__ == '__main__':
    v = '要加密的数据'
    v1 = rsa_encrypt(v)
    print('加密后密文:%s' % v1)   # b'\xea\xb2\xb8\xca]\xb8\xf6r\x81\xed\x13`E\xfe\xf6q\xbe(>\xc1\xf6\xf1\x1b\x9d?\xf1\xda\x05\x1c\xe0d\xfd' 不固定
    v2 = rsa_decrypt(v1)
    print(v2)               # b'\xe8\xa6\x81\xe5\x8a\xa0\xe5\xaf\x86\xe7\x9a\x84\xe6\x95\xb0\xe6\x8d\xae'
    print('解密后明文:%s' % v2.decode('utf-8'))      # 要加密的数据

注意点:rsa对加密的数据有大小的要求,我们可以通过newkeys(256)设置其加密数据的大小,加密数据越大,速度越慢。

踩过的坑:

AttributeError: module 'rsa' has no attribute 'newkeys'

解析:明明rsa模块安装没有问题,但运行代码时一直报上面的错误信息,最后发现文件名为:rsa.py,所以我们一定要注意自己的文件名一定不要和导入的模块重名,否则导入失败。

二 AES

针对RSA对加密数据有大小的控制,我们可以使用AES(高级加密标准  Advanced Encryption Standard,在密码学中又称Rijndael加密法)方式对数据进行加密。

特点:要加密的字符串,必须是16个字节或16个字节的倍数

from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex

def aes_encrypt(message):
    cipher = AES.new(key, AES.MODE_CBC, key)
    b_msg = bytearray(message, encoding='utf-8')        #转换为bytearray数据类型,方便修改
    v1 = len(b_msg)
    v2 = v1 % 16
    # 判断字符串刚好为16的倍数,增加16个16
    if v2 == 0:
        v3 = 16
    # 差n个字节我们就在该字节字符串后面加上n个n
    # 为什么不加空格,若字符串后面本来就存在空格,我们在解码时则会出错
    else:
        v3 = 16 - v2
    for i in range(v3):
        b_msg.append(v3)
    final_data = b_msg.decode('utf-8')
    msg = cipher.encrypt(final_data)        # 要加密的字符串,必须是16个字节或16个字节的倍数
    # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
    # 所以这里统一把加密后的字符串转化为16进制字符串
    return b2a_hex(msg)

def aes_decrypt(message):
    cipher = AES.new(key, AES.MODE_CBC, key)
    result = cipher.decrypt(a2b_hex(message))
    data = result[0:-result[-1]]     # 切片,将后面添加的字节切除
    return data.decode('utf-8')

if __name__ == '__main__':
    key = b'asdfasdfasdfasdf'   # 这里密钥key长度必须为16(AES-128)、24(AES-192)或32(AES-256)Bytes长度,目前AES-128足够用
    v = '需要加密的数据'
    data = aes_encrypt(v)
    print(data)         # b'082b31fe051515970a781172a3d4b8b83d2109d808c27e02fe041dd9d873e64f'
    result = aes_decrypt(data)
    print(result)       # 需要加密的数据
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex

class aesCrypto:
    def __init__(self,key):
        self.key = key
        self.mode = AES.MODE_CBC

    def aes_encrypt(self,msg):
        """
        #加密函数,如果msg长度不是16的倍数,需要补足为16的倍数
        :param msg: 需要加密的数据
        :return: 返回加密完成的数据
        """
        cryptor = AES.new(self.key, self.mode, self.key)
        b_msg = bytearray(msg, encoding='utf-8')     # 转换为bytearray数据类型,方便修改
        v1 = len(b_msg)
        v2 = v1 % 16
        # 判断字符串刚好为16的倍数,增加16个16
        if v2 == 0:
            v3 = 16
        # 差n个字节我们就在该字节字符串后面加上n个n
        # 为什么不加空格,若字符串后面本来就存在空格,我们在解码时则会出错
        else:
            v3 = 16 - v2
        for i in range(v3):
            b_msg.append(v3)
        data = b_msg.decode('utf-8')
        final_data = cryptor.encrypt(data)        # 要加密的字符串,必须是16个字节或16个字节的倍数
        # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
        # 所以这里统一把加密后的字符串转化为16进制字符串
        return b2a_hex(final_data)

    def aes_decrypt(self, msg):
        """
        解密
        :param msg:解密数据
        :return:解密后数据
        """
        cryptor = AES.new(self.key, self.mode, self.key)
        result = cryptor.decrypt(a2b_hex(msg))
        data = result[0:-result[-1]]        # 切片,将后面添加的字节切除
        return data.decode('utf-8')

if __name__ == '__main__':
    ac = aesCrypto('asdfasdfasdfasdf')  # 初始化密钥。这里密钥key长度必须为16(AES-128)、24(AES-192)或32(AES-256)Bytes长度,目前AES-128足够用
    v = '需要加密的数据'
    data = ac.aes_encrypt(v)
    print(data)         # b'082b31fe051515970a781172a3d4b8b83d2109d808c27e02fe041dd9d873e64f'
    result = ac.aes_decrypt(data)
    print(result)       # 需要加密的数据
面向对象式

注意点:一定要注意刚好为16的倍数的字符串的处理


Crypto模块的安装可参考:https://github.com/sfbahr/PyCrypto-Wheels,注意py版本。

posted @ 2018-04-02 11:28  Joe1991  阅读(959)  评论(0)    收藏  举报