习题一:Many Time Pad

题目链接:https://www.coursera.org/learn/crypto/home/week/1

Question:

Let us see what goes wrong when a stream cipher key is used more than once. Below are eleven hex-encoded ciphertexts that are the result of encrypting eleven plaintexts with a stream cipher, all with the same stream cipher key. Your goal is to decrypt the last ciphertext, and submit the secret message within it as solution.

Hint: XOR the ciphertexts together, and consider what happens when a space is XORed with a character in [a-zA-Z].
ciphertext #1:

315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e

ciphertext #2:

234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f

ciphertext #3:

32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb

ciphertext #4:

32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa

ciphertext #5:

3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070

ciphertext #6:

32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4

ciphertext #7:

32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce

ciphertext #8:

315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3

ciphertext #9:

271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027

ciphertext #10:

466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83

target ciphertext (decrypt this one): 

32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904

For completeness, here is the python script used to generate the ciphertexts.(it doesn't matter if you can't read this)

import sysMSGS = ( ---  11 secret messages  --- )def strxor(a, b):     # xor two strings of different lengthsif len(a) > len(b):return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])else:return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])def random(size=16):return open("/dev/urandom").read(size)def encrypt(key, msg):c = strxor(key, msg)printprint c.encode('hex')return cdef main():key = random(1024)ciphertexts = [encrypt(key, msg) for msg in MSGS]

Answer:

由提示,空格space的ASCII码二进制形式为0010 0000,大写字母A~Z的ASCII码二进制形式为01000001~01011010,小写字母a~z的ASCII码二进制形式为 01100001~01111010。

因此可以用space和字母做xor操作,对字母进行大小写切换,而两个字母做xor操作,结果将不在字母范围内。

又由于将两个密文做xor操作相当于将两个密文对应的明文做xor操作,如果结果中某个位置出现字母,则说明这两个明文的其中一个在该位置可能为空格。

故对11个密文分别做两两xor操作,然后通过结果判断不同明文中可能存在空格的位置,然后将对应位置上的密文和space做xor操作,就可得到对应位置的密钥信息,当获取足够多的密钥信息后,即可对目标密文进行解密。

附代码:

import sys  ciphertexts=[
"315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e",
"234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f",
"32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb",
"32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa",
"3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce",
"315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3",
"271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027",
"466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83",
"32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904"
]  NUM_CIPHER=len(ciphertexts)
THRESHOLD_VALUE=6def strxor(a, b): """xor two strings of different lengths"""  if len(a) > len(b):  return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])  else:  return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])   def letter_position(s): """ Return the position of letters in the given string """  position=[]for idx in range(len(s)):  if (s[idx]>='A' and s[idx]<='Z') or (s[idx]>='a' and s[idx]<='z'):  position.append(idx)  return position  def find_space(cipher):"""Find the position of space"""space_position={}space_possible={}  for cipher_idx_1 in range(NUM_CIPHER):  space_xor=[]  for cipher_idx_2 in range(NUM_CIPHER):   plain_xor=strxor(cipher[cipher_idx_1].decode('hex'),cipher[cipher_idx_2].decode('hex'))if cipher_idx_2!=cipher_idx_1:  space_xor.append(letter_position(plain_xor)) # record the possible value of space space_possible[cipher_idx_1]=space_xorfor cipher_idx_1 in range(NUM_CIPHER):  spa=[]  for position in range(100):  count=0 for cipher_idx_2 in range(NUM_CIPHER-1):  if position in space_possible[cipher_idx_1][cipher_idx_2]:  count+=1  if count>THRESHOLD_VALUE: # if possible position value appear more than THRESHOLD_VALUE times,# we consider it as a space positionspa.append(position)space_position[cipher_idx_1]=spa;  return space_positiondef calculate_key(cipher):key=[0]*100space=find_space(cipher)  for cipher_idx_1 in range(NUM_CIPHER):  for position in range(len(space[cipher_idx_1])):  idx=space[cipher_idx_1][position]*2; # ciphertext is hex-encoded, so its scale times twokey[space[cipher_idx_1][position]]=ord((ciphertexts[cipher_idx_1][idx]+ciphertexts[cipher_idx_1][idx+1]).decode('hex'))^ord(' '); #derive key  key_str="";  for k in key:  key_str+=chr(k);return key_str   result="";
key=calculate_key(ciphertexts)
for i in range(11):for letter in strxor(ciphertexts[i].decode('hex'),key): # decrypt the target cipherif (letter>='a' and letter<='z') or (letter>='A' and letter<='Z'):  result+=letter;  elif letter==' ':  result+=letter;  else:  result+='0';print result;print '\n'result=''

