栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

python实现AES#实现加密字符串和加密文件

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

python实现AES#实现加密字符串和加密文件

文章目录
  • 综述
    • 已实现的功能
    • 脚本使用
    • 算法流程
  • 源代码
    • AES.py文件
    • boxdata.py

综述

原理这块就不讲了,网上有很多参考文章。
需要注意运行脚本需要numpy这个库
这篇文章是对之前的一篇文章的重写和优化AES加密算法基于python实现
脚本执行截图:
1 加解密字符串

2 加解密文件

已实现的功能
  • 明文和密密钥可以是任意字符:中文,字符,数字或符号。

​ 明文长度任意,密钥的字节数不能超过16字节。默认编码为utf-8所以,密钥最多支持5个中文字符

  • 待加密的数据:可以是字符串,也可以对文本文件进行加密
脚本使用

需要指定输入类型(string或file),解密的时候需要加上–flag选项

AES> python AES.py -h
usage: AES [-h] [--flag] [--encoding ENCODING] {string,file} message key

positional arguments:
  {string,file}        输入数据的类型:文件或字符串}
  message              待加密或解密的字符串或文件
  key                  密钥:length<=16 bytes

optional arguments:
  -h, --help           show this help message and exit
  --flag               要进行的操作: 默认加密,带上--flag为解密
  --encoding ENCODING  文本字符集指定,默认gbk
算法流程

主要难点在于列混淆中的域上乘法这一步
我分成5步进行解决

 1、bit_split(): 将十进制数分解成二进制形式表示,如7=(1+10+100)二进制,被gmul调用
 2、_gmul(a,b):  特殊的G(2^8)上的乘法运算:第一个参数的值是2的n次方,被gmul调用
 3、gmul():  完整的G(2^8)上的乘法运算: 如0e*47=87
 4、multi: 列混淆常数矩阵的一行*状态矩阵,返回一维矩阵,被mixcolumns调用
 5、mixcolumns():列混淆常数矩阵*状态矩阵
源代码

两个文件
静态数据boxdata.py在AES.py中导入
脚本文件AES.py

AES.py文件
from boxdata import * #s盒等数据
import numpy as np #方便操作字节数组
import argparse
import functools
import operator


#功能函数
def subBytes(state):
    '''
    字节替换函数,参数是np数组
    根据FLAG字段决定是加密还是解密
    '''
    state=state.reshape(16)
    if FLAG:
        box=S_BOX
    else:
        box=I_SBOX
    for _ in range(16):
        row=(state[_]>>4)&0b1111
        col=state[_]&0b1111
        state[_]=box[row][col]
    return state.reshape(4,4)

def shiftrows(state):
    '''-1 if FLAG else 1 如果加密就向左移位,如果解密就向右移位'''
    return np.vstack(
        (
            state[0,:],#第一行不移动
            np.roll(state[1,:],-1 if FLAG else 1),#第2行:循环向左(或向右)移动一个字节
            np.roll(state[2,:],-2 if FLAG else 2),#第3行:循环向左(或向右)移动2个字节
            np.roll(state[3,:],-3 if FLAG else 3),#第4行:循环向左(或向右)移动3个字节
        )
    )

'''列混淆处理
1、bit_split(): 将十进制数分解成二进制形式表示,如7=(1+10+100)二进制,被gmul调用
2、_gmul(a,b):  特殊的G(2^8)上的乘法运算:第一个参数的值是2的n次方,被gmul调用
3、gmul():  完整的G(2^8)上的乘法运算: 如0e*47=87
4、multi: 列混淆常数矩阵的一行*状态矩阵,返回一维矩阵,被mixcolumns调用
5、mixcolumns():列混淆常数矩阵*状态矩阵
'''
def bit_split(num):
    '''将num分成形如(0b1+0b10+0b100+...),返回一个列表,被gmul调用'''
    li=[]
    arg=[int(i) for i in format(num,'b')][::-1]
    if arg[0]:
        li.append(1)
    base=1
    for offset in arg[1:]:
        base=base<<1
        if offset:
            li.append(base)
    return li
def _gmul(a,b):
    '''被gmul调用(a为2的n次方)'''
    while a>>1:
        a=a>>1
        x=(b&0b1111111)<<1
        y=(b>>7)*0b11011
        b=x^y
    return b
