"""
strxor and random_string functions are written by Paul Crowley and
distributed with this package under separate MIT
license. paul@ciphergoth.org
"""

import random
import pickle
import binascii
import sha
import hmac

from urllib import urlencode

# XXX: set __all__

def hmacsha1(key, text):
    return hmac.new(key, text, sha).digest()

def sha1(s):
    return sha.new(s).digest()

def long2a(l):
    if l == 0:
        return '\x00'
    
    return ''.join(reversed(pickle.encode_long(l)))

def a2long(s):
    return pickle.decode_long(''.join(reversed(s)))

def to_b64(s):
    """Represent string s as base64, omitting newlines"""
    return binascii.b2a_base64(s)[:-1]

def from_b64(s):
    return binascii.a2b_base64(s)

def kvform(d):
    """Represent dict d as newline-terminated key:value pairs"""
    return ''.join(['%s:%s\n' % (k, v) for k, v in d.iteritems()])

def parsekv(d):
    d = d.strip()
    args = {}
    for line in d.split('\n'):
        pair = line.split(':', 1)
        if len(pair) != 2: continue
        k, v = pair
        args[k.strip()] = v.strip()
    return args

def strxor(aa, bb):
    return "".join([chr(ord(a) ^ ord(b)) for a, b in zip(aa, bb)])

def sign_reply(reply, key, signed_fields):
    """Sign the given fields from the reply with the specified key.
    Return signed and sig"""
    token = []
    for i in signed_fields:
        token.append((i, reply['openid.' + i]))
    
    text = ''.join(['%s:%s\n' % (k, v) for k, v in token])
    return ','.join(signed_fields), to_b64(hmacsha1(key, text))

def append_args(url, args):
    if len(args) == 0:
        return url

    return '%s%s%s' % (url, ('?' in url) and '&' or '?', urlencode(args))

def random_string(length, srand):
    """Produce a string of length random bytes using srand as a source of
    random numbers."""
    return ''.join([chr(srand.randrange(256)) for _ in xrange(length)])



class DiffieHellman(object):
    DEFAULT_MOD = 155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443L

    DEFAULT_GEN = 2

    @classmethod
    def fromBase64(cls, p=None, g=None, srand=None):
        if p is not None:
            p = a2long(from_b64(p))
        if g is not None:
            g = a2long(from_b64(g))

        return cls(p, g, srand)
    
    def __init__(self, p=None, g=None, srand=None):
        if p is None:
            p = self.DEFAULT_MOD
        self.p = long(p)

        if g is None:
            g = self.DEFAULT_GEN
        self.g = long(g)

        if srand is None:
            srand = random

        self.x = srand.randrange(1, p - 1)

    def createKeyExchange(self):
        return pow(self.g, self.x, self.p)

    def decryptKeyExchange(self, keyEx):
        return pow(keyEx, self.x, self.p)
