import base64
import string
import collections
import csv
import random
from math import sqrt
import itertools
import simple_crypto as sc# helper functions

stl = 20  # str_tips length
do_4 = False

# 1. Convert hex to base64 and back.
print "\n---- Problem 1: Convert hex to base64 and back ----"
p1_hex = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"
p1_b64 = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t"
p1_hex_dec = p1_hex.decode ('hex')
p1_b64_enc = base64.b64encode (p1_hex_dec)
p1_b64_dec = base64.b64decode (p1_b64_enc)
p1_hex_enc = p1_b64_dec.encode ('hex')
print "hex (G) :", sc.str_tips (p1_hex, stl) 
print "b64 (G) :", sc.str_tips (p1_b64, stl)
print "hex_dec :", p1_hex_dec
print "b64_enc :", sc.str_tips (p1_b64_enc, stl)
print "b64_dec :", p1_b64_dec
print "hex_enc :", sc.str_tips (p1_hex_enc, stl)
assert p1_b64_enc == p1_b64, 'Hex -> B64 failed'
assert p1_b64_dec == p1_hex_dec, 'Decoding mismatch (dec b64 != dec hex)'
assert p1_hex_enc == p1_hex, 'b64 -> hex failed'


# 2. Fixed XOR
print "\n---- Problem 2: Fixed XOR ----"
p2_a = "1c0111001f010100061a024b53535009181c"
p2_b = "686974207468652062756c6c277320657965"
p2_r = "746865206b696420646f6e277420706c6179"
p2_a_dec = p2_a.decode ('hex')
p2_b_dec = p2_b.decode ('hex')
p2_r_dec = p2_r.decode ('hex')
p2_o_dec =  sc.xor_string(p2_a_dec, p2_b_dec)
print "a_dec   : ", p2_a_dec
print "b_dec   : ", p2_b_dec
print "a^b (G) : ", p2_r_dec
print "a^b     : ", p2_o_dec
assert p2_o_dec.encode ('hex') == p2_r, 'a^b failed'


# 3. Single-character XOR Cipher
print "\n---- Problem 3: Single-character XOR Cipher ----"
p3_hex = "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736"
p3_hex_dec = p3_hex.decode ('hex')
f = sc.freq_array_load()
key, value = sc.ngram_freq_cos_sim (p3_hex_dec, f)
p3_xor_dec = sc.xor_char (p3_hex_dec, key)
p3_xor_enc = sc.xor_char (p3_xor_dec, key)
p3_hex_enc = p3_xor_enc.encode ('hex')
print "p3 dec : ", key
print "p3 dec : ", p3_xor_dec
assert p3_hex == p3_hex_enc, 'dec/enc failed'

# 4. Detect single-character XOR
if do_4:
    print "\n---- Problem 4: Detect single-character XOR ----"
    lines = [line.strip() for line in open('gistfile_p4.txt')]
    best = (0,'',"")
    f = sc.freq_array_load()
    for x in lines:
        x_raw = x.decode('hex')
        key, value = sc.ngram_freq_cos_sim (x_raw, f)
        if value > best[0]:
            best = (value, key, x)
    print "p4 key : ", best[1]
    print "p4 dec : ", sc.xor_str (best[2].decode('hex'),best[1]).strip()


# 5. Repeating-key XOR Cipher
print "\n---- Problem 5: Repeating-key XOR Cipher ----"
p5_str = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal"
p5_key = "ICE"
p5_enc_hex = "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f"
p5_enc = p5_enc_hex.decode('hex')
p5_str_enc = sc.xor_str(p5_str,p5_key)
p5_str_enc_hex = sc.xor_str(p5_str,p5_key).encode('hex')
p5_dec = sc.xor_str(p5_enc, p5_key)
print "p5 str     (G) :", sc.str_tips (p5_str, stl)
print "p5 enc hex (G) :", sc.str_tips (p5_enc_hex, stl)
print "p5 str enc hex :", sc.str_tips (p5_str_enc_hex, stl)
print "p5 dec         :", sc.str_tips (p5_dec, stl)
assert p5_enc == p5_str_enc, "p5 encryption failed"
assert p5_dec == p5_str, "p5 decryption failed"

# 5b. Encrypt a bunch of stuff using your repeating-key XOR function
keys = 10
sa = [] # string array
sa.append ("Please! This is supposed to be a happy occasion.")
sa.append ("Let's not bicker and argue over who killed who.")
sa.append ("Go and boil your bottoms, you sons of silly persons!")
sa.append ("Listen, strange women lyin' in ponds distributin' swords is no basis for a system of government.")
sa.append ("Supreme executive power derives from a mandate from the masses, not from some farcical aquatic ceremony.")
for s in sa:
    for k in range(keys):
        key_len = random.randint (3,30)
        key = ''.join (random.choice (string.ascii_letters) for r in range (key_len))
        assert sc.test_xor (s,key)
print "Repeating-key XOR tested successfully on:", "\n\t", \
         len(sa), "strings", "\n\t", \
         len(sa)*keys, "unique keys"


# 6. Break repeating-key XOR
print "\n---- Problem 6: Break repeating-key XOR ----"
p6_a = "this is a test"
p6_b = "wokka wokka!!!"
p6_hd_ab = sc.hamming_dist (p6_a, p6_b)
assert p6_hd_ab == 37 # Given
print "Hamming Distance [", p6_a,",", p6_b,"] =", p6_hd_ab
p6_str_b64 = ''.join([line.strip() for line in open('gistfile_p6.txt')])
p6_str = base64.b64decode (p6_str_b64)
p6_key_len = sc.key_len_finder (p6_str)
print "Possible p6_key_len :", p6_key_len[0][0],",", p6_key_len[1][0],",", p6_key_len[2][0]



s = "DFJKSDJFKsjlakfjdsfkd"
key_len = 5


print sc.group_and_trans (s,key_len)