习题二:Vigenere-like cipher

Question:

Write a program that allows you to "crack" ciphertexts generated using a Vigenere-like cipher, where byte-wise XOR is used instead of addition modulo 26.

Specifically, the ciphertext

F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794

was generated by encrypting English-language text using the following C program:

#include <stdio.h>
#define KEY_LENGTH 2 // Can be anything from 1 to 13main(){unsigned char ch;FILE *fpIn, *fpOut;int i;unsigned char key[KEY_LENGTH] = {0x00, 0x00};/* of course, I did not use the all-0s key to encrypt */fpIn = fopen("ptext.txt", "r");fpOut = fopen("ctext.txt", "w");i=0;while (fscanf(fpIn, "%c", &ch) != EOF) {/* avoid encrypting newline characters */  /* In a "real-world" implementation of the Vigenere cipher, every ASCII character in the plaintext would be encrypted.However, I want to avoid encrypting newlines here because it makes recovering the plaintext slightly more difficult... *//* ...and my goal is not to create "production-quality" code =) */if (ch!='\n') {fprintf(fpOut, "%02X", ch ^ key[i % KEY_LENGTH]); // ^ is logical XOR    i++;}}fclose(fpIn);fclose(fpOut);return;
} 

(Of course, when encrypting I used a random key length and chose each byte of the key at random.) The plaintext contains upper- and lower-case letters, punctuation, and spaces, but no numbers.

Recovered the original plaintext

Answer:

假设加密者使用的密钥为vigenerekey,长度为keylen,密文为字符串arr

那么字符串subarr0=arr[0]+arr[keylen]+arr[keylen*2]……是被vigenerekey[0]解密的内容

依次类推,subarr1=arr[1]+arr[1+keylen]+arr[1+keylen*2]……是被vigenerekey[1]解密的内容

subarr2=arr[2]+arr[2+keylen]+arr[2+keylen*2]……是被vigenerekey[2]解密的内容

……

按照这种分割方法,可以把密文arr分割成keylen份,每份都被密钥vigenerekey的同一位解密

比如:

密钥为WXYZ,密文为abcdefghijklmnop

那么解密过程为

a b c d e f g h i j k l m n o p
W X Y Z W X Y Z W X Y Z W X Y Z

subarr0=aeim

subarr1=bfjn

以此类推

对每个vigenerekey[index],穷举vigenerekey[index]的值(范围是0x00~0xFF),并与对应的subarr里的内容解码,找到能将该subarr所有内容解为可见字符的所有可能值

附代码:

