def VigenereEncrypto(inputt, key):
ptlen = len(inputt)
keylen = len(key)
quotient = ptlen // keylen # 商
remainder = ptlen % keylen # 余
out=''
for i in range(0,quotient):#几轮,每轮的长度为keylen
for j in range(0,keylen):#每一轮
c=int((ord(inputt[i*keylen+j])-ord('a')+ord(key[j]) - ord('a'))%26+ord('a'))
out+=chr(c)
for i in range(0,remainder):
c=int((ord(inputt[i+keylen*quotient])-ord('a')+ord(key[j]) - ord('a'))%26+ord('a'))
out+=chr(c)
return out
def VigenereDecrypto (output , key) :
ptlen = len(output)
keylen = len(key)
quotient = ptlen // keylen # 商
remainder = ptlen % keylen # 余
inp=''
for i in range(0, quotient): # 几轮,每轮的长度为keylen
for j in range(0, keylen): # 每一轮
c = int((ord(input[i * keylen + j]) - ord('a') - (ord(key[j]) - ord('a'))) % 26 + ord('a'))
inp += chr(c)
for i in range(0, remainder):
c = int((ord(input[i + keylen * quotient]) - ord('a') - (ord(key[j]) - ord('a'))) % 26 + ord('a'))
inp += chr(c)
return inp
##尝试用词频分析写了一下午,还没做出来 捂脸
from string import ascii_letters, digits
# find_index_key: 确定key中index部分ascii码
# sub_arr: 当key_len和index确定时,使用key中同一位加密的子串
# 返回该子串可能使用的所有可见字符
def find_index_key(sub_arr): # sub_arr是同一个ki的分组
# all_ch = printable
all_key = ascii_letters + digits + ',' + '.' + ' '
test_key = []
possible_key = []
# 遍历整个ascii码(0-127)
for x in range(0x00, 0xFF):
test_key.append(x)
possible_key.append(x)
# 如果子串中所有位置都可以被ch异或为可见字符,则该ch可能为key的一部分
for i in test_key:
for j in sub_arr:
if chr(i ^ j) not in all_key:
possible_key.remove(i)
break
return possible_key
s = "F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794"
ct = bytes.fromhex(s)#有很多不可打印的
# 遍历keylen和index的所有情况
for key_len in range(1, 30):
for index in range(key_len):
sub_arr = ct[index::key_len] # 分组
possible_ch = find_index_key(sub_arr)
print('key_len = ', key_len, 'index = ', index, 'possible_ch = ', possible_ch)
# 遍历所有可能的字符,解密ct中第一个长度为key_len的部分
if possible_ch:
k = []
for j in possible_ch:
k.append(chr(j ^ sub_arr[0]))
print(k)
# decryption
key = [186, 31, 145, 178, 83, 205, 62]
pt = ""
for i in range(len(ct)):
pt += chr(ct[i] ^ key[i % 7])
print(pt)
思路:
假设空格来自ciphertext_a
,其他密文对应ciphertext_b:
for ciphertext_a in ciphertexts:
space_suspect_counts = [0] * len(ciphertext_a)
for ciphertext_b in ciphertexts:
#如果遇到自己,跳过,不和自己做异或
if ciphertext_a == ciphertext_b:
continue
两两异或(这样可以进行多次统计,体现在 对空格可能在的位置进行计数,max=10,若大于8,就确定他是空格),得到空格可能的位置。
如何得到key: (这里其实是假设了key都是可见字符)空格再与ciphertext_a对应位置异或,得到初步确定的key
初步确定的key再与其他密文异或,如果满足全部是在字母范围内,再添加进key值
这样其实得到11组key
import binascii
ciphertexts = [
"315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e",
"234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f",
"32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb",
"32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa",
"3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4",
"32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce",
"315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3",
"271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027",
"466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83",
"32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904",
]
#转换为16进制数字
ciphertexts = [binascii.unhexlify(x) for x in ciphertexts]
#print(ciphertexts)
target_ciphertext = ciphertexts[-1]
suspect_num=[]
#进行异或,zip函数将长的字符串截取到和短的字符串相同的长度
#res直接和最短的同,不会循环加密
def strxor(a, b):
return "".join([chr(x ^ y) for x, y in zip(a, b)])
def repeat_key_xor(m,key):
output_bytes=b''
index=0
for byte in m:#直接就是对应的ASCII
#print(byte)
#print(key[index])
output_bytes+=bytes([byte^key[index]])
#bytes[116,112]转为b'tp'
if(index+1)==len(key):
index=0
else:
index+=1
return output_bytes
key = [0] * 1000
max_space_count=[0]*1000
#开始做异或,有c1⊕c2=m1⊕k⊕m2⊕k=m1⊕m2
for ciphertext_a in ciphertexts:
space_suspect_counts = [0] * len(ciphertext_a)
for ciphertext_b in ciphertexts:
#如果遇到自己,跳过,不和自己做异或
if ciphertext_a == ciphertext_b:
continue
#开始两两异或
a_xor_b = strxor(ciphertext_a, ciphertext_b)
for char_idx, xor_resulting_char in enumerate(a_xor_b):
#一个大写字母与空格异或,结果为其对应的小写字母;一个小写字母与空格异或,结果为其对应的大写字母。
ascii_null = "\x00"
#isaplha()函数:判断字符串中是否是字母
if xor_resulting_char.isalpha() or xor_resulting_char == ascii_null:
#获得可能的空格位置,统计这个位置和其他字符串异或出现字母的次数
space_suspect_counts[char_idx] += 1
#开始假设空格位置来自于ciphertext_a,如果统计的某个位置上满足要求的次数大于等于我所期望的次数,
#那么我们假设这个位置上就是空格且来自与ciphertext_a中对应的位置
#space_tolerance_threshold = 0.8
for char_idx, suspect_count in enumerate(space_suspect_counts):
#判断出现的次数是否满足要求
if suspect_count >= max_space_count[char_idx]:
#通过判断得知密文这个位置上大概率是space,所以,此时 m=space,所以 c⊕space=m⊕k⊕space=k,从而可以求的key值
whitespace = ord(" ")
suspect_key=ciphertext_a[char_idx] ^ whitespace
#增加判断,将 key再与其他密文对应位置异或,如果满足全部是在字母范围内,再添加进key值。
#等于说又判断了一次???
for ciphertext_b in ciphertexts:
if char_idx<len(ciphertext_b):
if(0x41<=ciphertext_b[char_idx]^suspect_key<=0x7A):
max_space_count[char_idx] = suspect_count
key[char_idx]=suspect_key
#print("".join(chr(i)for i in key))
print(len(key))
print(len(ciphertexts[0]))
i=0
target_plaintext=[0]*11
for ciphertext_c in ciphertexts:
# print(len(key)==len(ciphertext_c)) false
target_plaintext[i]= strxor(ciphertext_c,key)
#print("".join(chr(i)for i in key))
print(f"明文{i}:{target_plaintext[i]}")
print(len(target_plaintext[i])==len(ciphertexts[i]))
i+=1
m10=b'The secret message is: When using a stream cipher, never use the key more than once'
key=repeat_key_xor(m10,ciphertexts[10])
#print(len(key)==len(m10))
print(key)
print(bytes([b1^b2 for b1,b2 in zip(m10,ciphertexts[10])]).hex())##key的十六进制表示
print(repeat_key_xor(ciphertexts[7],key))#第八组明文
# key1=strxor(ciphertexts[10],m10)
# print(f"key为:{key1}")
# print(bytes(key1),encoding='utf8')
# print(len(bytes(key1)))
# print(strxor(bytes(key1),ciphertexts[7]))
# print(len(strxor(bytes(key1),ciphertexts[7])))
import codecs
hex = "49276d206b696c6c696e6720796f757220627261
696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"
b64 = codecs.encode(codecs.decode(hex, 'hex'), 'base64').decode()
print(b64)
x1='1c0111001f010100061a024b53535009181c'
x2='686974207468652062756c6c277320657965'
x1 = bytes.fromhex(x1)
#print(x1)b'\x1c\x01\x11\x00\x1f\x01\x01\x00\x06\x1a\x02KSSP\t\x18\x1c'
x2 = bytes.fromhex(x2)
#print(x2)b"hit the bull's eye"
res=bytes([b1^b2 for b1,b2 in zip(x1,x2)])
#print(res)b"the kid don't play"
print(res.hex())
def get_english_score(input_bytes):
"""Compares each input byte to a character frequency
chart and returns the score of a message based on the
relative frequency the characters occur in the English
language
"""
# From https://en.wikipedia.org/wiki/Letter_frequency
# with the exception of ' ', which I estimated.
character_frequencies = {
'a': .08167, 'b': .01492, 'c': .02782, 'd': .04253,
'e': .12702, 'f': .02228, 'g': .02015, 'h': .06094,
'i': .06094, 'j': .00153, 'k': .00772, 'l': .04025,
'm': .02406, 'n': .06749, 'o': .07507, 'p': .01929,
'q': .00095, 'r': .05987, 's': .06327, 't': .09056,
'u': .02758, 'v': .00978, 'w': .02360, 'x': .00150,
'y': .01974, 'z': .00074, ' ': .13000
}
return sum([character_frequencies.get(chr(byte), 0) for byte in input_bytes.lower()])
def single_char_xor(input_bytes, char_value):
"""Returns the result of each byte being XOR'd with a single value.
"""
output_bytes = b''
for byte in input_bytes:
output_bytes += bytes([byte ^ char_value])
return output_bytes
hexstring = '1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736'
ciphertext = bytes.fromhex(hexstring)
potential_messages = []
for key_value in range(256):
message = single_char_xor(ciphertext, key_value)
score = get_english_score(message)
data = {
'message': message,
'score': score,
'key': key_value
}
potential_messages.append(data)
best_score = sorted(potential_messages, key=lambda x: x['score'], reverse=True)[0]
for item in best_score:
print("{}: {}".format(item.title(), best_score[item]))
def get_english_score(input_bytes):
"""Compares each input byte to a character frequency
chart and returns the score of a message based on the
relative frequency the characters occur in the English
language.
"""
# From https://en.wikipedia.org/wiki/Letter_frequency
# with the exception of ' ', which I estimated.
character_frequencies = {
'a': .08167, 'b': .01492, 'c': .02782, 'd': .04253,
'e': .12702, 'f': .02228, 'g': .02015, 'h': .06094,
'i': .06094, 'j': .00153, 'k': .00772, 'l': .04025,
'm': .02406, 'n': .06749, 'o': .07507, 'p': .01929,
'q': .00095, 'r': .05987, 's': .06327, 't': .09056,
'u': .02758, 'v': .00978, 'w': .02360, 'x': .00150,
'y': .01974, 'z': .00074, ' ': .13000
}
return sum([character_frequencies.get(chr(byte), 0) for byte in input_bytes.lower()])
def single_char_xor(input_bytes, char_value):
"""Returns the result of each byte being XOR'd with a single value.
"""
output_bytes = b''
for byte in input_bytes:
output_bytes += bytes([byte ^ char_value])
return output_bytes
def bruteforce_single_char_xor(ciphertext):
"""Performs a singlechar xor for each possible value(0,255), and
assigns a score based on character frequency. Returns the result
with the highest score.
"""
potential_messages = []
for key_value in range(256):
message = single_char_xor(ciphertext, key_value)
score = get_english_score(message)
data = {
'message': message,
'score': score,
'key': key_value
}
potential_messages.append(data)
return sorted(potential_messages, key=lambda x: x['score'], reverse=True)[0]
def main():
ciphers = open('ex1.4.txt').read().splitlines()#每行放在一个列表中
potential_plaintext = []
for hexstring in ciphers:
ciphertext = bytes.fromhex(hexstring)
potential_plaintext.append(bruteforce_single_char_xor(ciphertext))
print(potential_plaintext)
best_score = sorted(potential_plaintext, key=lambda x: x['score'], reverse=True)[0]
for item in best_score:
print("{}: {}".format(item.title(), best_score[item]))
if __name__ == '__main__':
main()
def repeating_key_xor(key, string):
# i is the position within the key
i = 0
arr = []
for ch in string:
arr.append(ord(ch) ^ ord(key[i]))
i += 1
if (i == len(key)):
i = 0
##ascii转十六进制
#bytearray 这里将数字列表转为 字节串
return hexlify(bytearray(arr))
def repeat_key_xor(m,key):
output_bytes=b''
index=0
for byte in m:
output_bytes+=bytes([byte^key[index]])
#bytes[116,112]转为b'tp'
if(index+1)==len(key):
index=0
else:
index+=1
return output_bytes
m=b"Burning 'em, if you ain't quick and nimble"
m1=b'I go crazy when I hear a cymbal'
key=b'ICE'
c=repeat_key_xor(m,key)
c1=repeat_key_xor(m1,key)
print(c.hex())
print(c1.hex())
#msg=[3, 159, 11, 19, 148, 72, 65, 168, 50, 178, 66, 27, 158, 175, 109, 152, 54, 129, 62, 201, 217, 68, 165, 200, 52, 122, 124, 166, 154, 163, 77, 141, 192, 223, 112, 227, 67, 196, 0, 10, 42, 227, 88, 116, 206, 117, 230, 76, 49, 0]
print(bytearray(msg))#转为字节b'\x03\x9f\x0b\x13\x94HA\xa82\xb2B\x1b\x9e\xafm\x986\x81>\xc9\xd9D\xa5\xc84z|\xa6\x9a\xa3M\x8d\xc0\xdfp\xe3C\xc4\x00\n*\xe3Xt\xceu\xe6L1\x00'
import base64
def hamm (s1, s2):
tot = 0
for a,b in zip(s1,s2):
tot += (bin(a^b).count('1'))
#print('test Hamming distance is: ', tot)
return(tot)
#print(hamm(b'this is a test',b'wokka wokka!!!'))
def find_key_len(c):
aver_hamm=[]
for keylen in range(2,41):
#将密文分组
tmp_aver_hamm=[]
test1 = c
while len(test1) >= (2 * keylen):
x = test1[:keylen]
y = test1[keylen:(2 * keylen)]
# take the hamming distance and normalize by keysize
score = hamm(x, y) / keylen
test1 = test1[ keylen:]
tmp_aver_hamm.append(score)
res={
'keylength': keylen,
'avg distance': sum(tmp_aver_hamm)/len(tmp_aver_hamm)
}
aver_hamm.append(res)
possible_key_length = sorted(aver_hamm, key=lambda x: x['avg distance'])[0]
return possible_key_length['keylength']
##按照同一密钥进行分组c[::keylen]
##每个就转化成了 single_key_XOR: 根据字母出现的频率得到分数最高的
def get_english_score(input_bytes):
character_frequencies = {
'a': .08167, 'b': .01492, 'c': .02782, 'd': .04253,
'e': .12702, 'f': .02228, 'g': .02015, 'h': .06094,
'i': .06094, 'j': .00153, 'k': .00772, 'l': .04025,
'm': .02406, 'n': .06749, 'o': .07507, 'p': .01929,
'q': .00095, 'r': .05987, 's': .06327, 't': .09056,
'u': .02758, 'v': .00978, 'w': .02360, 'x': .00150,
'y': .01974, 'z': .00074, ' ': .13000
}
return sum([character_frequencies.get(chr(byte), 0) for byte in input_bytes.lower()])
def repeat_key_xor(m,key):
output_bytes=b''
index=0
for byte in m:#直接就是对应的ASCII
#print(byte)
#print(key[index])
output_bytes+=bytes([byte^key[index]])
#bytes[116,112]转为b'tp'
if(index+1)==len(key):
index=0
else:
index+=1
return output_bytes
def single_char_xor(input_bytes, char_value):
"""Returns the result of each byte being XOR'd with a single value.
"""
output_bytes = b''
for byte in input_bytes:
output_bytes += bytes([byte ^ char_value])
return output_bytes
def bruteforce_single_char_xor(ciphertext):
"""Performs a singlechar xor for each possible value(0,255), and
assigns a score based on character frequency. Returns the result
with the highest score.
"""
potential_messages = []
for key_value in range(256):
message = single_char_xor(ciphertext, key_value)
score = get_english_score(message)
data = {
'message': message,
'score': score,
'key': key_value
}
potential_messages.append(data)
return sorted(potential_messages, key=lambda x: x['score'], reverse=True)[0]['key']#最大的
cipher=open('ex1.4.txt').read().replace('\n','')
# convert to bytes
cipher=base64.b64decode(cipher)
keylen=find_key_len(cipher)
print(keylen)
#分组
key=[]
for index in range(keylen):
sub_cipher=cipher[index::keylen]
## single_key_XOR:
key.append(bruteforce_single_char_xor(sub_cipher))
print(''.join(chr(i) for i in key))
print(repeat_key_xor(cipher,bytes(''.join(chr(i) for i in key),encoding='utf8')))
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']]
##str2是用来交换的,比如 Qxxx xxxx xxxx都不对,就换成q xxxxxxxxx 时间复杂度为0()由于需要在10s之内求解,
str4=""
str3=[0]*8
#首先要知道密码有多少位吧。。咋确定就是8位呢
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 =hashlib.sha1("".join(i).encode("utf-8")).hexdigest()
if str4==hash1:
print("".join(i))
endtime = datetime.datetime.now()
print(f"运行时间是:{(endtime - starttime).seconds}s")