重走密码路:高级加密标准(AES)概述+python实现

一、算法概述

1、AES密码与分组密码Rijndael基本一致,AES只要求分组大小为128位,所以可以称128位的Rijndael才成为AES。

明文x(128位)经过k(128/192/256位)的AES得到128位的密文y

密钥长度轮数=n_{r}
128位10
192位12
256位14

AES不具有feistel网络,注意feistel网络每轮迭代只加密64/2位,AES在每轮迭代中就加密了所有的128位,因此AES的轮数比DES小。

2、AES由群构成,每层操纵的数据路径(算法状态)对应所有的128位

密钥加法层:128位轮密钥(来自主密钥),与状态进行异或操作;

字节代换层(S-盒)根据查找表进行非线性转换,在加密中引入混淆操作;(上篇的DES中有介绍)

扩散层:由两个子层构成,每层都执行线性操作:

        ShiftRows(行位移变化)层在位级进行行数据转换;

        MixColumn(列行列变换)一个混淆操作,混淆了长度四个字节的分组;

二、数学知识

1、首先介绍一下域:

域F是具有以下特性的元素的集合:

  • F中所有元素形成一个加法交换群,单位元为0
  • F中除0外所有元素构成一个乘法交换群,单位元为1
  • 混合使用加法和乘法两种操作时,分配定理始终成立,即a(b+c)=(ab)+(ac)

域所包含的元素个数称为域的阶或基

当m是一个素数幂时,及m= p^{n}(p是素数,n为正整数),阶为m的域才存在,p为这个有限域的特征。

2、接着介绍素域:

有限域最直观的例子及阶为素数的域,即n=1,域GF(p)的元素可以用整数0,1,...,p-来表示。域中的群操作就是模整数加法和模整数乘法,模p。

假设p是一个素数,整数环Zp表示为GF(p),也称为是拥有素数个元素的素数域或伽罗瓦域。GF(p)中所有非零元素都存在逆元,GF(p)内所有运算模p。

GF(2)是一个非常重要的素域,也是存在的最小有限域。

3、介绍GF\left ( 2^{m} \right )拓展域:

拓展域的加法:例A(x)=x^{7}+x^{6}+x^{4}+1;B(x)=x^{4}+x^{2}+1

C(x)=A(x)+B(x)=x^{7}+x^{6}+x^{2}

乘法:不可约多项式(可以看作素数的作用)例x^{4}+x^{3}+x+1可约即(x^{2}+x+1)(x^{2}+1

GF(2^{m})的逆操作:给定GF(2^{m})与其对应的不可约简化多项式,任何一个非0元素A\inGF(2^{m})的逆元为:A^{-1}(x)*A(x)=1modp(x)

三、AES内部结构

1、单轮AES结构

1、字节代换:AES的字节代换其实就是一个简单的查表操作。AES定义了一个S盒和一个逆S盒。这里不列了

2、扩散层

(1)shift子层

行移位是一个简单的左循环移位操作。例子:

(2)MixColumn子层

列混合变换是通过矩阵相乘来实现的,经行移位后的状态矩阵与固定的矩阵相乘,得到混淆后的状态矩阵

3、密钥加法层

与本轮子密钥进行按位Xor

四、密钥编排

五、python实现

AES只是个基本算法,实现AES有几种模式,主要有ECB、CBC、CFB等几种模式。CBC模式中还有一个偏移量参数IV

ECB加密

from Crypto.Cipher import AES
import base64

# 补位
pad = lambda s: s + chr(16 - len(s) % 16) * (16 - len(s) % 16)
# 除去补16字节的多余字符
unpad = lambda s: s[:-s[-1]]


# 加密函数
def aes_ECB_Encrypt(data, key):   # ECB模式的加密函数,data为明文,key为16字节密钥
    key = key.encode('utf-8')
    data = pad(data)             # 补位
    data = data.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_ECB)  # 创建加密对象
    # encrypt AES加密  B64encode为base64转二进制编码
    result = base64.b64encode(aes.encrypt(data))
    return str(result, 'utf-8')        # 以字符串的形式返回


key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
encrypt_data = aes_ECB_Encrypt(data, key)
print("待加密的字符是:{}\n秘钥为:{}\n加密后的密文为:{}".format(data, key, encrypt_data))