def findindexkey(subarr):#该函数可以找出将密文subarr解密成可见字符的所有可能值visiable_chars=[]#可见字符for x in range(32,126):visiable_chars.append(chr(x))#print(vi)test_keys=[]#用于测试密钥ans_keys=[]#用于结果的返回for x in range(0x00,0xFF):# 枚举密钥里所有的值test_keys.append(x)ans_keys.append(x)for i in test_keys:#对于0x00~0xFF里的每一个数i和subarr里的每个值s异或for s in subarr:if chr(s^i) not in visiable_chars:#用i解密s,如果解密后明文不是可见字符,说明i不是密钥ans_keys.remove(i)#去掉ans_keys里测试失败的密钥break#print(ans_keys)return ans_keysstrmi='F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923C\
AB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF\
5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84C\
C931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D96\
3FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47E\
FD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5\
923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA\
36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63C\
ED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A8\
5A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250\
C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794'
arr=[]#密文,每个元素为字符的ascii码
for x in range(0,len(strmi),2):arr.append(int(strmi[x:2+x],16))for keylen in range(1,14):#枚举密钥的长度1~14for index in range(0,keylen):#对密钥里的第index个进行测试subarr=arr[index::keylen]#每隔keylen长度提取密文的内容,提取出来的内容都被密文的第index个加密ans_keys=findindexkey(subarr)#找出密钥中第index个的可能的值print('keylen=',keylen,'index=',index,'keys=',ans_keys)if ans_keys:#如果密钥第index个有可能存在,尝试用密钥的index个去解密文ch=[]for x in ans_keys:ch.append(chr(x^subarr[0]))print(ch)

运行结果:

可以看出,keylen=7时有结果

不妨缩小一下范围,假设明文只有字母、数字、空格、逗号和句号,再进行穷举

附代码:

import string
def findindexkey2(subarr):#再造一个函数筛选密钥test_chars=string.ascii_letters+string.digits+','+'.'+' '#将检查的字符改为英文+数字+逗号+句号+空格#print(test_chars)test_keys=[]#用于测试密钥ans_keys=[]#用于结果的返回for x in range(0x00,0xFF):# 枚举密钥里所有的值test_keys.append(x)ans_keys.append(x)for i in test_keys:#对于0x00~0xFF里的每一个数i和substr里的每个值s异或for s in subarr:if chr(s^i) not in test_chars:#用i解密s,如果解密后不是英文、数字、逗号、句号、空格,说明i不是密钥ans_keys.remove(i)#去掉ans_keys里测试失败的密钥break#print(ans_keys)return ans_keysvigenerekeys=[]#维基尼尔密码的密钥
for index in range(0,7):#已经知道密钥长度是7subarr=arr[index::7]vigenerekeys.append(findindexkey2(subarr))
print(vigenerekeys)

运行结果:

[[186], [31], [145], [178], [83], [205], [62]]

结果已经是唯一的了,它就是密钥,我们再使用这个密钥去解密密文

附代码:

ming=''
for i in range(0,len(arr)):ming=ming+chr(arr[i]^vigenerekeys[i%7][0])
print(ming)

解密结果:

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.

注:此解法为穷举,算是非预期解法,关于字母频率分析解法后面会发布,请关注

附完整代码:

