import random
import sys

punctuation_chars = " .,"

key = "MZEkLlRmlVhNNlytFvpHoctNxORiBqSuylWoWdOhGqNYJtYTyCtYMhP^bduCkcSewezUGbpTPpgXBSeqKDRBwWP[MOwIhMono[CKG\MrvW[WPQlm\dZOPrcMLtrxLvxiBNJEGbHz^geg[kwl_JzB^sdc_Yh]JSdS[_hS[]cljKnekih`NarBTshRUGmZ\M`TucC][JpB]sPgJJoLCjMG\K^iiRpI\sc[ChFALWcCVLSQjfSxByLrlnsiNbryW`h^WAvwMYZkhcsWSY_OPiABC]JA]tGrWnJjJfVOxkpEIsJxezXxCfXkkknuTzOvck\AtKoWTTjtlGUJygohEFHHsaNnInOKMNSaFbvgyOdEh`NGFH`xr`ilynTL`_xoSGVrfkunBAnR]zULHpzChhsBoOsUFpOuEI^xqMtH^c`Zt^PKHzNxclvdJdNEd^Rz^lqiiPqUgkTLVeMDNwmoR^ql]IK]PxtpIAtrzevYxigqvRcKbbedKPkkKO]PXWaygnte"

raw_msgs = ( "Cryptography prior to the modern age was effectively synonymous with encryption, the conversion of information from a readable state to apparent nonsense.",
             "The originator of an encrypted message shared the decoding technique needed to recover the original information only with intended recipients",
             "thereby precluding unwanted persons to do the same. Since World War I and the advent of the computer",
             "the methods used to carry out cryptology have become increasingly complex and its application more widespread.",
             "Modern cryptography is heavily based on mathematical theory and computer science practice;",
             "cryptographic algorithms are designed around computational hardness assumptions,",
             "making such algorithms hard to break in practice by any adversary. It is theoretically possible to break such a system but it is infeasible to do so by any known practical means",
             "hese schemes are therefore termed computationally secure; theoretical advances",
             "e.g., improvements in integer factorization algorithms and faster computing technology require these solutions to be continually adapted.",
             "here exist information-theoretically secure schemes that provably cannot be broken")

hex_ciphertexts = ( "315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e",
                    "234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f",
                    "32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb",
                    "32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa",
                    "3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070",
                    "32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4",
                    "32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce",
                    "315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3",
                    "271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027",
                    "466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83")

ciphertexts = ()

hex_target = "32510ba9babebbbefd001547a810e67149caee11d945cd7fc81a05e9f85aac650e9052ba6a8cd8257bf14d13e6f0a803b54fde9e77472dbff89d71b57bddef121336cb85ccb8f3315f4b52e301d16e9f52f904"

def 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 rnd(size=16):
    result = "";
    for i in range(size):
        result += chr(random.randint(65, 122))

    return result

def encrypt(key, msg):
    c = strxor(key, msg)
    #print
    #print c.encode('hex')
    return c

def is_valid_char(c):
    return (ord(c) >= 65 and ord(c) <=90) or (ord(c) >= 97 and ord(c) <=122) or punctuation_chars.find(c) >= 0

def assume_space(msg, pos):
    count = 0
    total = 0
    for m in ciphertexts:
        if m != msg:
            s = strxor(msg, m)
            if pos < len(s):
                total += 1
                if is_valid_char(s[pos]):
                    count += 1

    if total == 0:
        return 0

    if 100*count/total > 75:
        return 1
    else:
        return 0;

def search_space(msg):
    is_space = []
    for i in range(len(msg)):
        is_space.append(assume_space(msg, i))

    return is_space


def recover_key(ciphertexts):
    result = ""
    for i in range(85):
        result += recover_key_at(i,ciphertexts)

    return result

def recover_key_at(pos,ciphertexts):
    result = ""
    for k in range(256):
        valid = 0
        for m in ciphertexts:
            c = strxor(chr(k), m[pos])
            if is_valid_char(c):
                valid += 1

        if valid == len(ciphertexts):
            result += chr(k)

    print result

    if len(result) == 1:
        return result[0]
    else:
        return "*"

def extract_letters(msg):
    result = ""
    for c in msg:
        if is_valid_char(c):
            result += c
        else:
            result += "_"
    return result

def assume_space(msg, pos, ciphertexts):
    count = 0
    total = 0
    for m in ciphertexts:
        if m != msg:
            s = strxor(msg, m)
            if pos < len(s):
                total += 1
                if is_valid_char(s[pos]):
                    count += 1

    if total == 0:
        return 0

    if 100*count/total > 75:
        return 1
    else:
        return 0;

def search_space(msg, ciphertexts):
    is_space = []
    for i in range(len(msg)):
        is_space.append(assume_space(msg, i, ciphertexts))

    return is_space

def mask_msg(msg, mask):
    result = ""
    for i in range(len(msg)):
        if mask[i]:
            result += msg[i]
        else:
            result += "_"

    return result

def reveal_spaces(ciphertexts):
    for m1 in ciphertexts:
        spaces = search_space(m1)
        for m2 in [ciphertexts[1]]:
            s = strxor(m1, m2)
            print mask_msg(s, spaces)

def main():

    key = strxor("09e1c5f70a65ac519458e7e53f36".decode("hex"), "attack at dawn")
    print strxor(key, "attack at dusk").encode("hex")

main()