【现代密码学】作业二

Question1

问题原文

PA2 option

In thisassignment, you must decrypt a challenge ciphertext generated using AES inCBC-mode with PKCS #5 padding. (Note: technically this is PKCS #7 padding,since the block size of AES is 16 bytes. But the padding is done in exactly thesame way as PKCS #5 padding.) To do so, you will be given access to a server thatwill decrypt any ciphertexts you send it (using the same key that was used togenerate the challenge ciphertext)…but that will only tell you whether or notdecryption results in an error!

【connect(('128.8.130.16',49101))】

问题翻译

在此分配中,您必须解密使用带有PKCS#5填充的AES inCBC模式生成的质询密文。(注意:从技术上讲,这是PKCS#7填充,因为AES的块大小是16字节。但是填充的方式与PKCS#5填充完全相同。)为此,您将获得访问服务器的权限,该服务器将解密您发送的任何密文(使用用于生成质询密文的同一密钥),但这只会告诉你解密是否会导致错误!

代码

暂无

Question2

问题原文

问题来源:
Crypto Challenge Set 2

问题原文:
This is the first of several sets on block cipher cryptography. This is bread-and-butter crypto, the kind you’ll see implemented in most web software that does crypto.

This set is relatively easy. People that clear set 1 tend to clear set 2 somewhat quickly.

Three of the challenges in this set are extremely valuable in breaking real-world crypto; one allows you to decrypt messages encrypted in the default mode of AES, and the other two allow you to rewrite messages encrypted in the most popular modes of AES.

  1. Implement PKCS#7 padding

A block cipher transforms a fixed-sized block (usually 8 or 16 bytes) of plaintext into ciphertext. But we almost never want to transform a single block; we encrypt irregularly-sized messages.

One way we account for irregularly-sized messages is by padding, creating a plaintext that is an even multiple of the blocksize. The most popular padding scheme is called PKCS#7.

So: pad any block to a specific block length, by appending the number of bytes of padding to the end of the block. For instance,

"YELLOW SUBMARINE"

… padded to 20 bytes would be:

"YELLOW SUBMARINE\x04\x04\x04\x04"
  1. Implement CBC mode

CBC mode is a block cipher mode that allows us to encrypt irregularly-sized messages, despite the fact that a block cipher natively only transforms individual blocks.

In CBC mode, each ciphertext block is added to the next plaintext block before the next call to the cipher core.

The first plaintext block, which has no associated previous ciphertext block, is added to a “fake 0th ciphertext block” called the initialization vector, or IV.

Implement CBC mode by hand by taking the ECB function you wrote earlier, making it encrypt instead of decrypt (verify this by decrypting whatever you encrypt to test), and using your XOR function from the previous exercise to combine them.

The file here is intelligible (somewhat) when CBC decrypted against “YELLOW SUBMARINE” with an IV of all ASCII 0 (\x00\x00\x00 &c)

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
  1. An ECB/CBC detection oracle

Now that you have ECB and CBC working:

Write a function to generate a random AES key; that’s just 16 random bytes.

Write a function that encrypts data under an unknown key — that is, a function that generates a random key and encrypts under it.

The function should look like:

encryption_oracle(your-input)
=> [MEANINGLESS JIBBER JABBER]

Under the hood, have the function append 5-10 bytes (count chosen randomly) before the plaintext and 5-10 bytes after the plaintext.

Now, have the function choose to encrypt under ECB 1/2 the time, and under CBC the other half (just use random IVs each time for CBC). Use rand(2) to decide which to use.

Detect the block cipher mode the function is using each time. You should end up with a piece of code that, pointed at a block box that might be encrypting ECB or CBC, tells you which one is happening.

  1. Byte-at-a-time ECB decryption (Simple)

Copy your oracle function to a new function that encrypts buffers under ECB mode using a consistent but unknown key (for instance, assign a single random key, once, to a global variable).

Now take that same function and have it append to the plaintext, BEFORE ENCRYPTING, the following string:

Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg
aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq
dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg
YnkK

Base64 decode the string before appending it. Do not base64 decode the string by hand; make your code do it. The point is that you don’t know its contents.

What you have now is a function that produces:

AES-128-ECB(your-string || unknown-string, random-key)

It turns out: you can decrypt “unknown-string” with repeated calls to the oracle function!

