import hashlib
import json
import hmac
import base64
import pyaes
from pkcs7 import PKCS7Encoder
import os, urllib2,urllib
import cookielib
from operator import xor
from itertools import izip, starmap
from struct import Struct


def evpKDF(passwd, salt, key_size=8, iv_size=4, iterations=1, hash_algorithm="md5"):
    target_key_size = key_size + iv_size
    derived_bytes = ""
    number_of_derived_words = 0
    block = None
    hasher = hashlib.new(hash_algorithm)
    while number_of_derived_words < target_key_size:
        if block is not None:
            hasher.update(block)

        hasher.update(passwd)
        hasher.update(salt)
        block = hasher.digest()
        hasher = hashlib.new(hash_algorithm)

        for i in range(1, iterations):
            hasher.update(block)
            block = hasher.digest()
            hasher = hashlib.new(hash_algorithm)

        derived_bytes += block[0: min(len(block), (target_key_size - number_of_derived_words) * 4)]

        number_of_derived_words += len(block)/4

    return {
        "key": derived_bytes[0: key_size * 4],
        "iv": derived_bytes[key_size * 4:]
    }


def PBKDF2(data, salt, iterations=1000, keylen=24, hashfunc=None):
    """Returns a binary digest for the PBKDF2 hash algorithm of `data`
    with the given `salt`.  It iterates `iterations` time and produces a
    key of `keylen` bytes.  By default SHA-1 is used as hash function,
    a different hashlib `hashfunc` can be provided.
    """
    _pack_int = Struct('>I').pack
    hashfunc = hashfunc or hashlib.sha1
    mac = hmac.new(data, None, hashfunc)
    def _pseudorandom(x, mac=mac):
        h = mac.copy()
        h.update(x)
        return map(ord, h.digest())
    buf = []
    for block in xrange(1, -(-keylen // mac.digest_size) + 1):
        rv = u = _pseudorandom(salt + _pack_int(block))
        for i in xrange(iterations - 1):
            u = _pseudorandom(''.join(map(chr, u)))
            rv = starmap(xor, izip(rv, u))
        buf.extend(rv)
    return ''.join(map(chr, buf))[:keylen]


def encode(plaintext,passphrase,saltsize=8):
    salt= os.urandom(saltsize)
    data = evpKDF(passphrase,salt)
    decryptor = pyaes.new(data['key'], pyaes.MODE_CBC, IV=data['iv'])
    plaintext = PKCS7Encoder().encode(plaintext)
    enctext= decryptor.encrypt(plaintext)
    return base64.b64encode("Salted__"+salt+enctext)

##''if salt is provided, it should be string
##ciphertext is base64 and passphrase is string
def decode(ciphertext,passphrase,salt=None):
    ciphertext=base64.b64decode(ciphertext)
    if not salt:
        salt=ciphertext[8:16]
        ciphertext=ciphertext[16:]
    data = evpKDF(passphrase, salt)
    decryptor = pyaes.new(data['key'], pyaes.MODE_CBC, IV=data['iv'])
    d= decryptor.decrypt(ciphertext)
    return PKCS7Encoder().decode(d)

def getUrl(url, cookieJar=None,post=None, timeout=20, headers=None):

    cookie_handler = urllib2.HTTPCookieProcessor(cookieJar)
    opener = urllib2.build_opener(cookie_handler, urllib2.HTTPBasicAuthHandler(), urllib2.HTTPHandler())
    #opener = urllib2.install_opener(opener)
    req = urllib2.Request(url)
    req.add_header('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36')
    if headers:
        for h,hv in headers:
            req.add_header(h,hv)

    response = opener.open(req,post,timeout=timeout)
    link=response.read()
    response.close()
    return link;

def gettvnDecryptedURL(cookiejar=None,globalkey="XXX",passphrase="turbo", videoid="835", ref="http://www.moje-filmy.tk/tv/tvn", pubkeyurl='http://www.moje-filmy.tk/film/cryption/getPublicKey', handshakeurl="http://www.moje-filmy.tk/film/cryption/handshake", getvideourl="http://www.moje-filmy.tk/tv/get"):

    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_v1_5
    if cookiejar==None:
        jw=cookielib.LWPCookieJar()
    else:
        jw=cookiejar

    pubkey=getUrl(pubkeyurl,cookieJar=jw,headers=[('Referer',ref)])
    pubkey=eval(pubkey)["publickey"]
    key=encode(globalkey, passphrase)

    
    key2 = RSA.importKey(pubkey)

    
    cipher = PKCS1_v1_5.new(key2)
    ciphertext = cipher.encrypt(key)
    getpart=base64.b64encode(ciphertext)

    post={'key':getpart}
    post = urllib.urlencode(post)
    challenge=getUrl(handshakeurl,post=post,cookieJar=jw,headers=[('Referer',ref)])

    challenge=eval(challenge)["challenge"]
    cc=encode( videoid, key)

    post={'key':cc}
    post = urllib.urlencode(post)
    url=getUrl(getvideourl,post=post,cookieJar=jw,headers=[('Referer',ref)])

    url=eval(url)["url"]
    finalurl=decode(url, key)
    print finalurl
    finalurl=eval(finalurl)["url"]
    finalurl=finalurl.replace('\\/','/')
    return finalurl


#import binascii
#import hashlib
#key, iv = EVP_BytesToKey(hashlib.md5, pp, salt, 32, 16, 1)
#print key,iv
#print 1/0
#print 'salt=%s' % binascii.b2a_hex(salt)
#print 'key=%s' % binascii.b2a_hex(key)
#print 'iv =%s' % binascii.b2a_hex(iv)

#print  decode(ct,pp,salt)
#decryptor = pyaes.new(key, pyaes.MODE_CBC, IV=iv)
#d= decryptor.decrypt(ct)
#print d

    #print pubkey
#c=cookielib.LWPCookieJar()
#print gettvnDecryptedURL(c)


