密码学大作业

密码学大作业

第一次大作业(0930)

题目1

题目内容

题目大致意思就是给你多个使用同一密钥进行流密码加密的密文,解密出来给定密文的信息。

思路

由ASCII码的性质可以知道,空格与字母异或会使字母大小写翻转,字母异或得到的非字母。故将密文分别两两异或,通过结果判断不同明文中可能存在空格的位置,将对应位置上的密文和空格异或,得到对应位置密钥,并最终对目标密文进行解密。
先前已经解出了最后一组明文,只需要将明文与对应的密文16进制异或,得到密钥再与给定的第八组明文进行异或即可。

源码
plaintext = "The secret message is: When using a stream cipher, never use the key more than once"
ciphertext = "32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904"
ciphertext8 = "315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3"


def charListToHexList(charList):
    plainHexList = []
    for i in charList:
        plainHexList.append(hex(ord(i)))
    return plainHexList


if __name__ == '__main__':
    keyList = []
    plainList8 = []
    plaintext8 = ""
    plainList = list(plaintext)
    plainHexList = (charListToHexList(plainList))
    cipherHex = bytes.fromhex(ciphertext)
    cipherHex8 = bytes.fromhex(ciphertext8)

    for i in range(0, len(plainHexList)):
        keyList.append(cipherHex[i] ^ int(plainHexList[i], 16))
        plainList8.append(keyList[i] ^ cipherHex8[i])
    for i in range(0, len(plainList8)):
        plaintext8 += chr(plainList8[i])

    print("密钥(10进制ASCII码表示):", keyList)
    print("第八组明文:" + plaintext8)

结果
密钥(10进制ASCII码表示): [102, 57, 110, 137, 201, 219, 216, 204, 152, 116, 53, 42, 205, 99, 149, 16, 46, 175, 206, 120, 170, 127, 237, 40, 160, 127, 107, 201, 141, 41, 197, 11, 105, 176, 51, 154, 25, 248, 170, 64, 26, 156, 109, 112, 143, 128, 192, 102, 199, 99, 254, 240, 18, 49, 72, 205, 216, 232, 2, 208, 91, 169, 135, 119, 51, 93, 174, 252, 236, 213, 156, 67, 58, 107, 38, 139, 96, 191, 78, 240, 60, 154, 97]
第八组明文:We can see the point where the chip is unhappy if a wrong bit is sent and consumes 

题目2

题目内容

给定类维吉尼亚密码的流密码加密密文(不是相加模26,而是异或),解密出明文信息。

思路

设密钥的长度为x,密文为c,则c[i]、c[i+x]、c[i+2x]……都是明文与同一字符异或得到,所以我们可以猜测密钥长度,遍历密钥的每一个字符的每一个ASCII码可能值,直到对应的明文都是字母或标点为止,这样就能得到密钥和明文。

源码
import string

# text
ciphertext = "F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794"


# 将16进制长串转为10进制ASCII码
def ciphertextToList(ciphertext):
    cipherList = []
    for i in range(0, len(ciphertext), 2):
        cipherList.append(int(ciphertext[i:2 + i], 16))
    return cipherList


# 选取密钥
def keySelect(subCipher):
    charList = string.ascii_letters + " " + "," + "."  # 这仨不能用string.punctuation,问就是乱码
    KeyTest = []
    KeyFin = []
    for i in range(0x00, 0xFF):
        KeyTest.append(i)
        KeyFin.append(i)
    for i in KeyTest:
        for j in subCipher:
            if chr(i ^ j) not in charList:
                KeyFin.remove(i)
                break
    return KeyFin


# main
def Decryption(cipherList):
    KeyFin = []
    KeyLenFin = 0
    for keyLen in range(1, 14):
        alternateKey = []
        for i in range(0, keyLen):
            subArray = cipherList[i::keyLen]
            keyAlter = keySelect(subArray)
            if not keyAlter:
                break
            else:
                alternateKey.insert(i, keyAlter)
        if alternateKey:
            KeyFin = alternateKey
            KeyLenFin = keyLen
            print("长度:", KeyLenFin)
            print("密钥(十进制ASCII码):", KeyFin)
            plaintext = ''
    for i in range(0, len(cipherList)):
        plaintext = plaintext + chr(cipherList[i] ^ KeyFin[i % len(KeyFin)][0])
    print('明文:', plaintext)
    return 0


cipherList = ciphertextToList(ciphertext)

Decryption(cipherList)
结果
长度: 7
密钥(十进制ASCII码): [[186], [31], [145], [178], [83], [205], [62]]
明文: Cryptography is the practice and study of techniques for, among other things, secure communication in the presence of attackers. Cryptography has been used for hundreds, if not thousands, of years, but traditional cryptosystems were designed and evaluated in a fairly ad hoc manner. For example, the Vigenere encryption scheme was thought to be secure for decades after it was invented, but we now know, and this exercise demonstrates, that it can be broken very easily.