Here’s roughly how:

  1. Feed identical bytes of your-string to the function 1 at a time — start with 1 byte (“A”), then “AA”, then “AAA” and so on. Discover the block size of the cipher. You know it, but do this step anyway.
  2. Detect that the function is using ECB. You already know, but do this step anyways.
  3. Knowing the block size, craft an input block that is exactly 1 byte short (for instance, if the block size is 8 bytes, make “AAAAAAA”). Think about what the oracle function is going to put in that last byte position.
  4. Make a dictionary of every possible last byte by feeding different strings to the oracle; for instance, “AAAAAAAA”, “AAAAAAAB”, “AAAAAAAC”, remembering the first block of each invocation.
  5. Match the output of the one-byte-short input to one of the entries in your dictionary. You’ve now discovered the first byte of unknown-string.
  6. Repeat for the next byte.

This is the first challenge we’ve given you whose solution will break real crypto. Lots of people know that when you encrypt something in ECB mode, you can see penguins through it. Not so many of them can decrypt the contents of those ciphertexts, and now you can. If our experience is any guideline, this attack will get you code execution in security tests about once a year.

  1. ECB cut-and-paste

Write a k=v parsing routine, as if for a structured cookie. The routine should take:

foo=bar&baz=qux&zap=zazzle

… and produce:

{
  foo: 'bar',
  baz: 'qux',
  zap: 'zazzle'
}

(you know, the object; I don’t care if you convert it to JSON).

Now write a function that encodes a user profile in that format, given an email address. You should have something like:

profile_for("foo@bar.com")

… and it should produce:

{
  email: 'foo@bar.com',
  uid: 10,
  role: 'user'
}

… encoded as:

email=foo@bar.com&uid=10&role=user

Your “profile_for” function should not allow encoding metacharacters (& and =). Eat them, quote them, whatever you want to do, but don’t let people set their email address to “foo@bar.com&role=admin”.

Now, two more easy functions. Generate a random AES key, then:

A. Encrypt the encoded user profile under the key; “provide” that to the “attacker”.
B. Decrypt the encoded user profile and parse it.
Using only the user input to profile_for() (as an oracle to generate “valid” ciphertexts) and the ciphertexts themselves, make a role=admin profile.

  1. Byte-at-a-time ECB decryption (Harder)

Take your oracle function from #12. Now generate a random count of random bytes and prepend this string to every plaintext. You are now doing:

AES-128-ECB(random-prefix || attacker-controlled || target-bytes, random-key)

Same goal: decrypt the target-bytes.

  1. PKCS#7 padding validation

Write a function that takes a plaintext, determines if it has valid PKCS#7 padding, and strips the padding off.

The string:

"ICE ICE BABY\x04\x04\x04\x04"

… has valid padding, and produces the result “ICE ICE BABY”.

The string:

"ICE ICE BABY\x05\x05\x05\x05"

… does not have valid padding, nor does:

"ICE ICE BABY\x01\x02\x03\x04"

If you are writing in a language with exceptions, like Python or Ruby, make your function throw an exception on bad padding.

Crypto nerds know where we’re going with this. Bear with us.

  1. CBC bitflipping attacks

Generate a random AES key.

Combine your padding code and CBC code to write two functions.

The first function should take an arbitrary input string, prepend the string:

"comment1=cooking%20MCs;userdata="

… and append the string:

";comment2=%20like%20a%20pound%20of%20bacon"

The function should quote out the “;” and “=” characters.

The function should then pad out the input to the 16-byte AES block length and encrypt it under the random AES key.

The second function should decrypt the string and look for the characters “;admin=true;” (or, equivalently, decrypt, split the string on “;”, convert each resulting string into 2-tuples, and look for the “admin” tuple).

Return true or false based on whether the string exists.

If you’ve written the first function properly, it should not be possible to provide user input to it that will generate the string the second function is looking for. We’ll have to break the crypto to do that.

Instead, modify the ciphertext (without knowledge of the AES key) to accomplish this.

You’re relying on the fact that in CBC mode, a 1-bit error in a ciphertext block:

Completely scrambles the block the error occurs in
Produces the identical 1-bit error(/edit) in the next ciphertext block.

问题翻译

这是关于分组密码的几组密码中的第一组。这是bread-and-butter加密,你会看到在大多数网络软件中实现加密。

这一套相对容易。清除集合1的人倾向于较快地清除集合2。
这组挑战中有三个在破解现实世界密码方面极为重要;一个允许您解密以默认AES模式加密的消息,另两个允许您重写以最流行的AES模式加密的消息。

  1. 实施PKCS#7填充
  2. 实施CBC模式
  3. ECB/CBC检测oracle
  4. 每次字节ECB解密(简单)
  5. 欧洲央行剪贴
  6. 每次字节ECB解密(更难)
  7. PKCS#7填充验证
  8. CBC翻转攻击