def gmul(a,b):
    '''在G(2^8)上的乘法a*b'''
    a_li=bit_split(a)
    func=functools.partial(_gmul,b=b)
    return functools.reduce(operator.xor,list(map(func,a_li)))
def multi(cons,state):
    '''const每一行 * state 返回一行数据'''
    li=[]
    for _ in range(4):
        li.append(functools.reduce(operator.xor,list(map(gmul,cons,state[:,_]))))
    return li
def mixcolumns(state):
    '''
    域上乘法,调用gmul()
    '''
    li=[]
    const_M=MIX_C if FLAG else I_MIXC #常数矩阵的选择
    const_M=np.array(const_M) #转化为np数组
    for _ in range(4):
        li.append(multi(const_M[_,:],state))
    return np.array(li)


def addroundkey(state,key):
    '''state和key都是4x4的np数组'''
    li=[]
    for _ in range(4):
        li.append(list(map(operator.xor,state[:,_],key[:,_])))
    return np.array(li).transpose() #需要进行转置
    

#输入处理以及密钥扩展
def subword(temp: list):
    li=[]
    for i in temp:
        col=i&0b1111
        row=i>>4
        li.append(S_BOX[row][col])
    return li

def expandkey(key: bytes):
    '''密钥扩展:初始密钥为16字节'''
    key=[i for i in key]#把字节读成列表
    w=[]
    i=0
    while i<4:
        w.append([key[4*i],key[4*i+1],key[4*i+2],key[4*i+3]])
        i+=1
    while i<44:
        temp=w[i-1][:]#深拷贝
        if i%4==0:
            temp.append(temp.pop(0))#循环左移一个字节
            temp=subword(temp)#字节替换
            temp=list(map(operator.xor,temp,RCon[i//4 -1]))#与轮常量异或
        w.append(list(map(operator.xor,w[i-4],temp)))#与w[i-1]异或
        i=i+1
    return np.array(w).transpose()
#--------------------------------------------------------------
def matri2bytes(matrix)->bytes:
    '''将4x4状态矩阵转换为字节序列'''
    li=list(matrix.transpose().reshape(16))
    li=list(map(lambda x: format(x,'02x'),li))
    li=''.join(li)
    return bytes.fromhex(li)

def process(state,key):
    '''单个分组加解密处理'''
    if FLAG:
        state=addroundkey(state,key[:,0:4])
        for i in range(1,10):#前9轮
            state=subBytes(state)
            state=shiftrows(state)
            state=mixcolumns(state)
            state=addroundkey(state,key[:,i*4:i*4+4])
        #第10轮
        state=subBytes(state)
        state=shiftrows(state)
        state=addroundkey(state,key[:,40:])
    else:
        state=addroundkey(state,key[:,40:])
        for i in range(10,1,-1):
            state=shiftrows(state)
            state=subBytes(state)
            state=addroundkey(state,key[:,4*i-4:4*i])
            state=mixcolumns(state)
            
        #第10轮
        state=shiftrows(state)
        state=subBytes(state)
        state=addroundkey(state,key[:,0:4])
    return matri2bytes(state).hex()


def handlekey(key:str,encoding='utf-8')->bytes:
    '''对key进行预处理,转化为bytes
    key超过16字节,报错,不足16字节末尾补零
    '''
    size=len(key.encode(encoding))
    if size>16:
        print('密钥不符合要求,长度超过16字节')
        exit()
    key=key+' '*(16-size)
    return key.encode(encoding)   
def setargs():    
    parser=argparse.ArgumentParser(prog='AES',prefix_chars='-',epilog=None,add_help=True)
    parser.add_argument('Type',type=str,choices=['string','file'],help='输入数据的类型:文件或字符串}')
    parser.add_argument('message',type=str,help="待加密或解密的字符串或文件")
    parser.add_argument('key',type=str,help='密钥:length<=16 bytes')
    parser.add_argument('--flag',action='store_false',help="要进行的操作: 默认加密,带上--flag为解密")
    parser.add_argument('--encoding',type=str,default='utf-8',help='文本字符集指定,默认gbk')
    return parser.parse_args()

def bytes2matri(by):
    '''将字节序列转化为4x4矩阵'''
    t=[x for x in by]
    return np.array(t).reshape(4,4).transpose()
def group_handle(b_m):
    '''将原明文或密文进行分组,然后加解密'''
    b_size=len(b_m)//16
    li=[]
    group=[]
    for i in range(b_size):
        li.append(b_m[i*16:i*16+16])
    for i in li:
        state=bytes2matri(i)
        group.append(process(state,key))
    return group

def encrypt(message,key,encoding='utf-8'):
    '''明文加密'''
    size=len(message.encode(encoding))
    rem=size%16
    if rem==0:
        message=message+' '*15+chr(65+16)
    else:#chr(65+16-rem),将补充数表示为ascii字符,占一个字节
        message=message+' '*(16-1-rem)+chr(65+16-rem)
    #现在的message字节数为16的整数倍
    b_m=message.encode(encoding)
    cipher=group_handle(b_m)
    return  functools.reduce(operator.add,cipher)

def decrypt(message,key,encoding='utf-8'):
    '''密文解密'''
    b_m=bytes.fromhex(message)
    m=group_handle(b_m)
    m=bytes.fromhex(functools.reduce(operator.add,m))
    num=m[-1]-65 #之前加上了65,现在减掉65后得到补充的0的个数
    return m[:len(m)-num].decode(encoding)


if __name__=='__main__':
    args=setargs()
    
    FLAG=args.flag
    encode=args.encoding
    key=expandkey(handlekey(args.key,encode))
    #判断加解密:
    if FLAG:
        if args.Type=='file':
            with open(args.message,'r',encoding=encode) as f:
                message=f.read()
            cipher=encrypt(message,key,encode)
            with open('cipher.txt','w',encoding=encode) as fi:
                fi.write(cipher)
            print('生成密文文件,cipher.txt')
        else:
            message=args.message
            cipher=encrypt(message,key,encode)
            print()
            print("+"*15,'密文',"+"*15)
            print(cipher)
    else:
        if args.Type=='file':
            with open(args.message,'r',encoding=encode) as f:
                message=f.read()
            plain=decrypt(message,key,encode)
            with open('plain.txt','w',encoding=encode) as fi:
                fi.write(plain)
            print('生成明文文件,plain.txt')
        else:
            message=args.message
            plain=decrypt(message,key,encode)
            print()
            print("+"*15,'明文',"+"*15)
            print(plain)
boxdata.py
#列混淆常数矩阵
MIX_C  = [[0x2, 0x3, 0x1, 0x1], [0x1, 0x2, 0x3, 0x1], [0x1, 0x1, 0x2, 0x3], [0x3, 0x1, 0x1, 0x2]]
#逆列混淆矩阵
I_MIXC = [[0xe, 0xb, 0xd, 0x9], [0x9, 0xe, 0xb, 0xd], [0xd, 0x9, 0xe, 0xb], [0xb, 0xd, 0x9, 0xe]]
RCon   = [[0x01,0x00,0x00,0x00], 
       [0x02,0x00,0x00,0x00], 
       [0x04,0x00,0x00,0x00],
       [0x08,0x00,0x00,0x00], 
       [0x10,0x00,0x00,0x00], 
       [0x20,0x00,0x00,0x00], 
       [0x40,0x00,0x00,0x00], 
       [0x80,0x00,0x00,0x00], 
       [0x1B,0x00,0x00,0x00], 
       [0x36,0x00,0x00,0x00]
       ]
#S盒子
S_BOX = [[0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76],
      [0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0],
      [0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15],
      [0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75],
      [0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84],
      [0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF],
      [0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8],
      [0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2],
      [0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73],
      [0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB],
      [0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79],
      [0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08],
      [0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A],
      [0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E],
      [0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF],
      [0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]]
#逆S盒
I_SBOX = [[0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB],
       [0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB],
       [0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E],
       [0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25],
       [0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92],
       [0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84],
       [0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06],
       [0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B],
       [0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73],
       [0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E],
       [0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B],
       [0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4],
       [0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F],
       [0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF],
       [0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61],
       [0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]]


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/938358.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号