def findindexkey(subarr):#该函数可以找出将密文subarr解密成可见字符的所有可能值visiable_chars=[]#可见字符for x in range(32,126):visiable_chars.append(chr(x))#print(vi)test_keys=[]#用于测试密钥ans_keys=[]#用于结果的返回for x in range(0x00,0xFF):# 枚举密钥里所有的值test_keys.append(x)ans_keys.append(x)for i in test_keys:#对于0x00~0xFF里的每一个数i和subarr里的每个值s异或for s in subarr:if chr(s^i) not in visiable_chars:#用i解密s,如果解密后明文不是可见字符,说明i不是密钥ans_keys.remove(i)#去掉ans_keys里测试失败的密钥break#print(ans_keys)return ans_keysstrmi='F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923C\
AB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF\
5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84C\
C931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D96\
3FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47E\
FD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5\
923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA\
36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63C\
ED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A8\
5A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250\
C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794'
arr=[]#密文,每个元素为字符的ascii码
for x in range(0,len(strmi),2):arr.append(int(strmi[x:2+x],16))for keylen in range(1,14):#枚举密钥的长度1~14for index in range(0,keylen):#对密钥里的第index个进行测试subarr=arr[index::keylen]#每隔keylen长度提取密文的内容,提取出来的内容都被密文的第index个加密ans_keys=findindexkey(subarr)#找出密钥中第index个的可能的值print('keylen=',keylen,'index=',index,'keys=',ans_keys)if ans_keys:#如果密钥第index个有可能存在,尝试用密钥的index个去解密文ch=[]for x in ans_keys:ch.append(chr(x^subarr[0]))print(ch)
#运行到这里,观察输出可以发现,密钥长度为7时有解
print('###############')
import string
def findindexkey2(subarr):#再造一个函数筛选密钥test_chars=string.ascii_letters+string.digits+','+'.'+' '#将检查的字符改为英文+数字+逗号+句号+空格#print(test_chars)test_keys=[]#用于测试密钥ans_keys=[]#用于结果的返回for x in range(0x00,0xFF):# 枚举密钥里所有的值test_keys.append(x)ans_keys.append(x)for i in test_keys:#对于0x00~0xFF里的每一个数i和substr里的每个值s异或for s in subarr:if chr(s^i) not in test_chars:#用i解密s,如果解密后不是英文、数字、逗号、句号、空格,说明i不是密钥ans_keys.remove(i)#去掉ans_keys里测试失败的密钥break#print(ans_keys)return ans_keysvigenerekeys=[]#维基尼尔密码的密钥
for index in range(0,7):#已经知道密钥长度是7subarr=arr[index::7]vigenerekeys.append(findindexkey2(subarr))
print(vigenerekeys)#输出的是[[186], [31], [145], [178], [83], [205], [62]].print("#########")
ming=''
for i in range(0,len(arr)):ming=ming+chr(arr[i]^vigenerekeys[i%7][0])
print(ming)

习题三:Cryptopals Set 1

题目链接:http://www.cryptopals.com/sets/1

Question:

(1) Convert hex to base64

(2) Fixed XOR

(3) Single-byte XOR cipher

(4) Detect single-character XOR

(5) Implement repeating-key XOR

(6) Break repeating-key XOR

Answer:

(1)

import base64
str1="49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d".decode("hex")
m = base64.b64encode(str1)
print m

(2)

import base64
import re
str1="1c0111001f010100061a024b53535009181c".decode('hex')
str2="686974207468652062756c6c277320657965".decode('hex')
str3=[]
for i in range(0,len(str1)):str3+=[chr(ord(str1[i])^ord(str2[i]))]
str3="".join(str3)
print str3.encode('hex')

(3)

import re
str="1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736"
score=0
for i in range(0,129):tmp=[]for j in re.findall(".{2}",str):tmp += chr(i^int(j,16))tmpstr = "".join(tmp)num=0for j in range(0,len(tmpstr)):if tmpstr[j]>='a'and tmpstr[j]<='z':num+=1if num>score:score=numansstr=tmpstrkey=chr(i)
print key
print ansstr

(4)

import re
wenben=[]
for i in open("ex4.txt","r").readlines():wenben+=[i.replace("\n","")]
score=0
for k in wenben:for i in range(0,129):tmp=[]for j in re.findall(".{2}",k):tmp += chr(i^int(j,16))tmpstr = "".join(tmp)num=0num=len(re.findall(r'[a-zA-Z ]',tmpstr))if num>score:score=numansstr=tmpstrc=kkey=chr(i)
print c
print key
print ansstr

(5)

import re
str1="Burning 'em, if you ain't quick and nimble I go crazy when I hear a cymbal"
str2="ICE"*200
str3=[]
for i in range(0,len(str1)):str3 +=[(chr(ord(str1[i])^ord(str2[i])))]
print "".join(str3).encode('hex')