代码

  1. 每次字节ECB解密(更难)
def detect_prefix_length():
    """Detects the length of the prefix used in the oracle

    Returns:
        int: the length of the prefix
    """
    block_size = detect_block_size()

    # first find number of integer blocks occupied
    test_case_1 = encryption_oracle(b'a')#prefix+your string + unknown
    test_case_2 = encryption_oracle(b'b')

    length1 = len(test_case_1)
    length2 = len(test_case_2)

    blocks = 0
    min_length = min(length1, length2)#我咋觉得他两个是一样的??
    # if the any of the blocks (starting from the left) are the same,
    # these blocks are occupied by the `PREFIX`
    for i in range(0, min_length, block_size):
        if test_case_1[i:i+block_size] != test_case_2[i:i+block_size]:
            break
        blocks += 1 # the number of the same blocks of cipher

    # now calculate the residual number of bytes and add to total size
    test_input = b''
    length = blocks * block_size
    # if adding an extra `?` does not change the current block of cipher-text
    # we've reached the end of that block, and so,
    # we've found the number of extra characters needed to complete the block with some prefix characters
    for extra in range(block_size):
        test_input += b'?'
        curr = encryption_oracle(test_input)[length: length+block_size]
        next = encryption_oracle(test_input + b'?')[length: length+block_size]
        if curr == next:
            break

    residue = block_size - len(test_input)
    length += residue
    return length


