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.
- 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"
- 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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
- 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.
- 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:
- 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.
- Detect that the function is using ECB. You already know, but do this step anyways.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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模式加密的消息。
- 实施PKCS#7填充
- 实施CBC模式
- ECB/CBC检测oracle
- 每次字节ECB解密(简单)
- 欧洲央行剪贴
- 每次字节ECB解密(更难)
- PKCS#7填充验证
- CBC翻转攻击
代码
- 每次字节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
- 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) }")
- 比特翻转攻击
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
问题解答
- AES加密模式为CBC,初始化矢量即IV为零,填充为01-00。此外,相应的密钥在身份证件上的机器可读区域(MRZ)等表格中,它与欧洲的电子护照一起使用时并不十分完整。
- 目标是找到以下base64编码消息的明文:
9MgYwmuPrjiecPMx61O6zIuy3MtIXQQ0E59T3xB6u0Gyf1gYs2i3K9Jxaa0zj4gTMazJuApwd6+jdyeI5iGHvhQyDHGVlAuYTgJrbFDrfB22Fpil2NfNnWFBTXyf7SDI - 对于加密,已生成并应用基于基本访问控制(BAC)协议的密钥KENC。对于解密,已经发送了以下字符,从中可以导出KENC(这些字符的编码类型在[1]中描述):
12345678 <8 <<< 1110182 <111116?<<<<<<<<<<<<<<< 4 - 在传输过程中丢失了并且突出显示了一个“?”。可以在[2]的帮助下恢复它。为了能够在之后计算密钥KENC,可以找到应用编码的概述[3],[4]中的协议和[5]中的一个例子。
- 在解密之前解码base64代码。
解题步骤:
- 求未知数字
- 根据得到的数字计算出key
- 拿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