Crypto report

### 第一次实验(0930)
**任务1**:题目给出一段 base64编码,该编码来自一段由秘钥重复异或明文所得的密文。且给出了秘钥的长度范围。要求解出对应明文。

原理:可见 [Challenge 6 Set 1 - The Cryptopals Crypto Challenges](https://cryptopals.com/sets/1/challenges/6)

代码:
```python
import re
import base64
with open("challenge6.txt","r") as fp:
    wenben=[base64.b64decode(i) for i in fp.readlines()]
wenben="".join(wenben)
def english_test(sentence):
    score = 0
    freqs = {
        'a': 0.0651738, 'b': 0.0124248, 'c': 0.0217339,
        'd': 0.0349835, 'e': 0.1041442, 'f': 0.0197881,
        'g': 0.0158610, 'h': 0.0492888, 'i': 0.0558094,
        'j': 0.0009033, 'k': 0.0050529, 'l': 0.0331490,
        'm': 0.0202124, 'n': 0.0564513, 'o': 0.0596302,
        'p': 0.0137645, 'q': 0.0008606, 'r': 0.0497563,
        's': 0.0515760, 't': 0.0729357, 'u': 0.0225134,
        'v': 0.0082903, 'w': 0.0171272, 'x': 0.0013692,
        'y': 0.0145984, 'z': 0.0007836, ' ': 0.1918182}
    for x in sentence.lower():
        if x in freqs:
            score += freqs[x]
    return score 
def hanming(x,y):
    num=0
    for i in range(0,len(x)):
        t=ord(x[i])^ord(y[i])
        while t:
           if t&1 : num+=1
           t>>=1
    return num
def thechar(st1):
    score = 0
    for i in range(0, 255):
        tmp = []
        for j in range(0,len(st1)):  
            tmp += chr(i ^ int(st1[j],16))
        tmpstr = "".join(tmp)
 
        num=english_test(tmpstr)
        if num > score:
            score = num  
            key = chr(i)
    return key
 
ans = []
for i in range(1,41):
    str1=[]
    str2=[]
    str3=[]
    str4=[]
    for j in range(0,i): str1+=[wenben[j]]
    for j in range(i,2*i): str2+=[wenben[j]]
    for j in range(2*i,3*i): str3+=[wenben[j]]
    for j in range(3*i,4*i): str4+=[wenben[j]]
    str1="".join(str1)
    str2="".join(str2)
    str3="".join(str3)
    str4="".join(str4)
    x1=float(hanming(str1,str2))/i
    x2=float(hanming(str2,str3))/i
    x3=float(hanming(str3,str4))/i
    x4=float(hanming(str1,str4))/i
    x5=float(hanming(str1,str3))/i
    x6=float(hanming(str2,str4))/i
    aa=(x1+x2+x3+x4+x5+x6)/6
    ans+=[(i,aa)]
ans.sort(lambda x,y:cmp(x[1],y[1]))
for i in range(len(ans)):
    print ans[i][0],ans[i][1]
 
wenben=wenben.encode('hex')
block=[re.findall(r'(.{2})',z)  for z in re.findall(r'(.{58})',wenben)]
 
keyy = []
for i in range(0,29):
    tmp=[]
    for j in range(0,len(block)):
        tmp+=[block[j][i]]
    keyy+=[thechar(tmp)]
keyy="".join(keyy)
 
print keyy
keyy=keyy*10000
 
wenben=wenben.decode('hex')
an=[]
for i in range(0,len(wenben)):
    an+=[chr(ord(wenben[i])^ord(keyy[i]))]
an="".join(an)
print an

# 5465726d696e61746f7220583a204272696e6720746865206e6f697365
'''I'm back and I'm ringin' the bell 
A rockin' on the mike while the fly girls yell 
In ecstasy in the back of me 
Well that's my DJ Deshay cuttin' all them Z's 
Hittin' hard and the girlies goin' crazy 
Vanilla's on the mike, man I'm not lazy. 

I'm lettin' my drug kick in 
It controls my mouth and I begin 
To just let it flow, let my concepts go 
My posse's to the side yellin', Go Vanilla Go! 

Smooth 'cause that's the way I will be 
And if you don't give a damn, then 
Why you starin' at me 
So get off 'cause I control the stage 
There's no dissin' allowed 
I'm in my own phase 
The girlies sa y they love me and that is ok 
And I can dance better than any kid n' play 

Stage 2 -- Yea the one ya' wanna listen to 
It's off my head so let the beat play through 
So I can funk it up and make it sound good 
1-2-3 Yo -- Knock on some wood 
For good luck, I like my rhymes atrocious 
Supercalafragilisticexpialidocious 
I'm an effect and that you can bet 
I can take a fly girl and make her wet. 

I'm like Samson -- Samson to Delilah 
There's no denyin', You can try to hang 
But you'll keep tryin' to get my style 
Over and over, practice makes perfect 
But not if you're a loafer. 

You'll get nowhere, no place, no time, no girls 
Soon -- Oh my God, homebody, you probably eat 
Spaghetti with a spoon! Come on and say it! 

VIP. Vanilla Ice yep, yep, I'm comin' hard like a rhino 
Intoxicating so you stagger like a wino 
So punks stop trying and girl stop cryin' 
Vanilla Ice is sellin' and you people are buyin' 
'Cause why the freaks are jockin' like Crazy Glue 
Movin' and groovin' trying to sing along 
All through the ghetto groovin' this here song 
Now you're amazed by the VIP posse. 

Steppin' so hard like a German Nazi 
Startled by the bases hittin' ground 
There's no trippin' on mine, I'm just gettin' down 
Sparkamatic, I'm hangin' tight like a fanatic 
You trapped me once and I thought that 
You might have it 
So step down and lend me your ear 
'89 in my time! You, '90 is my year. 

You're weakenin' fast, YO! and I can tell it 
Your body's gettin' hot, so, so I can smell it 
So don't be mad and don't be sad 
'Cause the lyrics belong to ICE, You can call me Dad 
You're pitchin' a fit, so step back and endure 
Let the witch doctor, Ice, do the dance to cure 
So come up close and don't be square 
You wanna battle me -- Anytime, anywhere 

You thought that I was weak, Boy, you're dead wrong 
So come on, everybody and sing this song 

Say -- Play that funky music Say, go white boy, go white boy go 
play that funky music Go white boy, go white boy, go 
Lay down and boogie and play that funky music till you die. 

Play that funky music Come on, Come on, let me hear 
Play that funky music white boy you say it, say it 
Play that funky music A little louder now 
Play that funky music, white boy Come on, Come on, Come on 
Play that funky music '''
```

**任务2**:题目给出用户输入密码时使用到的按键,给出密码长度及密码经 SHA1 哈希的结果。要求解出用户的密码。

原理:爆破。

代码:

![[Pasted image 20220109152907.png]]

### 第二次实验(1024)

**任务1** :题目指定了一个服务器,该服务器尝试解密收到的任意密文,并返回解密成功或失败。题目给出了一段密文,要求解出对应的明文。

原理:Padding oracle attack

代码:

```python
from oracale_for_py3 import *
import sys

cipher = bytes.fromhex("9F0B13944841A832B2421B9EAF6D9836813EC9D944A5C8347A7CA69AA34D8DC0DF70E343C4000A2AE35874CE75E64C31")
cipher_len = len(cipher)
size = 16
block = [cipher[i:i+size] for i in range(0, cipher_len, size)]

def set_dummy_byte(dummy, i, j):
    dummy = dummy[::-1]
    dummy = dummy[:i] + bytes([j]) + dummy[i+1:]
    dummy = dummy[::-1] 
    return dummy
        
def decry(begin, iv):
    result = []
    for i in begin:
        result += i
    result_byte = bytes(result)[::-1]
    result_str = ''
    for i in range(len(iv)):
        result_str += chr(iv[i]^result_byte[i])
    return result_str

def main():
    plain = ''
    for z in range(1,len(block)):
        check = []
        dummy = bytes([0])*size
        padding = 1
        for i in range(0, size):
            tmp = []
            print("processing", i, "bit")
            for j in range(0, 0x100):
                dummy = set_dummy_byte(dummy, i, j)
                fake = dummy + block[z]

                flag = 0
                while (flag != 1):
                    try:
                        Oracle_Connect()                    
                        ret = Oracle_Send(fake, 2)
                        Oracle_Disconnect()                    
                    except Exception:
                        print('.',end='')
                        continue
                    else:
                        flag = 1

                if chr(ret) == '1':
                    print('right: ', hex(j), '<===')
                    target = j ^ padding
                    tmp.append(target)
                    break
                elif chr(ret) == '0':
                    pass
                else:
                    print('error: ', hex(j))
                    input()

            check.append(tmp)
            padding += 1
            print('padding:',padding)

            for k in range(i+1):
                dummy_byte_next = check[k][0] ^ padding
                if len(check[k]) == 0:
                    print('no match')
                elif len(check[k]) == 1:
                    dummy = set_dummy_byte(dummy, k, dummy_byte_next)
                else:
                    print('more than one match')
                    input()

        plain += decry(check,block[z-1])
    print(plain)
    
if __name__ == '__main__':
    main()
```

![[Pasted image 20220109153758.png]]

**任务2**:题目给出一个神谕 `AES-128-ECB(random-prefix || attacker-controlled || target-bytes, random-key)`,要求解出 target-bytes。

原理:根据 ECB 模式加密中各块相互独立的特点,进行枚举和比较解出 target-bytes。

代码:
```python
key = bytes(random_key(16))
random_prefix = random_key(randint(0, 256))

def encryption_oracle(data):
    unknown_string = bytearray((
        "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg\n" +
        "aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq\n" +
        "dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg\n" +
        "YnkK"
    ).decode("base64"))
    plaintext = pad_pkcs7(
        random_prefix + data + unknown_string,
        AES.block_size,
    )
    return aes_128_ecb_enc(plaintext, key)

def get_prefix_size(oracle, block_size):
    for prefix_padding_size in range(block_size):
        reps = 10
        prefix_padding = bytearray("A" * prefix_padding_size)
        buffer = oracle(prefix_padding + bytearray("YELLOW SUBMARINE" * reps))
        prev_block = count = index = None
        for i in range(0, len(buffer), block_size):
            block = buffer[i: i + block_size]
            if block == prev_block:
                count += 1
            else:
                index = i
                prev_block = block
                count = 1

            if count == reps:
                return index, prefix_padding_size

def get_unknown_string(oracle):
    block_size = get_block_size(oracle)
    prefix_size_rounded, prefix_padding_size = get_prefix_size(oracle, block_size)
    unknown_string_size = (
        get_unknown_string_size(oracle) -
        prefix_size_rounded -
        prefix_padding_size
    )

    unknown_string = bytearray()
    unknown_string_size_rounded = (
        ((unknown_string_size / block_size) + 1) *
        block_size
    )
    for i in range(unknown_string_size_rounded - 1, 0, -1):
        d1 = bytearray("A" * (i + prefix_padding_size))
        c1 = oracle(d1)[
            prefix_size_rounded:
            unknown_string_size_rounded + prefix_size_rounded
        ]
        for c in range(256):
            d2 = d1[:] + unknown_string + chr(c)
            c2 = oracle(d2)[
                prefix_size_rounded:
                unknown_string_size_rounded + prefix_size_rounded
            ]
            if c1 == c2:
                unknown_string += chr(c)
                break
    return unknown_string

get_unknown_string(encryption_oracle)
    
# b"Rollin' in my 5.0\nWith my rag-top down so my hair can blow\nThe girlies on standby waving just to say hi\nDid you stop? No, I just drove by\n" 
```

**任务3**:实现 padding 检查算法。

原理:padding 内容与长度的特点。

代码:
```python
def pkcs7_padding_validation(byte_string: bytes)->bytes:
    last_byte = byte_string[-1]
    if last_byte > len(byte_string):
        return ValueError("bad padding")
    for i in range(last_byte, 0, -1):
        if byte_string[-i] != last_byte:
            raise ValueError("bad padding")
    return byte_string[:-last_byte]

pkcs7_padding_validation(b"ICE ICE BABY\x04\x04\x04\x04")
# pkcs7_padding_validation(b"ICE ICE BABY\x05\x05\x05\x05")
pkcs7_padding_validation(b"ICE ICE BABY\x01\x02\x03\x04")
```

![[Pasted image 20220109163652.png]]

**任务4**:题目给定明文格式,要求修改 comment2 的值。

原理:CBC 比特翻转攻击。

代码:
```python
from Crypto.Cipher import AES
from os import urandom

BLOCK_SIZE = 16
KEY_SIZE = 16
IV_SIZE = 16

key = urandom(KEY_SIZE)
iv = urandom(IV_SIZE)

prefix = b"comment1=cooking%20MCs;userdata="
suffix = b";comment2=%20like%20a%20pound%20of%20bacon" 

def filter_and_pad(pt):
    pt = pt.replace(b";",b"%").replace(b"=",b"%")
    return prefix + pt + suffix

def PKCS7_padding(s):
    if len(s)%BLOCK_SIZE != 0:
        return s + chr((BLOCK_SIZE*(len(s)//BLOCK_SIZE)+BLOCK_SIZE)-len(s)).encode()*((BLOCK_SIZE*(len(s)//BLOCK_SIZE + 1))-len(s))
    return s

def encrypt(pt):
    pt = PKCS7_padding(pt)
    aes = AES.new(key, AES.MODE_CBC, iv)
    ct = aes.encrypt(pt)
    return ct

def cbc_decrypt(ct):
    aes = AES.new(key, AES.MODE_CBC, iv)
    dec = aes.decrypt(ct)
    if b";admin=true;" in dec:
        return True
    return False

def CBC_bitflipping_attack(ct):
    semicolon = ct[len(prefix)-16] ^ ord("%") ^ ord(";")
    equals = ct[len(prefix)-10] ^ ord("%") ^ ord("=")
    return ct[:len(prefix) - 16] + bytes([semicolon]) + ct[len(prefix)-15:len(prefix) - 10] + bytes([equals]) + ct[len(prefix) - 9:]

def main():
    pt = b";admin=true"
    ct = encrypt(filter_and_pad(pt))
    alt_ct = (CBC_bitflipping_attack(ct))
    print (cbc_decrypt(alt_ct))

if __name__ == "__main__":
    main()
```

![[Pasted image 20220109165317.png]]

### 第三次实验

**任务3**:解决2016全国高校密码数学挑战赛赛题三。Alice 使用某 RSA 加密软件发送密文,题目给出被截获的 21 个加密帧数据,加密帧数据的格式也被给出。要求尽可能多地解出 Alice 发送的明文。

原理:尝试使用常见的 RSA 攻击方式解出明文,如共模攻击、广播攻击、公因数攻击和 p - 1 分解。

代码:
```python
from Crypto.Util.number import inverse
 
def itos(num):
    string = ''
    for i in range(8):
        string += chr(num % 256)
        num >>= 8
    string = string[::-1]
    num >>= 352
    ret = num & ((1 << 32) - 1)
    return ret, string
 
def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a % b)
 
def extend_gcd(a, b):
    if b == 0:
        return 1, 0
    s1, s2 = extend_gcd(b, a % b)
    ret = s1 - a // b * s2
    return s2, ret
 
def common_modulus_attack(n, e1, c1, e2, c2):
    s1, s2 = extend_gcd(e1, e2)
    # print(x,y)
    if s1 < 0:
        s1 = -s1
        c1 = inverse(c1, n)
    if s2 < 0:
        s2 = -s2
        c2 = inverse(c2, n)
    ret = pow(c1, s1, n) * pow(c2, s2, n) % n
    return ret
 
def common_factor_attack(n1, e1, c1, n2, e2, c2):
    p = gcd(n1, n2)
    q1 = n1 // p
    q2 = n2 // p
    phi1 = (p - 1) * (q1 - 1)
    phi2 = (p - 1) * (q2 - 1)
    d1 = inverse(e1, phi1)
    d2 = inverse(e2, phi2)
    ret1 = pow(c1, d1, n1)
    ret2 = pow(c2, d2, n2)
    return ret1, ret2 
 
def chinese_remainder_theorem(a, m):
    M = 1
    for i in m:
        M *= i
    ret = 0
    for i in range(len(m)):
        ret = (ret + a[i] * M // m[i] * inverse(M // m[i], m[i])) % M
    return ret
 
def broadcast_attack(a, m, e):
    c = chinese_remainder_theorem(a, m)
    l = 1
    r = c
    while l + 1 < r:
        md = (l + r) // 2
        if md ** e < c:
            l = md
        else:
            r = md
    if l ** e == c:
        return l
    if r ** e == c:
        return r
    return 0
 
def pollard_p1(n, e, c, b):
    k = 1
    for i in range(b):
        k *= i + 1
    p = gcd(pow(2, k, n) - 1, n)
    if p == 1 or p == n:
        return 0
    q = n // p
    if p * q != n:
        return 0
    phi = (p - 1) * (q - 1)
    d = inverse(e, phi)
    return pow(c, d, n)
 
def attack():
    n = []
    e = []
    c = []
    
    # 处理加密帧格式
    for i in range(21):
        f = open('./Frame' + str(i))
        s = f.read()
        n.append(int(s[:256], 16))
        e.append(int(s[256:512], 16))
        c.append(int(s[512:], 16))
 
    m = [0 for i in range(21)]
 
    # 共模攻击
    print("尝试共模攻击..")
    for i in range(21):
        for j in range(i):
            if n[i] == n[j]:
                m[i] = common_modulus_attack(n[i], e[i], c[i], e[j], c[j])
                m[j] = m[i]
                print(i, j, "=>", itos(m[i])[1])

    # 广播攻击
    print("尝试广播攻击..")
    index = [3, 8, 12, 16, 20]
    temp = broadcast_attack([c[i] for i in index], [n[i] for i in index], 5)
    for i in index:
        m[i] = temp
    print(index, "=>", itos(temp)[1])
 
    # 公因数攻击
    print("尝试公因数攻击..")
    for i in range(21):
        for j in range(i):
            if gcd(n[i], n[j]) > 1 and n[i] != n[j]:
                m[i], m[j] = common_factor_attack(n[i], e[i], c[i], n[j], e[j], c[j])
                print(i, "=>", itos(m[i])[1])
                print(j, "=>", itos(m[j])[1])
 
    # Pollard p-1 分解
    print("尝试 Pollard p-1 分解..")
    for i in range(1, 21):
        if m[i] > 0:
            continue
        temp = pollard_p1(n[i], e[i], c[i], 10000)
        if temp > 0:
            print(i, "=>", itos(temp)[1])
 
if __name__ == '__main__':
    attack()
```
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值