def ecb_decrypt(block_size):
    """decrypts the plaintext (without key) using byte-at-a-time attack (simple)

    Args:
        block_size (int): the `block_size` used by the `encryption_oracle()` for encryption
    """
    # common = lower_cases + upper_cases + space + numbers
    # to optimize brute-force approach
    common = list(range(ord('a'), ord('z'))) + list(range(ord('A'),
                                                          ord('Z'))) + [ord(' ')] + list(range(ord('0'), ord('9')))
    rare = [i for i in range(256) if i not in common]
    possibilities = bytes(common + rare)

    plaintext = b''  # holds the entire plaintext = sum of `found_block`'s
    check_length = block_size

    prefix_len = detect_prefix_length()
    print(f"Calculated Length of Prefix = { prefix_len }")
    check_begin = (prefix_len // block_size) * block_size
    #check_begin = (prefix_len // block_size+1) * block_size
    residue = prefix_len % block_size

    while True:
        # as more characters in the block are found, the number of A's to prepend decreases
        #padding1 = b'A'*(block_size-residue)
        # prepend = b'A' * (block_size - 1 - (len(plaintext) % block_size))
        # prepend = padding1+prepend
        prepend = b'A' * (block_size - 1 -
                          ((len(plaintext)+residue) % block_size))
        actual = encryption_oracle(
            prepend)[check_begin: check_begin+check_length]

        found = False
        for byte in possibilities:
            value = bytes([byte])
            your_string = prepend + plaintext + value
            produced = encryption_oracle(your_string)[
                check_begin: check_begin+check_length]
            if actual == produced:
                plaintext += value
                found = True
                break

        if not found:
            print(f'Possible end of plaintext: No matches found.')
            print(f"Plaintext: \n{ plaintext.decode('ascii') }")
            return

        if (len(plaintext) + residue) % block_size == 0:
            check_length += block_size

  1. PKCS#7填充验证
def valid_padding(paddedMsg, block_size):
    """checks if `paddedMsg` has valid PKCS#7 padding for given `block_size`

    Args:
        paddedMsg (bytes): the padded text
        block_size (int): the block size that is to be obtained by padding

    Returns:
        bool: True, if the padding is valid. False, otherwise. 
    """
    # if the length of the `paddedMsg` is not a multiple of `block_size`
    if len(paddedMsg) % block_size != 0:
        return False

    last_byte = paddedMsg[-1]

    # if the value of the last_byte is greater than or equal to block_size
    if last_byte >= block_size:
        return False

    padValue = bytes([last_byte]) * last_byte
    # if all the padding bytes are not the same
    if paddedMsg[-last_byte:] != padValue:
        return False

    # if, after removing the padding, the remaining characters are not all printable
    if not paddedMsg[:-last_byte].decode('ascii').isprintable():
        return False

    return True


def PKCS7_restore(m):
    return m[:-m[-1]]


def test(m, size):
    try:
        if not valid_padding(m, size):
            raise ValueError
    except ValueError:
        print(f"{m} has invaild PKCS#7 padding.")
        return

    print(f"Padding successfully...")
    print(f"Before padding removal: { m }")
    print(f"After padding removal: { PKCS7_restore(m) }")

  1. 比特翻转攻击
from Crypto.Cipher import AES
from Crypto import Random
import re
prepend = b"comment1=cooking%20MCs;userdata="
append = b";comment2=%20like%20a%20pound%20of%20bacon"  # len==42


def pad(value, size):
    if len(value) % size == 0:
        return value
    padding = size - len(value) % size
    padValue = bytes([padding]) * padding
    return value + padValue


class InvalidPaddingError(Exception):
    """exception class for invalid PKCS#7 padding

    Args:
        Exception (class): inherits from the in-built `Exception` class
    """

    def __init__(self, paddedMsg, message="has invalid PKCS#7 padding."):
        self.paddedMsg = paddedMsg
        self.message = message
        super().__init__(self.message)

    def __repr__(self):
        return f"{ self.paddedMsg } { self.message }"


def valid_padding(paddedMsg, block_size):
    # if the length of the `paddedMsg` is not a multiple of `block_size`
    if len(paddedMsg) % block_size != 0:
        return False

    last_byte = paddedMsg[-1]

    # if the value of the last_byte is greater than or equal to block_size
    if last_byte >= block_size:
        return False

    padValue = bytes([last_byte]) * last_byte
    # if all the padding bytes are not the same
    if paddedMsg[-last_byte:] != padValue:
        return False

    # if, after removing the padding, the remaining characters are not all printable
    if not paddedMsg[:-last_byte].decode('ascii').isprintable():
        return False

    return True


def remove_padding(paddedMsg, block_size):
    """removes padding from `paddedMsg`, displays error-message if padding is invalid

    Args:
        paddedMsg (bytes): the message that is padded using PKCS#7 padding
        block_size (int): the block size that is obtained by said padding

    Raises:
        InvalidPaddingError: if the padding is invalid

    Returns: 
        (byte): the message after removal of padding, if valid.
    """
    if not valid_padding(paddedMsg, block_size):
        raise InvalidPaddingError

    last_byte = paddedMsg[-1]
    unpadded = paddedMsg[:-last_byte]
    return unpadded


# this is the dictionary for replacements
QUOTE = {b';': b'%3B', b'=': b'%3D'}

KEY = Random.new().read(AES.block_size)
IV = bytes(AES.block_size)  # for simplicity just a bunch of 0's


def cbc_encrypt(input_text):
    """encrypts a the `input_text` using AES-128 in CBC mode,
    aftr replacing `:` with `%3B` and `=` with `%3D` in the `input_text`

    Args:
        input_text (byte): the input to encrypt

    Returns:
        byte: result of AES-128-CBC(prefix+input_text+suffix)
    """

    for key in QUOTE:
        input_text = re.sub(key, QUOTE[key], input_text)

    plaintext = prepend + input_text + append
    plaintext = pad(plaintext, AES.block_size)

    cipher = AES.new(KEY, AES.MODE_CBC, IV)
    ciphertext = cipher.encrypt(plaintext)

    return ciphertext


def check(ciphertext):
    """checks if the `ciphertext` upon decryption has `;admin=true;` in it

    Args:
        ciphertext (bytes): the result of an AES-128-CBC encryption

    Returns:
        bool: True if the plain-text contains `;admin=true;`, False otherwise
    """

    cipher = AES.new(KEY, AES.MODE_CBC, IV)
    plaintext = cipher.decrypt(ciphertext)
    print(f"Plaintext: { plaintext }")

    if b";admin=true;" in plaintext:
        return True

    return False


def test():
    """tests the injection of `;admin=true;` into the cipher-text
    """

    # send two blocks of just A's
    input_string = b'A' * AES.block_size * 2
    print(AES.block_size)  # 16
    ciphertext = cbc_encrypt(input_string)
    print(len(ciphertext))  # 112
    # replace first block of A's with the `required` plain-text
    required = pad(b";admin=true;", AES.block_size)
    # xor each byte of the required with each byte of second block i.e, with 'A'
    inject = bytes([r ^ ord('A') for r in required])  # one block of input
    print(len(inject))  # 16
    # extra = length of ciphertext - length of injected text - length of prefix
    # = one block of input + suffix
    extra = len(ciphertext) - len(inject) - len(prepend)
    # print(extra)
    # keep `inject` fill either side with 0's to match length with original ciphertext
    # xor with 0 does not change value
    # this replaces the first block of input with `required` while the rest is unchanged
    # 0*len(prefix)+infect(A^AES(A)^target)+0*len(suffix+padding)
    inject = bytes(2 * AES.block_size) + inject + bytes(extra)

    # to craft cipher-text, xor the `inject` bytes with
    # corresponding byte of the ciphertext
    crafted = bytes([x ^ y for x, y in zip(ciphertext, inject)])

    if check(crafted):
        print("Admin Found")
    else:
        print("Admin Not Found")
if __name__ == "__main__":
    test()

Question3

问题原文

题目来源:
AES key – encoded in the machine readable zone of a European ePassport.

题目原文:
An AES encrypted message has been forwarded to you. Additionally, you have received the corresponding key - unfortunately not quite complete - in a form like a machine readable zone on an identity document as it is used e.g. with ePassports in Europe.

An AES encrypted message has been forwarded to you (CBC mode with zero initialization vector and 01-00 padding). Additionally, you have received the corresponding key - unfortunately not quite complete - in a form like a machine readable zone (MRZ) on an identity document as it is used e.g. with ePassports in Europe.

在这里插入图片描述
It is the objective to find the plaintext of the following base64-encoded message.

9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI

For encryption a key KENC based on the Basic Access Control(BAC) protocol has been generated and applied. For decryption the following characters have been transmitted from which KENC can be derived (The kind of coding of these characters is described in [1]):
12345678<8<<<1110182<111116?<<<<<<<<<<<<<<<4

Unfortunately, during transmission a character was lost and has been highlighted with a“?”. Nevertheless, you can make it visible again with the help of [2]. To be able to compute the key KENC afterwards you can find an overview of the applied encoding protocols in [3], [4] and an example in [5].

The AES-encrypted message contains a code word that is to be entered as the solution.

Note:You might benefit from CrypTool 1.4.30 for the cryptographic operations. Decode the base64 code before decryption (e.g. in CrypTool 1.4.30 with the function “Base64 Decode”).
References:The following documents are available online at: http://www2.icao.int

[1] ICAO MRTD DOC 9303 Part 1 Vol 1, p. IV-16 (Data structure of the lower machine readable line) and p. IV-42
[2] ICAO MRTD DOC 9303 Part 1 Vol 1, p. IV-24 to IV-26 (Check digits in the machine readable zone)
[3] ICAO MRTD DOC 9303 Part 1 Vol 2, p. IV-13 (MRTD Basic Access Control)
[4] ICAO MRTD DOC 9303 Part 1 Vol 2, p. IV-32
[5] ICAO MRTD DOC 9303 Part 1 Vol 2, p. IV-40 - IV-41

问题翻译

AES加密邮件已转发给您。此外,您还收到了相应的密钥(遗憾的是,该密钥不太完整),其形式类似于身份证件上的机器可读区域,例如在欧洲的ePassports中使用的密钥。

AES加密消息已转发给您(CBC模式,零初始化向量和01-00填充)。此外,您还收到了身份证件上类似机器可读区(MRZ)形式的相应密钥(遗憾的是,该密钥不太完整),因为该密钥用于欧洲的ePassports。

在这里插入图片描述
目标是查找以下base64编码消息的纯文本。

9MGYWMUPRJIECMPX61O6ZIUY3MTIXQQ0E59T3XB6U0GYF1GYS2I3K9JXAA0ZJ4GTMAZJUAPWD6+JDYEI5IGHVHQYDHGULUYTGJRBFDR22FPIL2NFNWFBTXYF7SDI

对于加密,已生成并应用基于基本访问控制(BAC)协议的密钥KENC。为了解密,传输了以下字符,从中可以导出KENC(这些字符的编码类型在[1]中描述):

12345678<8<<<1110182<111116?<<<<<<<<<<<<<<<4

不幸的是,在传输过程中,一个字符丢失,并用“?”突出显示。不过,您可以借助[2]使其再次可见。为了以后能够计算密钥KENC,您可以在[3]、[4]中找到应用编码协议的概述,并在[5]中找到一个示例。

AES加密消息包含一个要作为解决方案输入的码字。

注意:加密操作可能会受益于CrypTool 1.4.30。在解密之前对base64代码进行解码(例如,在CrypTool 1.4.30中使用“base64解码”功能)。

参考资料:以下文件可在以下网址获得:http://www2.icao.int

[1] ICAO MRTD DOC 9303 Part 1 Vol 1, p. IV-16 (Data structure of the lower machine readable line) and p. IV-42
[2] ICAO MRTD DOC 9303 Part 1 Vol 1, p. IV-24 to IV-26 (Check digits in the machine readable zone)
[3] ICAO MRTD DOC 9303 Part 1 Vol 2, p. IV-13 (MRTD Basic Access Control)
[4] ICAO MRTD DOC 9303 Part 1 Vol 2, p. IV-32
[5] ICAO MRTD DOC 9303 Part 1 Vol 2, p. IV-40 - IV-41

问题解答

  1. AES加密模式为CBC,初始化矢量即IV为零,填充为01-00。此外,相应的密钥在身份证件上的机器可读区域(MRZ)等表格中,它与欧洲的电子护照一起使用时并不十分完整。
  2. 目标是找到以下base64编码消息的明文:
    9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI
  3. 对于加密,已生成并应用基于基本访问控制(BAC)协议的密钥KENC。对于解密,已经发送了以下字符,从中可以导出KENC(这些字符的编码类型在[1]中描述):
    12345678 <8 <<< 1110182 <111116?<<<<<<<<<<<<<<< 4
  4. 在传输过程中丢失了并且突出显示了一个“?”。可以在[2]的帮助下恢复它。为了能够在之后计算密钥KENC,可以找到应用编码的概述[3],[4]中的协议和[5]中的一个例子。
  5. 在解密之前解码base64代码。

解题步骤:

  1. 求未知数字
  2. 根据得到的数字计算出key
  3. 拿key和base64解码后的密文解密

代码

a = [1,1,1,1,1,6]
b = [7,3,1,7,3,1]
for i in range(0,6):
    c = c + a[i]*b[i]
    res = c % 10
print (res)
#res = 7
H_information = sha1(information.encode()).hexdigest()
#十进制先变为二进制散列再换成十六进制
K_seed = H_information[:32]# 取前16位
c = '00000001'
#0x00000001
d = K_seed + c
#print(d)
H_d = sha1(codecs.decode(d,"hex")).hexdigest()
#十六进制先变为二进制散列再换成十六进制
#print(H_d)
ka = sha1(codecs.decode(d,"hex")).hexdigest()[:16]
kb = sha1(codecs.decode(d,"hex")).hexdigest()[16:32]
k_1 = jiaoyan(ka)
k_2 = jiaoyan(kb)  
key = k_1 + k_2
print(key)
#ea8645d97ff725a898942aa280c43179
m=AES.new(binascii.unhexlify(key),AES.MODE_CBC,binascii.unhexlify(IV))
print(m.decrypt(cipher))
#b'Herzlichen Glueckwunsch. Sie haben die Nuss geknackt. Das Codewort lautet: Kryptographie!\x01\x00\x00\x00\x00\x00\x00'

#奇偶校验位的判断
def jiaoyan(x):
    k = []
    a = bin(int(x,16))[2:]
    for i in range(0,len(a),8):
        if (a[i:i+7].count("1"))%2 == 0:
            k.append(a[i:i+7])
            k.append('1') 
        else :
            k.append(a[i:i+7])
            k.append('0')      
    a1 = hex(int(''.join(k),2))
    #print("this is " + x + "---" +a1)
    return a1[2:] 
k_1 = jiaoyan(ka)
k_2 = jiaoyan(kb)  
key = k_1 + k_2
print(key)
#ea8645d97ff725a898942aa280c43179
m=AES.new(binascii.unhexlify(key),AES.MODE_CBC,binascii.unhexlify(IV))
print(m.decrypt(cipher))
#b'Herzlichen Glueckwunsch. Sie haben die Nuss geknackt. Das Codewort lautet: Kryptographie!\x01\x00\x00\x00\x00\x00\x00'

#奇偶校验位的判断
def jiaoyan(x):
    k = []
    a = bin(int(x,16))[2:]
    for i in range(0,len(a),8):
        if (a[i:i+7].count("1"))%2 == 0:
            k.append(a[i:i+7])
            k.append('1') 
        else :
            k.append(a[i:i+7])
            k.append('0')      
    a1 = hex(int(''.join(k),2))
    #print("this is " + x + "---" +a1)
    return a1[2:] 

答案

Herzlichen Glueckwunsch. Sie haben die Nuss geknackt. Das Codewort lautet: Kryptographie

### 回答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
发出的红包

打赏作者

不知谢长安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值