题目3

题目内容

Break repeating-key XOR - The Cryptopals Crypto Challenges

思路
  1. 猜测密钥长度KeySize,如从2-30
  2. 计算两个字符串之间的汉明距离
  3. 每次尝试KeySize时,从文件开头截取四个块,两两组合计算其汉明距离
  4. 选取3个最小的汉明距离所对应的KeySize作为密钥长度备选
  5. 知道KeySize大小后,将密文按KeySize大小切片,每片取第一个、第二个……组成新的块
  6. 对新的块而言,解密思路类似作业第2题
  7. 将每个单字符异或的Key拼接起来即为所要的最终的Key,将明文拼接即为完整明文
源码
import base64
from functools import partial
import itertools

letterFreqs = \
    {'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}  # 字母频率


def GetScore(ib):  # 计算输入文本的分值
    score = 0
    for b in ib:
        score += letterFreqs.get(chr(b).lower(), 0)
    return score


def SingleXOR(ib, KeyValue):  # 对每个字符和Key异或
    output = b""
    for ch in ib:
        output += bytes([ch ^ KeyValue])
    return output


def SingleXorBreak(ciphertext):  # 破解单字符异或
    choices = []
    for KeyChoice in range(256):
        PlaintextChoice = SingleXOR(ciphertext, KeyChoice)
        ScoreChoice = GetScore(PlaintextChoice)
        result = {
            "key": KeyChoice,
            "score": ScoreChoice,
            "plaintext": PlaintextChoice
        }
        choices.append(result)
    return sorted(choices, key=lambda c: c['score'], reverse=True)[0]


def HammingDistance(bstr1, bstr2):  # 汉明距离
    distance = 0
    for b1, b2 in zip(bstr1, bstr2):
        dis = b1 ^ b2
        distance += sum([1 for bit in bin(dis) if bit == "1"])
    return distance


def KeyXOR(plaintext, Key):
    ciphertext = b""
    i = 0
    for b in plaintext:
        ciphertext += bytes([b ^ Key[i]])
        i = i + 1 if i < len(Key) - 1 else 0
    return ciphertext


def KeyBreak(text):
    NorDistances = {}
    for KeySize in range(2, 30):
        Slices = [text[i:i + KeySize] for i in range(0, len(text), KeySize)][:4]
        TempDistance = 0
        SlicePair = itertools.combinations(Slices, 2)
        for (a, b) in SlicePair:
            TempDistance += HammingDistance(a, b)
        TempDistance /= 6
        NorDistance = TempDistance / KeySize  # 对汉明距离进行归一化
        NorDistances[KeySize] = NorDistance
    PossibleKeySize = sorted(NorDistances, key=NorDistances.get)[:3]  # 取最小的3个汉明距离所对应的KeySize
    PossiblePlaintext = []
    for i in PossibleKeySize:
        TempKey = b""
        for j in range(i):
            block = b""
            for k in range(j, len(text), i):
                block += bytes([text[k]])
            TempKey += bytes([SingleXorBreak(block)["key"]])
        PossiblePlaintext.append((KeyXOR(text, TempKey), TempKey))
    return max(PossiblePlaintext, key=lambda k: GetScore(k[0]))  # 选取分数最高,即最有可能是正确明文的那一组


if __name__ == '__main__':
    with open("H3.txt") as fp:
        text = base64.b64decode(fp.read())
    result = KeyBreak(text)
    print("Key=", result[1].decode())
    print("----------result----------")
    print(result[0].decode().rstrip())


结果
Key= Terminator X: Bring the noise
----------result----------
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

进程已结束,退出代码0

题目4

题目内容

Cracking SHA1-Hashed Passwords

源码
import hashlib
import itertools
import datetime

starttime = datetime.datetime.now()
hash1 = "67ae1a64661ac8b4494666f58c4822408dd0a3e4"
searchList = [['Q', 'q'], ['W', 'w'], ['I', 'i'], ['N', 'n'], ['5', '%'], ['8', '('], ['0', '='], ['*', '+']]


def encryptSha(str):
    sha = hashlib.sha1(str.encode("utf-8"))
    encrypts = sha.hexdigest()
    return encrypts


if __name__ == '__main__':
    zeroStr = "00000000"
    str4 = ""
    zeroList = list(zeroStr)
    for a in range(0, 2):
        zeroList[0] = searchList[0][a]
        for b in range(0, 2):
            zeroList[1] = searchList[1][b]
            for c in range(0, 2):
                zeroList[2] = searchList[2][c]
                for d in range(0, 2):
                    zeroList[3] = searchList[3][d]
                    for e in range(0, 2):
                        zeroList[4] = searchList[4][e]
                        for f in range(0, 2):
                            zeroList[5] = searchList[5][f]
                            for g in range(0, 2):
                                zeroList[6] = searchList[6][g]
                                for h in range(0, 2):
                                    zeroList[7] = searchList[7][h]
                                    finStr = "".join(zeroList)
                                    for i in itertools.permutations(finStr, 8):
                                        str4 = encryptSha("".join(i))
                                        if str4 == hash1:
                                            print("".join(i))
                                            endtime = datetime.datetime.now()
                                            print("time: " + str(endtime - starttime))

结果
(Q=win*5
time: 0:00:06.105986

第二次大作业(1024)

题目1

题目内容

大致意思就是说解密CBC模式下使用PKCS #5填充的密文,通过与服务器进行交互来得到是否没有错误的信息。

思路
源码
# -*- coding: cp936 -*-

from oracle import *
from Crypto.Util import strxor
import re


def main():
    CipherText = "9F0B13944841A832B2421B9EAF6D9836813EC9D944A5C8347A7CA69AA34D8DC0" \
                 "DF70E343C4000A2AE35874CE75E64C31"
    BlockCount = 2
    Division = len(CipherText) / (BlockCount + 1)
    CipherTextList = re.findall(".{" + str(Division) + "}", CipherText)

    Oracle_Connect()
    PlainText = []
    IVALUE = []
    for bc in range(0, BlockCount):  # 对两组密文分别求解
        print "-" * 60
        print "Now Detecting Block " + str(bc + 1) + "."
        IV = CipherTextList[bc]
        ivalue = []  # 将解密后的ciphertext初始化
        TempIV = "0" * 32  # 初始化 IV
        TempIV = re.findall('.{2}', TempIV)[::-1]
        padding = 1
        for l in range(16):
            print "-" * 60
            print "Now Detecting Last " + str(l + 1) + ' Byte In Block.'
            for ll in range(l):
                TempIV[ll] = hex(int(ivalue[ll], 16) ^ padding)[2:].zfill(2)  # 更新 TempIV

            for n in range(0, 256):  # 从0x00-0xFF遍历寻找符合条件的字节
                TempIV[l] = hex(n)[2:].zfill(2)
                data = "".join(TempIV[::-1]) + CipherTextList[bc + 1]
                print data
                ctext = [(int(data[i:i + 2], 16)) for i in range(0, len(data), 2)]
                Feedback = Oracle_Send(ctext, 2)
                if str(Feedback) == "1":
                    ivalue += [hex(n ^ padding)[2:].zfill(2)]
                    break
            print "-" * 60
            print "Now The Value of IV is: ", "".join(TempIV[::-1])
            print "The Temporary Ciphertext after Decryption is: ", "".join(ivalue[::-1])

            padding += 1
        ivalue = "".join(ivalue[::-1])
        IVALUE += [ivalue]
        # IV与CADe异或求明文
        plaintext = re.findall("[0-9a-f]+", str(hex(int(IV, 16) ^ int("".join(ivalue), 16))))[1].decode("hex")
        PlainText += [plaintext]
        print "Detecting Block", bc + 1, "Finished."
        print "The ivalue" + str(bc + 1) + " is:", ivalue
        print "The Plaintext" + str(bc + 1) + "is:", plaintext
        print "-" * 60
    Oracle_Disconnect()
    print "The Ciphertext after Decryption is: ", "".join(IVALUE)
    print "The Plaintext is:", "".join(PlainText)


if __name__ == '__main__':
    main()
结果

在这里插入图片描述

题目2

题目内容

Set2 - The Cryptopals Crypto Challenges

源码
c7.py
from Crypto.Cipher import AES
from c9 import *


def decrypt_aes_128_ecb(data, key):
    cipher = AES.new(key, AES.MODE_ECB)
    return pkcs7_unpad(cipher.decrypt(data))
c8.py
from Crypto.Cipher.AES import block_size


def count_aes_ecb_repetitions(ciphertext):
    chunks = [ciphertext[i:i + block_size] for i in range(0, len(ciphertext), block_size)]
    number_of_duplicates = len(chunks) - len(set(chunks))
    return number_of_duplicates


def detect_ecb_encrypted_ciphertext(ciphertexts):
    best = (-1, 0)
    for i in range(len(ciphertexts)):
        repetitions = count_aes_ecb_repetitions(ciphertexts[i])
        best = max(best, (i, repetitions), key = lambda t: t[1])
    return best


def main():
    ciphertexts = [bytes.fromhex(line.strip()) for line in open("8.txt")]
    result = detect_ecb_encrypted_ciphertext(ciphertexts)
    print("The   ",result[0])
    print("the",result[1])
    print(result[0])
    assert result[0] == 132

if __name__ == '__main__':
    main()
c9.py
def pkcs7_padding(message,block_size):
    if len(message) == block_size:
        return message
    padding_thing = block_size - (len(message) % block_size)  # 填充内容、长度计算
    return message + bytes([padding_thing] * padding_thing)


def is_pkcs7_padded(bin_data):
    padding = bin_data[-bin_data[-1]:]
    return all(padding[b] == len(padding) for b in range(0, len(padding)))


def pkcs7_unpad(padded_message):
    if len(padded_message) == 0:
        raise Exception("the input must contain at least one byte!")
    if not is_pkcs7_padded(padded_message):
        return padded_message
    padded_len = padded_message[len(padded_message) - 1]
    return padded_message[:-padded_len]


def c9_main():
    message=b"YELLOW SUBMARINE"
    padded_message = pkcs7_padding(message, 20)
    print(padded_message)
    assert pkcs7_unpad(padded_message) == message


if __name__ == '__main__':
    c9_main()
c10.py
from Crypto.Cipher.AES import block_size
from base64 import b64decode
from c7 import *
from c9 import *


def encrypt_aes_128_ecb(message, key):
    cipher_message = AES.new(key, AES.MODE_ECB)
    return cipher_message.encrypt(pkcs7_padding(message, AES.block_size))


def ez_xor(bin_data1, bin_data2):
    return bytes([b1 ^ b2 for b1, b2 in zip(bin_data1, bin_data2)])


def encrypt_aes_128_cbc(message, key, iv):
    ciphertext = b""
    p = iv
    for i in range(0, len(message), AES.block_size):
        temp_plaintext_block = pkcs7_padding(message[i: i + AES.block_size], AES.block_size)
        block_ciphertext_in = ez_xor(temp_plaintext_block, p)
        encrypted_block = encrypt_aes_128_ecb(block_ciphertext_in, key)
        ciphertext += encrypted_block
        p = encrypted_block

    return ciphertext


def decrypt_aes_128_cbc(data, key, iv, unpad=True):
    plaintext = b""
    p = iv
    for i in range(0, len(data), AES.block_size):
        temp_ciphertext_block = data[i:i + AES.block_size]
        decrypted_blcok = decrypt_aes_128_ecb(temp_ciphertext_block, key)
        plaintext += ez_xor(p, decrypted_blcok)
        p = temp_ciphertext_block

    return pkcs7_unpad(plaintext) if unpad else plaintext


def main():
    iv = b'\x00' * AES.block_size
    key = b"YELLOW SUBMARINE"
    with open("10.txt") as f:
        bin_data = b64decode(f.read())
    print(decrypt_aes_128_cbc(bin_data, key, iv).decode().rstrip())


if __name__ == '__main__':
    main()

c12.py
from Crypto import Random

from c10 import *


class ECBOracle:
    def __init__(self, secret_padding):
        self._key = Random.new().read(AES.key_size[0])
        self._secret_padding = secret_padding

    def encrypt(self, data):
        return encrypt_aes_128_ecb(data + self._secret_padding, self._key)


def find_block_length(encryption_oracle):
    my_text = b""
    ciphertext = encryption_oracle.encrypt(my_text)
    initial_len = len(ciphertext)
    new_len = initial_len

    while new_len == initial_len:
        my_text += b"A"
        ciphertext = encryption_oracle.encrypt(my_text)
        new_len = len(ciphertext)

    return new_len - initial_len

c14.py(第6题)
from random import randint

from c12 import *
from c8 import *


class HarderECBOracle(ECBOracle):
    def __init__(self, secret_padding):
        super(HarderECBOracle, self).__init__(secret_padding)
        self._random_prefix = Random.new().read(randint(0, 255))

    def encrypt(self, data):
        return encrypt_aes_128_ecb(self._random_prefix + data + self._secret_padding, self._key)


def get_next_byte(prefix_length, block_length, curr_decrypted_message, encryption_oracle):
    length_to_use = (block_length - prefix_length - (1 + len(curr_decrypted_message))) % block_length
    my_input = b"A" * length_to_use
    cracking_length = prefix_length + length_to_use + len(curr_decrypted_message) + 1
    real_ciphertext = encryption_oracle.encrypt(my_input)
    for i in range(256):
        fake_ciphertext = encryption_oracle.encrypt(my_input + curr_decrypted_message + bytes([i]))
        if fake_ciphertext[:cracking_length] == real_ciphertext[:cracking_length]:
            return bytes([i])
    return b""


def has_equal_block(ciphertext, block_length):
    for i in range(0, len(ciphertext) - 1, block_length):
        if ciphertext[i:i + block_length] == ciphertext[i + block_length:i + 2 * block_length]:
            return True
    return False


def find_prefix_length(encryption_oracle, block_length):
    ciphertext1 = encryption_oracle.encrypt(b"")
    ciphertext2 = encryption_oracle.encrypt(b"a")
    prefix_length = 0
    for i in range(0, len(ciphertext2), block_length):
        if ciphertext1[i:i + block_length] != ciphertext2[i:i + block_length]:
            prefix_length = i
            break
    for i in range(block_length):
        fake_input = bytes([0] * (2 * block_length + i))
        ciphertext = encryption_oracle.encrypt(fake_input)
        if has_equal_block(ciphertext, block_length):
            return prefix_length + block_length - i if i != 0 else prefix_length
    raise Exception("the oracle is not using ECB")


def byte_at_a_time_ecb_harder_decryption(encryption_oracle):
    block_length = find_block_length(encryption_oracle)
    ciphertext = encryption_oracle.encrypt(bytes([0] * 64))
    assert count_aes_ecb_repetitions(ciphertext) > 0
    prefix_length = find_prefix_length(encryption_oracle, block_length)
    mysterious_text_length = len(encryption_oracle.encrypt(b"")) - prefix_length
    secret_padding = b""
    for i in range(mysterious_text_length):
        secret_padding += get_next_byte(prefix_length, block_length, secret_padding, encryption_oracle)
    return secret_padding


def main():
    secret_padding = b64decode("Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg"
                               "aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq"
                               "dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg"
                               "YnkK")
    oracle = HarderECBOracle(secret_padding)
    discovered_secret_padding = byte_at_a_time_ecb_harder_decryption(oracle)
    print(pkcs7_unpad(discovered_secret_padding))


if __name__ == '__main__':
    main()
c15.py(第7题)
def is_pkcs7_padded(bin_data):
    padding = bin_data[-bin_data[-1]:]
    return all(padding[b] == len(padding) for b in range(0, len(padding)))
c16.py(第8题)
from Crypto.Cipher import AES
from Crypto import Random
from c10 import *


class Oracle:
    def __init__(self):
        self._key = Random.new().read(AES.key_size[0])
        self._iv = Random.new().read(AES.block_size)
        self._prefix = "comment1=cooking%20MCs;userdata="
        self._suffix = ";comment2=%20like%20a%20pound%20of%20bacon"

    def encrypt(self, data):
        data = data.replace(";", "").replace("=", "")
        plaintext = (self._prefix + data + self._suffix).encode()
        return encrypt_aes_128_cbc(plaintext, self._key, self._iv)

    def decrypt_and_check_admin(self, ciphertext):
        data = decrypt_aes_128_cbc(ciphertext, self._key, self._iv)
        return b";admin=true" in data


def find_block_length(encryption_oracle):
    text = ""
    ciphertext = encryption_oracle(text)
    ordi_len = len(ciphertext)
    new_len = ordi_len
    while new_len == ordi_len:
        text += "A"
        ciphertext = encryption_oracle(text)
        new_len = len(ciphertext)
    return new_len - ordi_len


def find_prefix_length(encryption_oracle, block_length):
    ciphertext_a = encryption_oracle("A")
    ciphertext_b = encryption_oracle("B")
    common_len = 0
    while ciphertext_a[common_len] == ciphertext_b[common_len]:
        common_len += 1
    common_len = int(common_len / block_length) * block_length
    for i in range(1, block_length + 1):
        ciphertext_a = encryption_oracle("A" * i + "X")
        ciphertext_b = encryption_oracle("A" * i + "Y")
        if ciphertext_a[common_len:common_len + block_length] == ciphertext_b[common_len:common_len + block_length]:
            return common_len + (block_length - i)


def cbc_bit_flip_atk(encryption_oracle):
    block_length = find_block_length(encryption_oracle.encrypt)
    prefix_length = find_prefix_length(encryption_oracle.encrypt, block_length)
    addition_prefix_bytes = (block_length - (prefix_length % block_length)) % block_length
    total_prefix_length = prefix_length + addition_prefix_bytes
    plaintext = "?admin?true"
    additional_plaintext_bytes = (block_length - (len(plaintext) % block_length)) % block_length
    final_palintext = additional_plaintext_bytes * "?" + plaintext
    ciphertext = encryption_oracle.encrypt(addition_prefix_bytes * "?" + final_palintext)
    semicolon = ciphertext[total_prefix_length - 11] ^ ord("?") ^ ord(";")
    equals = ciphertext[total_prefix_length - 5] ^ ord("?") ^ ord("=")
    forced_ciphertext = ciphertext[:total_prefix_length - 11] + bytes([semicolon]) + \
                        ciphertext[total_prefix_length - 10: total_prefix_length - 5] + \
                        bytes([equals]) + ciphertext[total_prefix_length - 4:]
    return forced_ciphertext


def main():
    encryption_oracle = Oracle()
    forced_ciphertext = cbc_bit_flip_atk(encryption_oracle)
    print(encryption_oracle.decrypt_and_check_admin(forced_ciphertext))


if __name__ == '__main__':
    main()
结果
c14(第6题)
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"
c16(第8题)
True

题目3

题目内容

MTC3 - AES key

思路
  1. 根据参考资料,16.1-16.1.5,可以算出?的值
  2. 根据文件得到kseed
  3. 把kseed和c相连,计算d的sha1,前十六位是ka,后十六位是kb
  4. Ka和kb奇偶校验生成key
  5. 把密文以base64解码,用key解密
源码
# coding=utf-8


import base64
import re

from Crypto.Cipher import AES
from Crypto.Hash import SHA


def odd_even_verify(ka):  # 调整奇偶校验位
    k = []
    for i in ka:
        if bin(int(i, 16) >> 1).count('1') % 2 == 0:  # 若1的个数为偶数
            k += [hex(1 + (int(i, 16) >> 1 << 1))[2:].zfill(2)]  # 调整为奇数
        else:
            k += [hex((int(i, 16) >> 1 << 1))[2:].zfill(2)]  # 不动
    return ''.join(k)


def get_sha1(d):
    h = SHA.new()
    h.update(d)  # 计算d的sha1
    return h.hexdigest()[:32]  # 获取sha1的前32位


def main():
    c = '9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6' \
        '+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI '  # C由文档中获取
    c = base64.b64decode(c)
    code = '12345678<8<<<1110182<1111167<<<<<<<<<<<<<<<4'
    code_no = code[:9]
    code_verify = code[9]
    nation = code[10:13]
    birth = code[13:19]
    birth_verify = code[19]
    sex = code[20]
    date_end = code[21:27]
    date_end_verify = code[27]
    other = code[28:]
    # 按照文件提取code中机读区对应的信息
    info = code_no + code_verify + birth + birth_verify + date_end + date_end_verify  # 得到机读区信息
    k_seed = get_sha1(info)  # 获取k_seed
    d = (k_seed + '0' * 7 + '1').decode('hex')  # 连接k_seed和c
    key = get_sha1(d)  # 获取key的sha1
    k1 = odd_even_verify(re.findall('.{2}', key[:16]))  # 对前半后半分别进行奇偶校验位的调整
    k2 = odd_even_verify(re.findall('.{2}', key[16:]))
    key = k1 + k2  # 再将密钥key拼接起来
    print 'The key is:', key
    ciphertext = AES.new(key.decode('hex'), AES.MODE_CBC, ('0' * 32).decode('hex'))
    print 'The M is:', ciphertext.decrypt(c)


if __name__ == '__main__':
    main()
结果
The key is: ea8645d97ff725a898942aa280c43179
The M is: Herzlichen Glueckwunsch. Sie haben die Nuss geknackt. Das Codewort lautet: Kryptographie!      

第三次大作业(RSA大礼包)

题目

题目内容

这次的题目是2016年密码挑战赛的第三题,大意上是说现在有一个RSA的加解密软件,并且有一些明密文对和对应参数,同时截获了一些密文。现在利用多种针对RSA的攻击,对明密文对和对应的参数,以及截获的密文进行分析和挖掘。从加密数据中,恢复通关密语和RSA的体制参数,以及对应的明文。

思路

利用多种针对RSA的攻击,如RSA共模攻击、低指数攻击、p-1分解法、公因数攻击、Fermat攻击等,尽可能多得在所截获的数据中,挖掘出明文和参数。

源码
共模攻击

如果一对消息的模数和明文相同,而指数互质,那么可以找到 x , y x,y x,y 使
x e 1 + y e 2 = 1 xe_1+ye_2=1 xe1+ye2=1 那么有 c 1 x + c 2 y ≡ m   m o d   n c_1^x+c_2^y≡m ~mod~n c1x+c2ym mod n
Frame0、Frame4采用该种攻击方法

def egcd(a, b):
    if a == 0:
        return b, 0, 1
    else:
        g, y, x = egcd(b % a, a)
        return g, x - (b // a) * y, y


# 共模攻击
def sameMod():
    index1 = 0
    index2 = 0
    for i in range(21):
        for j in range(i + 1, 21):
            if F[i] == F[j]:
                index1, index2 = i, j
    n = int(F[index1], 16)
    e1 = int(T[index1], 16)
    e2 = int(T[index2], 16)
    c1 = int(S[index1], 16)
    c2 = int(S[index2], 16)
    s = egcd(e1, e2)
    s1 = s[1]
    s2 = s[2]
    if s1 < 0:
        s1 = - s1
        c1 = gmpy2.invert(c1, n)
    elif s2 < 0:
        s2 = - s2
        c2 = gmpy2.invert(c2, n)

    m = pow(c1, s1, n) * pow(c2, s2, n) % n

    result = binascii.a2b_hex(hex(m)[-16:]).decode('ascii')

    return result
公因数攻击

Frame1、Frame18采用该种攻击方法

def sameFactor():
    index = []
    for i in range(21):
        for j in range(i + 1, 21):
            if int(F[i], 16) == int(F[j], 16):
                continue
            prime = gmpy2.gcd(int(F[i], 16), int(F[j], 16))
            if prime != 1:
                index.append(i)
                index.append(j)
                frameP = prime
    frameQ1 = int(F[index[0]], 16) // frameP
    frameQ18 = int(F[index[1]], 16) // frameP

    framePhi1 = (frameP - 1) * (frameQ1 - 1)
    framePhi18 = (frameP - 1) * (frameQ18 - 1)

    frameD1 = gmpy2.invert(int(T[index[0]], 16), framePhi1)
    frameD18 = gmpy2.invert(int(T[index[1]], 16), framePhi18)

    plaintext1 = gmpy2.powmod(int(S[index[0]], 16), frameD1, int(F[index[0]], 16))
    plaintext18 = gmpy2.powmod(int(S[index[1]], 16), frameD18, int(F[index[1]], 16))

    fin1 = binascii.a2b_hex(hex(plaintext1)[-16:]).decode('ascii')
    fin18 = binascii.a2b_hex(hex(plaintext18)[-16:]).decode('ascii')

    print('Frame', index[0], ':', fin1, sep='')
    print('Frame', index[1], ':', fin18, sep='')
    return 0

低指数攻击

若多个消息明文和指数相同,指数和明文个数相同,而且模数互质,那么可以列出方程组 { m e ≡ c 1   m o d   n 1 m e ≡ c 2   m o d   n 2 m e ≡ c 3   m o d   n 3 . . . m e ≡ c e   m o d   n e \left\{\begin{matrix} m^e≡c_1~mod~n_1\\m^e≡c_2~mod~n_2\\m^e≡c_3~mod~n_3\\...\\m^e≡c_ e~mod~n_e \end{matrix}\right. mec1 mod n1mec2 mod n2mec3 mod n3...mece mod ne
利用中国剩余定理可以解出 m e < n 1 n 2 n 3 . . . n e m^e<n_1n_2n_3...n_e me<n1n2n3...ne ,从而直接开根解出明文

Frame3、Frame8、Frame12、Frame16、Frame20采用该种攻击方法

def lowE():
    sessions = [{"c": int(S[3], 16), "n": int(F[3], 16)},
                {"c": int(S[8], 16), "n": int(F[8], 16)},
                {"c": int(S[12], 16), "n": int(F[12], 16)},
                {"c": int(S[16], 16), "n": int(F[16], 16)},
                {"c": int(S[20], 16), "n": int(F[20], 16)}]
    data = []
    for session in sessions:
        data += [(session['c'], session['n'])]
    x, y = ChineseRemainder(data)

    pt = gmpy2.iroot(gmpy2.mpz(x), 5)
    print(binascii.a2b_hex(hex(pt[0])[-16:]).decode('ascii'))

    return binascii.a2b_hex(hex(pt[0])[2:])
Pollard p-1分解法

选取一个数 B B B,并令 k = B ! k=B! k=B!,如果 B B B足够大,则有 p − 1 ∣ k p-1|k p1k。由
2 p − 1 ≡ 1   m o d   n 2^{p-1}≡1~mod~n 2p11 mod n,有 p ∣ 2 k − 1 p|2^k-1 p2k1。又有 p ∣ n p|n pn,所以有 p ∣ a p|a pa a ≡ 2 k − 1   m o d   n 。 a≡2^k-1~mod~n。 a2k1 mod n将幂与 n n n取最大公因数即可分解模数。

Frame2、Frame6、Frame19均采用该种攻击方法

def p1(n):
    B = pow(2,20)
    a = 2
    for i in range(2, B + 1):
        a = pow(a, i, n)
        d = gmpy2.gcd(a - 1, n)
        if (d >= 2) and (d <= (n - 1)):
            q = n // d
            n = q * d
    return d


def pollardResolve():
    index_list = [2, 6, 19]
    plaintext = []
    for i in range(3):
        N = int(F[index_list[i]], 16)
        c = int(S[index_list[i]], 16)
        e = int(T[index_list[i]], 16)
        p = p1(N)
        q = N // p
        framePhi = (p - 1) * (q - 1)
        d = gmpy2.invert(e, framePhi)
        m = gmpy2.powmod(c, d, N)
        plaintext.append(binascii.a2b_hex(hex(m)[2:]))
        print(f"Frame{index_list[i]}:{(binascii.a2b_hex(hex(m)[-16:])).decode('ascii')}")
    return plaintext
费马分解法

p、q比较接近时,可以使用这种攻击方法
Frame10采用该种攻击方法

def fermat(n):
    B = math.factorial(2 ** 14)
    v = 0
    i = 0
    u0 = gmpy2.iroot(n, 2)[0] + 1
    while i <= (B - 1):
        u = (u0 + i) * (u0 + i) - n
        if gmpy2.is_square(u):
            v = gmpy2.isqrt(u)
            break
        i += 1
    p = u0 + i + v
    return p


def fermatResolve():
    for i in range(10, 14):
        N = int(F[i], 16)
        p = fermat(N)
结果
共模攻击
My secre
公因数攻击
Frame1:. Imagin
Frame18:m A to B
低指数攻击
t is a f
Pollard p-1 分解法
Frame2: That is
Frame6: "Logic 
Frame19:instein.
费马分解法
Frame10:will get

通过上边的攻击我们可以破解出Frame0、1、2、3、4、6、8、10、12、16、18、19、20,再通过某些科学手段(百度)得到以下结果

"My secret is a famous saying of Albert Einstein. That is "Logic will get you from A to B. Imagination will take you everywhere.""
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Hitsz现代密码学作业主要包括以下几个方面的内容。首先,作业会涉及对于对称加密算法和公钥加密算法的理解和应用。对于对称加密算法,作业可能会要求我们理解其工作原理和常用的对称加密算法,如AES、DES等,并能够进行加密和解密的实践操作。同时,还可能需要我们能够了解对称加密算法的优缺点和安全性。 其次,作业可能会要求我们学习和理解公钥加密算法的原理与应用。作业可能会要求我们学习RSA算法,理解其加密和解密的过程,并能够实践操作。同时,我们还需要了解公钥加密算法的安全性和应用场景,以及与对称加密算法的比较。 此外,作业可能会要求我们学习和应用密码学中的哈希函数和消息认证码。我们需要学习哈希函数的原理和常用的哈希算法,如MD5、SHA-1等,并能够进行哈希函数的实践运用。同时,我们还需要了解消息认证码的概念和应用,以及其在保障数据完整性和身份认证方面的作用。 最后,作业还可能会要求我们学习和理解密码学中的数字签名和密钥交换协议。我们需要了解数字签名的原理和应用,以及其在保证消息的真实性和不可抵赖性方面的作用。同时,我们还需要学习密钥交换协议的原理和常见的协议,如Diffie-Hellman密钥交换协议等,并能够进行实践操作。 综上所述,Hitsz现代密码学作业涉及对对称加密算法、公钥加密算法、哈希函数、消息认证码、数字签名以及密钥交换协议的学习和应用。我们需要理解它们的原理与应用场景,并能够进行实践操作。这些作业将帮助我们全面了解和掌握现代密码学的基本概念和技术,为今后的密码学研究和应用奠定基础。 ### 回答2: hitsz现代密码学作业是哈尔滨信息科技大学计算机学院中的一门课程作业。该课程主要介绍现代密码学的基本理论和应用,通过学习和掌握密码学的基本概念、加密算法和安全协议等,培养学生在信息安全领域的专业知识和能力。 在这门作业中,学生需要完成一系列与现代密码学相关的任务。这些任务可能包括选择适当的加密算法来实现安全的数据传输、设计密码学方案来保护敏感数据的机密性、进行密码攻击与防御的实验等。学生需要运用所学的知识和技能,结合实际情境和问题,提出解决方案并完成相应的实验和报告。 通过这门作业,学生可以加深对现代密码学基本原理的理解,提高密码学算法的设计和应用能力。同时,这门作业也能帮助学生培养解决实际安全问题的思维和能力,增强对信息安全的认识和重视程度。 总之,hitsz现代密码学作业是一门具有实践性和综合性的课程作业,通过完成这些作业任务,学生将能够在实际应用中熟练运用密码学的知识和技术,为信息安全提供有效的保护。 ### 回答3: HITSZ现代密码学作业涉及到现代密码学领域的一些基本概念和技术。在作业中,我们需要掌握对称加密算法和公钥密码学的基本原理和应用。对称加密算法包括DES、AES等,公钥密码学包括RSA、椭圆曲线密码学等。作业内容主要包括以下几个方面: 1. 对称加密算法的原理和应用:需要了解DES和AES算法的工作原理,以及它们在实际应用中的使用场景和安全性评估。 2. 公钥密码学的基本原理和应用:需要掌握RSA算法的原理,了解数字签名、密钥交换和身份认证等应用。同时,需要理解椭圆曲线密码学的基本概念和应用场景。 3. 密码学中的安全性分析:需要了解密码学中的攻击模型和常见的攻击手段,如密码分析、密钥泄露等。同时,需要学习密码学的安全性分析方法,如信息论和计算复杂性理论。 4. 实际应用案例研究:通过学习现代密码学的实际应用案例,如SSL/TLS安全协议,可理解密码学在互联网传输安全中的重要性和应用场景。 在完成作业的过程中,我们可以通过查阅相关教材、参考文献以及互联网上的学术资源来加深理解和掌握这些知识。同时,还可以尝试编写一些简单的代码实现,如DES算法的加解密过程,以提升对密码算法的认识。 总之,HITSZ现代密码学作业要求我们深入了解现代密码学的基本知识和技术,以及其在实际应用中的运用。通过完成作业,我们可以加深对密码学的理解,并将其应用于实际场景中,提高信息安全的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值