大致原理:
单表替换密码(将明文中的字母按照对照表映射成密文),会将明文中的统计规律带到密文中,如明文中出现最多的是A,则密文中出现最多的就是A在对照表下的密文。因此我们可以通过频率分析的方法找到对照表,破解密文。
代码思想:
读入密文ciphertext.txt(只有小写的字母+空格+回车的密文),然后统计其中各个字母出现的次数并对统计结果进行排序。然后我们还有一个已知的排序结果words_frequency(这个是百度搜到的公开单字母频率),这两个排序结果的对应关系我们就认为是对照表了,接着使用这个对照表翻译密文得到明文out.txt
vim task1.py
sudo python3 task1.py
def get_frequency(path):
res = {}
for i in range(ord('a'),ord('z')+1):
res[chr(i)]=0
with open(path) as f:
for line in f.readlines():
for ch in line.strip():
if ch.isalpha():
res[ch.lower()] +=1
return sorted(res.items(),key=lambda s:s[1],reverse=True)
def main():
ciphertext_frequency= get_frequency('./ciphertext.txt')
words_frequency= "ETAOINRSHDCLMPUFGWYBKJVXQZ";
trans = {}
for i in range(26):
trans[ciphertext_frequency[i][0]] = words_frequency[i].lower()
with open('./out.txt',mode='a') as f1:
with open('./ciphertext.txt') as f2:
for line in f2.readlines():
for ch in line.strip():
if ch.isalpha():
f1.write(trans[ch.lower()])
else:
f1.write(ch)
if __name__ == '__main__':
main()
用AES加密算法(128位密钥,CBC模式)加密一个文件并进行解密。
openssl enc -aes-128-cbc -e -in ./plaintext.txt -out cipher.bin -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-cbc -d -in cipher.bin -out out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
用AES加密算法(128位密钥),分别采用ECB和CBC模式加密一个bmp图片,查看加密后的图片。
openssl enc -aes-128-ecb -in ./pic_original.bmp -out ./pic_ecb.bmp -e -K 00112233445566778889aabbccddeeff
openssl enc -aes-128-cbc -in ./pic_original.bmp -out ./pic_cbc.bmp -e -K 00112233445566778889aabbccddeeff -iv 0102030405060708
发现图片无法查看,因为.bmp文件的前54个字节包含图片的标题信息,被我们加密了,我们重新调整一下,下面获取原图片的标题信息(前54字节),结合新图片的内容信息(55以后字节),构造新的图片
head -c 54 ./pic_original.bmp >header
tail -c +55 pic_ecb.bmp > ecb_body
tail -c +55 pic_cbc.bmp > cbc_body
cat header ecb_body > newECB.bmp
cat header cbc_body > newCBC.bmp
我们可以发现,CBC模式的加密比较彻底,而ECB模式的加密仍然会显示出原文的统计信息。
分别创建大小为5,10,15字节的文件
echo -n "01234" > 5.txt
echo -n "0123456789" > 10.txt
echo -n "012345678999999" > 15.txt
先用AES加密算法(128位密钥,CBC模式)加密这些文件,然后解密这些密文(选择解密时不去除padding的选项),观察解密后各个文件的尺寸大小
注:
我们在解密的时候添加了参数-nopad,表示不去除padding
openssl enc -aes-128-cbc -e -in ./5.txt -out ./cbc/5-cbc.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-cbc -e -in ./10.txt -out ./cbc/10-cbc.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-cbc -e -in ./15.txt -out ./cbc/15-cbc.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-cbc -d -in ./cbc/5-cbc.txt -out ./cbc/5-cbc-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
openssl enc -aes-128-cbc -d -in ./cbc/10-cbc.txt -out ./cbc/10-cbc-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
openssl enc -aes-128-cbc -d -in ./cbc/15-cbc.txt -out ./cbc/15-cbc-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
用xxd命令查看各个解密文件中padding的内容
xxd 5-cbc-out.txt
xxd 10-cbc-out.txt
xxd 15-cbc-out.txt
用AES加密算法(128位密钥,ECB模式,CFB模式,OFB模式)进行类似上述(2)和(3)的操作,查看各个解密文件中padding的内容。
注:
观察发现,ECB、CBC出现填充,而CFB、OFB没有填充。因为CFB、OFB可以将DES转换为流密码。
ecb
openssl enc -aes-128-ecb -e -in ./5.txt -out ./ecb/5-ecb.txt -K 00112233445566778889aabbccddeeff
openssl enc -aes-128-ecb -e -in ./10.txt -out ./ecb/10-ecb.txt -K 00112233445566778889aabbccddeeff
openssl enc -aes-128-ecb -e -in ./15.txt -out ./ecb/15-ecb.txt -K 00112233445566778889aabbccddeeff
openssl enc -aes-128-ecb -d -in ./ecb/5-ecb.txt -out ./ecb/5-ecb-out.txt -K 00112233445566778889aabbccddeeff -nopad
openssl enc -aes-128-ecb -d -in ./ecb/10-ecb.txt -out ./ecb/10-ecb-out.txt -K 00112233445566778889aabbccddeeff -nopad
openssl enc -aes-128-ecb -d -in ./ecb/15-ecb.txt -out ./ecb/15-ecb-out.txt -K 00112233445566778889aabbccddeeff -nopad
xxd 5-ecb-out.txt
xxd 10-ecb-out.txt
xxd 15-ecb-out.txt
注:
xxd的第三列表示的是这一行原本的内容,发现多了一些...
cfb
openssl enc -aes-128-cfb -e -in ./5.txt -out ./cfb/5-cfb.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-cfb -e -in ./10.txt -out ./cfb/10-cfb.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-cfb -e -in ./15.txt -out ./cfb/15-cfb.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-cfb -d -in ./cfb/5-cfb.txt -out ./cfb/5-cfb-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
openssl enc -aes-128-cfb -d -in ./cfb/10-cfb.txt -out ./cfb/10-cfb-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
openssl enc -aes-128-cfb -d -in ./cfb/15-cfb.txt -out ./cfb/15-cfb-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
xxd 5-cfb-out.txt
xxd 10-cfb-out.txt
xxd 15-cfb-out.txt
ofb
openssl enc -aes-128-ofb -e -in ./5.txt -out ./ofb/5-ofb.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-ofb -e -in ./10.txt -out ./ofb/10-ofb.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-ofb -e -in ./15.txt -out ./ofb/15-ofb.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
openssl enc -aes-128-ofb -d -in ./ofb/5-ofb.txt -out ./ofb/5-ofb-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
openssl enc -aes-128-ofb -d -in ./ofb/10-ofb.txt -out ./ofb/10-ofb-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
openssl enc -aes-128-ofb -d -in ./ofb/15-ofb.txt -out ./ofb/15-ofb-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708 -nopad
xxd 5-ofb-out.txt
xxd 10-ofb-out.txt
xxd 15-ofb-out.txt
创建一个至少1000字节大的文本文件
#!/bin/bash
f=""
for (( i = 1; i < 1024; ++i)); do f=$f"6"; done
echo $f >> f.txt
用AES加密算法(128位密钥,ECB模式)加密这个文件
openssl enc -aes-128-ecb -e -in ./f.txt -out ./ecb/f-ecb.txt -K 00112233445566778889aabbccddeeff
用bless工具修改密文中第55个字节中的1个bit
bless ./ecb/f-ecb.txt
注:
bless工具貌似是不支持直接修改的,只能删除、复制和黏贴。比如我想将DF修改成EF,做法就是选中EF(是鼠标拖动,让ED块变红),然后右键复制,选中DF右键删除,然后再右键黏贴。
解密被上述修改后的密文,查看解密后的明文有什么变化
openssl enc -aes-128-ecb -d -in ./ecb、f-ecb.txt -out ./ecb/f-ecb-out.txt -K 00112233445566778889aabbccddeeff
xxd ./ecb/f-ecb-out.txt
用AES加密算法(128位密钥,CBC模式,OFB模式)进行类似上述(2)-(4)的操作,查看对应解密后的明文有什么变化
注:
不同的模式下,密文改变带来的影响不同,具体怎么个不同法和采用的模式有关。
cbc模式
openssl enc -aes-128-cbc -e -in ./f.txt -out ./cbc/f-cbc.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
bless ./cbc/f-cbc.txt
openssl enc -aes-128-cbc -d -in ./cbc/f-cbc.txt -out ./cbc/f-cbc-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
xxd ./cbc/f-cbc-out.txt
ofb模式
openssl enc -aes-128-ofb -e -in ./f.txt -out ./ofb/f-ofb.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
bless ./ofb/f-ofb.txt
openssl enc -aes-128-ofb -d -in ./ofb/f-ofb.txt -out ./ofb/f-ofb-out.txt -K 00112233445566778889aabbccddeeff -iv 0102030405060708
xxd ./ofb/f-ofb-out.txt
注:
只有OFB模式不存在扩散问题,一个字节错误不会影响整组的解密错误,仅第55字节错误
用AES加密算法(128位密钥,CBC模式),采用相同的密钥和不同的初始化向量加密一个相同的文件,观察加密结果是否相同
echo -n "01234" > f.txt
openssl enc -aes-128-cbc -e -in ./f.txt -out ./f-cbc-iv1.txt -K 123456 -iv 111111
openssl enc -aes-128-cbc -e -in ./f.txt -out ./f-cbc-iv2.txt -K 123456 -iv 222222
cat f-cbc-iv1.txt
cat f-cbc-iv2.txt
用AES加密算法(128位密钥,CBC模式),采用相同的密钥和相同的初始化向量加密一个相同的文件,观察加密结果是否相同
openssl enc -aes-128-cbc -e -in ./f.txt -out ./f-cbc-iv1-same.txt -K 123456 -iv 111111
cat f-cbc-iv1.txt
cat f-cbc-iv1-same.txt
思考为什么IV必须唯一
从实验结果可以发现,在key相同的情况,相同的IV会导致加密结果相同,所以为了信息安全IV必须唯一。
已知明文攻击:假设采用OFB模式进行加密,加密时所采用的IV是相同的,请破译P2的内容。
首先使用提供的命令创建容器,然后操作
课堂上大佬说,将Yes和No的16字节形式输入进去,然后对比一下就出结果了,我实在是看不出来啊
下面分别是Yes和No的16字节形式
5965730D0D0D0D0D0D0D0D0D0D0D0D0D
4E6F0E0E0E0E0E0E0E0E0E0E0E0E0E0E
大致思想:
这个任务说的是,已知key是由words.txt文件中的某一行填充而成,给你明文、密文、iv以及words.txt,能不能找到key
代码思路:
核心思想就是把words.txt中的每一个单词当成key,结合已知的iv构造aes,然后使用这个aes去解码密文,如果得到的明文和已知明文相同,那就找到了key。
碰到的问题:
python中的Crypto包,把iv定死了成16bite,而任务给的是32bite的iv,没有办法,就自己重新生成了密文,希望老师不介意。(并且自己来做的话,填充函数这边就可以自己发挥了)
import base64
from Crypto.Cipher import AES
class EncryptDate:
def __init__(self, key, iv):
self.length = 16
self.key = self.pad(key).encode("utf-8")
self.iv = iv.encode("utf-8")
self.aes = AES.new(self.key, AES.MODE_CBC, self.iv)
self.unpad = lambda s: s[0:-s[-1]]
def pad(self, text): # 填充函数
count = len(text.encode('utf-8'))
add = self.length - (count % self.length)
entext = text + (chr(add) * add)
return entext
def encrypt(self, encrData): # 加密函数
a = self.pad(encrData)
res = self.aes.encrypt(a.encode("utf-8"))
msg = str(base64.b64encode(res), encoding="utf8")
return msg
def decrypt(self, decrData): # 解密函数
res = base64.decodebytes(decrData.encode("utf-8"))
msg_text = self.aes.decrypt(res)
decrypt_text = self.unpad(msg_text).decode('utf8')
return decrypt_text
def main():
# 使用Syracuse作为key,9999999999999999作为iv对明文进行加密
aes_key = "Syracuse"
aes_iv = "9999999999999999"
text_data = 'This is a top secret.'
encrypt_data = EncryptDate(aes_key, aes_iv).encrypt(text_data)
# 在words.txt中找到key
# 寻找的方式就是使用该单词作为key,配合已知的iv进行解密,若得到的明文和已知的明文相同,则找到了key
with open("words.txt") as f:
for line in f.readlines():
word = line.strip()
try:
decrypt_data = EncryptDate(word, aes_iv).decrypt(encrypt_data)
except Exception as e:
continue
if(decrypt_data == text_data):
print("原来key是:"+word)
break;
if __name__ == '__main__':
main()