密码学课程作业
1 仿射密码
密文:
FMXVED KAPHFERBND KRXRSREFMORUD SD KD VSHVUFED KAPRKD LYEVLRHHRH
明文:
algorithmsarequitegeneraldefinitionsofarithmeticprocesses
algorithms are quite general definitions of arithmetic processes
统计26个英文字母在密文中的频率分布
字母 | 频率 | 字母 | 频率 |
---|---|---|---|
A | 2 | N | 1 |
B | 1 | O | 1 |
C | 0 | P | 2 |
D | 7 | Q | 0 |
E | 5 | R | 8 |
F | 4 | S | 3 |
G | 0 | T | 0 |
H | 5 | U | 2 |
I | 0 | V | 4 |
J | 0 | W | 0 |
K | 5 | X | 2 |
L | 2 | Y | 1 |
M | 2 | Z | 0 |
频率较高的前五位是:R D E H K
按照英文字母的频率统计,推测R就是E,D就是T
设仿射加密函数为
联立解a,b的值,检查gcd(a,26)=1是否成立
(1)推测R是E,D是T
解得:
(2)推测R是E,E是T
解得:
(3)推测R是E,H是T
解得:
(4)推测R是E,K是T
解得:
a的逆元:
推测出R就是E,K就是T,进而算出:
加密:
解密:
最后求出明文为:
algorithms are quite general definitions of arithmetic processes
2 单表密码分析
明文和密文之间的关系是一一对应的。
v 密文:
YKHLBA JCZ SVIJ JZB LZVHI JCZ VHJ DR IZXKHLBA VSS RDHEI DR YVJV LBXSKYLBA YLALJVS IFZZXC CVI LEFHDNZY EVBTRDSY JCZ FHLEVHT HZVIDB RDH JCLI CVI WZZB JCZ VYNZBJ DR ELXHDZSZXJHDBLXI JCZ XDEFSZQLJT DR JCZ RKBXJLDBI JCVJ XVB BDP WZ FZHRDHEZY WT JCZ EVXCLBZ CVI HLIZB YHVEVJLXVSST VI V HZIKSJ DR JCLI JCVJ PZHZ DBXZ XDBILYZHZY IZXKHZ VHZ BDP WHZVMVWSZ
这段密文还有338个字母,按出现次数由多到少的顺序排列,依次为Z,J,V,B,H,D,I,L,C,X,S ,Y,E,R,T,F, K,A,W,N, P, M,Q,U,G,O。
由于Z出现的次数高于其它字母,推断z对应明文字母e,看到jcz 出现了三次,英文中最常用的三个字的单词就是the,所以先锁定这三个的翻译,从这里打开突破口,推断J对面明文字母t,C对应明文字母h。继而密文JCVJ中,我们判断V对应明文字母a,即为that。再观察JZB,我们进行可能的试探,得到结果为ten,即B对应n。密文VI,V为a,猜测I为明文的s,即as。我们继续猜测VSS,S对应明文中的l,即all。猜测DR中,D代表o,故DR可能代表or on of ok中的一个,or意味着明文字母r与自身相对应,显然不和理。由于B代表n,所以也不是on。那么R必代表f或k。如果代表k,则RDH译为kor,不合理,故R代表明文f,即of。基于此,我们对密文不断尝试和拆解,得到明密文对应表:
明文 | 密文 | 明文 | 密文 |
---|---|---|---|
a | V | n | B |
b | W | o | D |
c | X | p | F |
d | Y | q | G |
e | Z | r | H |
f | R | s | I |
g | A | t | J |
h | C | u | K |
i | L | v | N |
j | O | w | P |
k | M | x | Q |
l | S | y | T |
m | E | z | U |
依据上表,对密文求解得到明文:
during the last ten years the art of securing all forms of data including digital speech has improved manyfold primary reason for this has been the advent of microelectronics the complexity of the function that can now be performed by the machine has risen dramatically as a result of this recentdevelopment technology many of the cipher system that were once considered secure are now breakable
3 维吉尼亚
密文:
CHREEVOAHMAERATBIAXXWTNXBEEOPHBSBQMQEQERBWRVXUOAKXAOSXXWEAHBWGJMMQMNKGRFVG
XWTRZXWIAKLXFPSKAUTEMNDCMGTSXMXBTUIADNGMGPSRELXNJELXVRVPRTULHDNQWTWDTYGBPHXTF
ALJHASVBFXNGLLCHRZBWELEKMSJIKNBHWRJGNMGJSGLXFEYPHAGNRBIEQJTAMRVLCRREMNDGLXRRIMG
NSNRWCHRQHAEYEVTAQEBBIPEEWEVKAKOEWADREMXMTBHHCHRTKDNVRZCHRCLQOHPWQAIIWXNR
MGWOIIFKEE
大致思路:1 确定密钥长度 2 确定密钥 3 根据密钥恢复明文,最后得到:
秘钥:
janet
明文:
the almond tree was in tentative blossom the days were longer often ending with magnificent evenings of corrugated pink skies the hunting season was over with hounds and guns put away for six months the vineyards were busy again as the well organized farmers treated their vines and the more lackadaisical neighbors hurried to do the pruning they should have done in november
Python如下:
import wordninja
def encrypt(m, k):
c = ''
j = 0
for i in range(len(m)):
if m[i].isupper():
c += chr(((letter_to_numberber(m[i]) + letter_to_numberber(k[j % len(k)])) % 26) + ord('A'))
j += 1
elif m[i].islower():
c += chr(((letter_to_numberber(m[i]) + letter_to_numberber(k[j % len(k)])) % 26 + ord('a')))
j += 1
else:
c += m[i]
return c
# 带有密钥的解密
def decrypt(c, k):
m = ''
j = 0
for i in range(len(c)):
if c[i].isupper():
m += chr(((letter_to_numberber(c[i]) - letter_to_numberber(k[j % len(k)])) % 26) + ord('A'))
j += 1
elif c[i].islower():
m += chr(((letter_to_numberber(c[i]) - letter_to_numberber(k[j % len(k)])) % 26) + ord('a'))
j += 1
else:
m += c[i]
m = m.lower()
return m
# 获取唯密文解密时的密钥
def crack(c):
cipher = ''
c = c.lower()
# 删除特殊符号
for ch in c:
if ch.islower():
cipher += ch
keylength = get_length(cipher)
key = get_key(cipher, keylength)
key = key.lower()
return key
# 获取密钥长度
# 遍历3-20位,相同间隔的字母相同数最多的位数,即最有可能为密钥长度
def get_length(cipher):
keyLen = 1
maxCount = 0
# 密钥长度3-20位
for step in range(3, 15):
count = 0
for i in range(len(cipher) - step):
if cipher[i] == cipher[i - step]:
count += 1
if count > maxCount:
maxCount = count
keyLen = step
return keyLen
# 确定密钥
def get_key(text, length):
key = ''
Standard = [0.082, 0.015, 0.028, 0.043, 0.127, 0.022, 0.02, 0.061, 0.07, 0.002, 0.008, 0.04, 0.024,
0.067, 0.075, 0.019, 0.001, 0.06, 0.063, 0.091, 0.028, 0.01, 0.023, 0.001, 0.02, 0.001]
cipher_matrix = matrix(text, length)
for i in range(length):
col = [row[i] for row in cipher_matrix]
freq = letter_frequency(col)
Coin_index = []
for j in range(26):
index = 0.00000
for k in range(26):
index += freq[k] * Standard[k]
Coin_index.append(index)
freq = freq[1:] + freq[:1]
temp = 1
ch = ''
for j in range(len(Coin_index)):
if abs(Coin_index[j] - 0.065546) < temp:
temp = abs(Coin_index[j] - 0.065546)
ch = chr(j + 97)
key += ch
return key
# 统计a-z字母出现的频率
def letter_frequency(text):
freq = []
for i in range(97, 123):
count = 0
for ch in text:
if ch == chr(i):
count += 1
freq.append(count / len(text))
return freq
# 二维矩阵表示密文,行:用密钥加密,列:同一个字母移位加密的
def matrix(text, length):
cipher_matrix = []
row = []
i = 0
for ch in text:
row.append(ch)
i += 1
if i % length == 0:
cipher_matrix.append(row)
row = []
return cipher_matrix
# 将字母转换为数字
def letter_to_numberber(s):
if s.isupper():
return (ord(s) - ord('A')) % 26
elif s.islower():
return (ord(s) - ord('a')) % 26
def main():
while True:
mode = input("\n[E]加密\t[D]解密\t[C]唯密文\t[Q]结束\n")
if mode == 'E' or mode == 'e':
try:
message = input("请输入明文:\n")
key = input("请输入密钥:\n")
cipher = encrypt(message, key)
print("得到密文:\n" + cipher)
except:
print("错误!")
elif mode == 'D' or mode == 'd':
try:
cipher = input("请输入密文:\n")
key = input("请输入密钥:\n")
message = decrypt(cipher, key)
print(' '.join(wordninja.split(message)))
except:
print("错误!")
elif mode == 'C' or mode == 'c':
try:
cipher = input("请输入密文:\n")
key = crack(cipher)
print("猜测得到密钥:\n" + key)
message = decrypt(cipher, key)
print(' '.join(wordninja.split(message)))
except:
print("错误!")
elif mode == 'Q' or mode == 'q':
break
else:
continue
if __name__ == '__main__':
main()
4 CBC字节翻转攻击
打开容器后看到登录页面
通过dirsearch扫一下目录发现扫除一个.index.php.swp文件
get请求获取文件
打不开,拿到kali用vi去修复 ,命令为vi -r index.php.swp,进入修复后的文件
代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">;
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Login Form</title>
<link href="static/css/style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="static/js/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$(".username").focus(function() {
$(".user-icon").css("left","-48px");
});
$(".username").blur(function() {
$(".user-icon").css("left","0px");
});
$(".password").focus(function() {
$(".pass-icon").css("left","-48px");
});
$(".password").blur(function() {
$(".pass-icon").css("left","0px");
});
});
</script>
</head>
<?php
define("SECRET_KEY", file_get_contents('/root/key'));
define("METHOD", "aes-128-cbc");
session_start();
function get_random_iv(){
$random_iv='';
for($i=0;$i<16;$i++){
$random_iv.=chr(rand(1,255));
}
return $random_iv;
}
function login($info){
$iv = get_random_iv();
$plain = serialize($info);
$cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);
$_SESSION['username'] = $info['username'];
setcookie("iv", base64_encode($iv));
setcookie("cipher", base64_encode($cipher));
}
function check_login(){
if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){
$cipher = base64_decode($_COOKIE['cipher']);
$iv = base64_decode($_COOKIE["iv"]);
if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){
$info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");
$_SESSION['username'] = $info['username'];
}else{
die("ERROR!");
}
}
}
function show_homepage(){
if ($_SESSION["username"]==='admin'){
echo '<p>Hello admin</p>';
echo '<p>Flag is $flag</p>';
}else{
echo '<p>hello '.$_SESSION['username'].'</p>';
echo '<p>Only admin can see flag</p>';
}
echo '<p><a href="loginout.php">Log out</a></p>';
}
if(isset($_POST['username']) && isset($_POST['password'])){
$username = (string)$_POST['username'];
$password = (string)$_POST['password'];
if($username === 'admin'){
exit('<p>admin are not allowed to login</p>');
}else{
$info = array('username'=>$username,'password'=>$password);
login($info);
show_homepage();
}
}else{
if(isset($_SESSION["username"])){
check_login();
show_homepage();
}else{
echo '<body class="login-body">
<div id="wrapper">
<div class="user-icon"></div>
<div class="pass-icon"></div>
<form name="login-form" class="login-form" action="" method="post">
<div class="header">
<h1>Login Form</h1>
<span>Fill out the form below to login to my super awesome imaginary control panel.</span>
</div>
<div class="content">
<input name="username" type="text" class="input username" value="Username" οnfοcus="this.value=\'\'" />
<input name="password" type="password" class="input password" value="Password" οnfοcus="this.value=\'\'" />
</div>
<div class="footer">
<input type="submit" name="submit" value="Login" class="button" />
</div>
</form>
</div>
</body>';
}
}
?>
</html>
以上代码考察了CBC翻转攻击的利用。它禁止直接提交用户名为admin进行登陆,但是返回flag的条件又是session中用户名要是admin。所以需要构造类似”edmin”形式或者”aemin”等形式的用户名,之后通过修改iv和cipher,通过CBC翻转攻击将字符e还原成”admin”
我们从这里可以看到iv和cipher
修改cipher,然后再bp中的cookie中设置iv和翻转后的cipher,提交。
from urllib import parse
import base64
cipher = 'RfttKSc%2FFSFXqS2L1Hl872eCmHECra3rEdHkyITq1g9B8yFWOMaqWE%2BVrSReNTgE6boqxxjEWgzbWwzTQOedBg%3D%3D'
cipher = base64.b64decode(parse.unquote(cipher))
bytes_cipher = bytearray(cipher)
#a:2:{s:8:"username";s:5:"edmin";s:8:"password";s:8:"password";}
bytes_cipher[9] = bytes_cipher[9]^ord('m')^ord('a') #将e修改为a
cipher = parse.quote(base64.b64encode(bytes_cipher))
print(cipher)
但是出现服务器提示反序列化失败,原因是在我们修改edmin为admin的时候,是通过修改第一块数据来修改的,所以第一个块数据被破坏。程序中要求username要等于admin,所以不能利用文章里的说的填充字符。 第一个块数据被破坏,但第一个块数据是和IV有关,所以只要将在CBC字符翻转攻击,得到新的IV就可以修复第一块数据。
from urllib import parse
import base64
iv = 'xOuryflEZpmjJYRLPKW2eA%3D%3D'
plain = 'sf0tBJxhhh2QbN8rhYku2W1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjg6IlBhc3Nvd3JkIjt9'
a = 'a:2:{s:8:"userna'
iv = base64.b64decode(parse.unquote(iv))
plain = base64.b64decode(plain) #提示的错误的plain
bytes_iv = bytearray(iv)
for i in range(16):
bytes_iv[i] = ord(a[i])^bytes_iv[i]^plain[i]
iv = parse.quote(base64.b64encode(bytes_iv))
print(iv)
#得到iv:FCy09x5W2rwJay4T3F72wA%3D%3D
把得到的新的修复的iv值替换掉,cipher仍然为翻转后的cipher,然后提交,查看返回包,就能拿到flag{d6a8f9dccca121b77a6f3cc7416fc3cb}
下面简单介绍一下CBC字节翻转攻击
CBC加密的特性,简述来说:
明文首先被分割成等长的若干个明文块,每个明文块将作为下一个明文块加密过程中输入的一部分,从而影响到下一个明文块的加密结果。在一般情况下,明文会被分成等长的16字节的明文块,不足16字节部分,会用特殊填充符填充,图示如下:
这其中有一个重要输入IV,是随机生成的初始向量,它影响第一个明文块的结果,并且将传递到整个加密链中,以保证对同一明文每次的加密结果都是不同的。
CBC模式中涉及到的异或运算,是本次进行CBC翻转攻击的关键所在。
类似于CBC加密的过程,CBC解密的过程也是将当前的密文块作为下一个密文块参与运算的输入,具体如图:
假设我们修改了第一个密文块的第4个字节,那么根据CBC模式的解密,它将影响下一个密文块的解密结果,如图标红部分:
那么CBC翻转攻击如下:
我们知道已知A=B^C,可以得到结论B=A^C,并且也能得到A^C^B=0
设第一块的第4个字节设为变量A,第二块的明文中第4个字节设为变量C,在第二块加密产生的第4个字节设为变量B
因为A^B=C,根据结论有B=A^C
如果人为将A变量值改变为A^C的结果,那么参与运算后A^B将等于A^C^B=B^B=0,第二个产生的明文的第4个字节将变为0
如果将A变量值改变为A^C^X(这里X是任意字符),那么参与运算后,A^B将等于A^C^X^B=B^X^B=X,第二个产生的明文的第4个字节将变为X字符,这样,第二块密文块解密的结果就可控了。