(6)

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 = 0freqs = {'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=0for i in range(0,len(x)):t=ord(x[i])^ord(y[i])while t:if t&1 : num+=1t>>=1return num
def thechar(st1):score = 0for 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 keyans = []
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))/ix2=float(hanming(str2,str3))/ix3=float(hanming(str3,str4))/ix4=float(hanming(str1,str4))/ix5=float(hanming(str1,str3))/ix6=float(hanming(str2,str4))/iaa=(x1+x2+x3+x4+x5+x6)/6ans+=[(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*10000wenben=wenben.decode('hex')
an=[]
for i in range(0,len(wenben)):an+=[chr(ord(wenben[i])^ord(keyy[i]))]
an="".join(an)
print an

习题四:MTC3 Cracking SHA1-Hashed Passwords

题目链接:https://www.mysterytwisterc3.org/en/challenges/level-2/cracking-sha1-hashed-passwords

Question:

The Secure Hash Algorithmus 1 has been standardized by the National Institute of Standards and Technology in 1995 and is besides MD5 the most commonly used hash algorithm in practice. An example for its usage is password-based authentification. In that case, the server does not store the user password in plain text but instead the SHA1 hash value of it. Once the user enters his password and after its received at the server, its hash value is computed and compared to the value stored on the server in order to verify its correctness.

A vulnerability of a surveillance system’s webserver leaked the SHA1 hash value of the password of the administrator account. The password’s hash value is

67ae1a64661ac8b4494666f58c4822408dd0a3e4

Furthermore, the keyboard of the login terminal shows clear signs of the entered password since after a successful login navigation in the software is only done via arrow keys. What is the password?

Remark: Note the German keyboard layout!

Answer:

根据键盘上的按键分布,可以看出右边的数字键只有2486,很有可能是当做上下左右的功能,然后对剩余的按照每个按键出现1次进行暴力,可得出解。

由于需要在10s之内求解,而python遍历全部密钥空间需要15s,而根据遍历的原理,我们只要选出使最外层的循环正确的字母,就可以缩短一半的时间,因此若求解时间不符合要求,将最外层的求解顺序变换一下即可。

附代码:

import re
from Crypto.Hash import SHA
import hashlib
import itertools
import datetime
starttime = datetime.datetime.now()
hash1="67ae1a64661ac8b4494666f58c4822408dd0a3e4"
str1="QqWw%58(=0Ii*+nN"
str2=[['Q', 'q'],[ 'W', 'w'],[ '%', '5'], ['8', '('],[ '=', '0'], ['I', 'i'], ['*', '+'], ['n', 'N']]
def sha_encrypt(str):sha = hashlib.sha1(str)encrypts = sha.hexdigest()return encrypts
st3="0"*8
str4=""
str3=list(st3)
for a in range(0,2):str3[0]=str2[0][a]for b in range(0,2):str3[1]=str2[1][b]for c in range(0,2):str3[2]=str2[2][c]for d in range(0,2):str3[3] = str2[3][d]for e in range(0,2):str3[4] = str2[4][e]for f in range(0,2):str3[5] = str2[5][f]for g in range(0,2):str3[6] = str2[6][g]for h in range(0,2):str3[7] = str2[7][h]newS="".join(str3)for i in itertools.permutations(newS, 8):str4 = sha_encrypt("".join(i))if str4==hash1:print "".join(i)endtime = datetime.datetime.now()print (endtime - starttime).secondsexit(0)

现代密码学(Cryptography)经典习题及解法(一)相关推荐

  1. 数据结构经典习题【part2】

    一些数据结构经典习题 part 2 链表 1.给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 . struct ...

  2. 已知长短轴求椭圆上任意一点的坐标_高中数学必修2:平面解析几何——椭圆(经典习题)...

    今天接着给大家分享关于高中数学必修2平面解析几何中椭圆知识点讲解,从三个方面进行讲解:基础梳理.要点整理.经典高考习题解题过程及答案. 一.基础梳理 1.椭圆的定义 2.椭圆的标准方程和几何性质 要点 ...

  3. 新颖的c语言题目,新颖版c语言经典习题100例(全面面)

    新颖版c语言经典习题100例(全面面) (66页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 实用文档C语言习题100例(最新整理版) ...

  4. c语言全面,最新版c语言经典习题100例(最全面).doc

    最新版c语言经典习题100例(最全面).doc C语言习题100例(最新整理版) 习题目录:(按住Ctrl点击可以快速跳转到对应页面) TOC \o "1-3" \h \z \u ...

  5. 算法竞赛入门经典 习题3-2 分子量 Molar Mass

    给出一种物质的分子式(不带括号),求其分子量.本题分子式中只包含四种原子,分别为C.H.O.N,原子量分别为12.01,1.008,16.00,14.01.例如,C6H5OH的分子量为94.108g/ ...

  6. oracle经典习题(一)

    oracle经典习题(一) 1.显示与BLAKE在同一部门工作的雇员的姓名.工作和入职日期,但是BLAKE不包含在内 1.1 示例sql语句 SELECT ename,job,hiredate FRO ...

  7. oralce 经典习题系列-查询

    oralce 经典习题系列 数据库数据类型 The problem 1在已经创建的employee表中进行如下操作: (1)计算所有女员工('F')的工龄. (2)使用ROWNUM查询从第3条记录开始 ...

  8. 韩信点兵(hanxin)--算法竞赛经典习题2-2:相传韩信才智过人,从不清点自己军队的人数,只要让士兵先后以三人一排、五人一排、七人一排地变换队形,他每次只要掠一眼队伍的排尾就知道总数(C++实现)

    韩信点兵(hanxin)–算法竞赛经典习题2-2:相传韩信才智过人,从不清点自己军队的人数,只要让士兵先后以三人一排.五人一排.七人一排地变换队形,他每次只要掠一眼队伍的排尾就知道总数. (C++实现 ...

  9. 解析java多态经典习题

    解析java多态经典习题 1 题目一 1.1 题目内容 编写程序实现乐手弹奏乐器.乐手可以弹奏不同的乐器从 而发出不同的声音. 可以弹奏的乐器包括二胡.钢琴和琵琶. 实现思路及关键代码: ①定义乐器类 ...

最新文章

  1. 独家 | 利用Omniverse Code应用开展虚拟宇宙的未来
  2. SimpleDateFormat的线程安全问题
  3. ASP.NET中利用DataList实现图片无缝滚动
  4. NoSQL之Redis非关系数据库(redis概述,持久化,RDB持久化,AOF持久,内存碎片)
  5. vue项目中如何引入ElementUI
  6. 软件工程师安德烈·梅萨加冕 2021 世界小姐冠军
  7. 理解 Redux 的最好方式,是自己写一个
  8. Nopi的学习笔记(C#篇)
  9. PyCharm搜索技巧快捷键
  10. 【图片编辑小软件, 在线文件转换器】FastStone Photo Resizer支持批量转换和批量重命名;免费快速在线转换器, 将pdf, 图像, 视频, 文档, 音频, 电子书及压缩等格式相互转换
  11. 分享两个在线制图网站
  12. LocalDateTime和时间戳互转
  13. 渗透测试之后台查找,如何查找网站后台
  14. 手游《六大门派》 武侠MMORPG手机游戏全套源码下载
  15. Spring事务问题
  16. python全栈开发什么意思_Python是什么?老男孩python全栈开发
  17. 【设cache的容量为214块,每块是一个32位字,主存容量是cache容量的256倍,其中有如表4.11所示数据(地址和数据均采用十六进制表示)】
  18. 设置Notes客户端收发Internet邮件
  19. 开发者所需要知道的iOS7 SDK新特性
  20. 第一部分 思科九年 一(11)

热门文章

  1. kotlin入门!关于Flutter文本组件Widget的全面解读,醍醐灌顶!
  2. Jetson Xavier NX 学习(三)安装输入法和 jtop
  3. gif动图快速制作方法(附工具)(转)
  4. 用cookie显示上次登录时间
  5. Vue实现一个简单的登录页面【自定义】
  6. codeforces613B - Skills 金中市队儿童节常数赛
  7. 3d max 网络渲染
  8. php访问腾讯云cos,腾讯云COS的一次实践
  9. python队列实例
  10. windows下zlog输出日志长度只能在1024下解决方法