解密

from Crypto.Cipher import AES
import base64


key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
encrypt_data = 

# 解密函数
def aes_ECB_Decrypt(data, key):  # ECB模式的解密函数,data为密文,key为16字节密钥
    key = key.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_ECB)  # 创建解密对象

    # decrypt AES解密  B64decode为base64 转码
    result = aes.decrypt(base64.b64decode(data))
    result = unpad(result)  # 除去补16字节的多余字符
    return str(result, 'utf-8')  # 以字符串的形式返回


decrypt_data = aes_ECB_Decrypt(encrypt_data, key)
print("\n待解密的字符是:{}\n秘钥为:{}\n解密后的字符为:{}".format(encrypt_data, key, decrypt_data))

CBC模式加密

from Crypto.Cipher import AES
import base64

# 补位
pad = lambda s: s + chr(16 - len(s) % 16) * (16 - len(s) % 16)
# 除去补16字节的多余字符
unpad = lambda s: s[:-s[-1]]


# 加密函数
def aes_CBC_Encrypt(data, key, iv):  # CBC模式的加密函数,data为明文,key为16字节密钥,iv为16字节的偏移量
    key = key.encode('utf-8')
    iv = iv.encode('utf-8')  # CBC 模式下的偏移量
    data = pad(data)  # 补位
    data = data.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)  # 创建加密对象
    # encrypt AES加密  B64encode为base64转二进制编码
    result = base64.b64encode(aes.encrypt(data))
    return str(result, 'utf-8')  # 以字符串的形式返回


key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
iv = "1a2b3c4d5e6f7g8h"  # 偏移量
encrypt_data = aes_CBC_Encrypt(data, key, iv)
print("待加密的字符是:{}\n秘钥为:{}\n偏移量为:{}\n加密后的密文为:{}".format(data, key, iv, encrypt_data))

解密

from Crypto.Cipher import AES
import base64

key = '1qaz@WSXabcdefgh'  # 秘钥
data = "haha1234567890"   # 明文字符串
iv = "1a2b3c4d5e6f7g8h"  # 偏移量
encrypt_data = 


# 解密函数
def aes_CBC_Decrypt(data, key, iv):  # CBC模式的解密函数,data为密文,key为16字节密钥
    key = key.encode('utf-8')
    iv = iv.encode('utf-8')
    aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)  # 创建解密对象

    # decrypt AES解密  B64decode为base64 转码
    result = aes.decrypt(base64.b64decode(data))
    result = unpad(result)  # 除去补16字节的多余字符
    return str(result, 'utf-8')  # 以字符串的形式返回


decrypt_data = aes_CBC_Decrypt(encrypt_data, key, iv)
print("\n待解密的字符是:{}\n秘钥为:{}\n偏移量为:{}\n解密后的字符为:{}".format(encrypt_data, key, iv, decrypt_data))

五、例题

NewStarCTF 2023 公开赛道 babyaes

from Crypto.Cipher import AES
import os
from flag import flag
from Crypto.Util.number import *


def pad(data):
    return data + b"".join([b'\x00' for _ in range(0, 16 - len(data))])


def main():
    flag_ = pad(flag)
    key = os.urandom(16) * 2
    iv = os.urandom(16)
    print(bytes_to_long(key) ^ bytes_to_long(iv) ^ 1)
    aes = AES.new(key, AES.MODE_CBC, iv)
    enc_flag = aes.encrypt(flag_)
    print(enc_flag)


if __name__ == "__main__":
    main()
# 3657491768215750635844958060963805125333761387746954618540958489914964573229
# b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'

采用CBC模式,需要key和iv因为key有16*2字节,iv只有16字节,前部爆露,可以得到key和iv然后直接解密

from Crypto.Cipher import AES
from Crypto.Util.number import *

a = 3657491768215750635844958060963805125333761387746954618540958489914964573229
m = b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'

key2 = long_to_bytes(a)[:16]
iv = bytes_to_long(long_to_bytes(a)[16:])^1^bytes_to_long(key2)
aes = AES.new(key2*2, AES.MODE_CBC, long_to_bytes(iv))
c = aes.decrypt(m)
print(c)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值