# -*- coding: utf-8 -*-
#
# NOTE : Library for CrackMe 0.3 Beta (http://www.bitbin.it/PUt0h7ZN)
#        paste in a file with the name "crypto.py" and put in your
#        /home/user/.xchat2/
#
#        crypto.py
#
#        Copyright (c) 2010 - Kalkulators Knights
#
#        This file is part of Kalkb0t.
#        Kalkb0t is free software; you can redistribute it and/or modify
#        it under the terms of the GNU General Public License as published by
#        the Free Software Foundation; either version 2 of the License, or
#        (at your option) any later version.
#
#        This program is distributed in the hope that it will be useful,
#        but WITHOUT ANY WARRANTY; without even the implied warranty of
#        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#        GNU General Public License for more details.
#
#        You should have received a copy of the GNU General Public License
#        along with this program. If not, see <http://www.gnu.org/licenses/>.
#


from Crypto.Cipher import DES
import mhash

__all__ = ['HashMaker']


class SambaPass(object):
    """Generate lm and ntlm hashes - Thanks to sanguinarius for this class
    """
    def lmhash(self, password):
        """generate lm hash"""
        secret   = r'KGS!@#$%'
        password = password.upper()[:14]
        k1 = self.SMB_Key(password[:7])
        k2 = self.SMB_Key(password[7:])
        d1 = DES.new(k1, DES.MODE_CBC)
        d2 = DES.new(k2, DES.MODE_CBC)
        h1 = d1.encrypt(secret).encode('hex').upper()
        h2 = d2.encrypt(secret).encode('hex').upper()
        if len(password) > 7:
            return h1+h2
        else:
            return h1

    def SMB_Key(self, string):
        """convert the string the way samba does
        """
        key7bits = [0] * 8
        key8bits = [0] * 8

        for i in range(0, len(string)):
            key7bits[i] = ord(string[i])

        key8bits[0] = ((key7bits[0] >> 1) & 0xff)
        key8bits[1] = ((((key7bits[0] & 0x01) << 6) | (((key7bits[1] & 0xff)>>2) & 0xff)) & 0xff)
        key8bits[2] = ((((key7bits[1] & 0x03) << 5) | (((key7bits[2] & 0xff)>>3) & 0xff)) & 0xff)
        key8bits[3] = ((((key7bits[2] & 0x07) << 4) | (((key7bits[3] & 0xff)>>4) & 0xff)) & 0xff)
        key8bits[4] = ((((key7bits[3] & 0x0F) << 3) | (((key7bits[4] & 0xff)>>5) & 0xff)) & 0xff)
        key8bits[5] = ((((key7bits[4] & 0x1F) << 2) | (((key7bits[5] & 0xff)>>6) & 0xff)) & 0xff)
        key8bits[6] = ((((key7bits[5] & 0x3F) << 1) | (((key7bits[6] & 0xff)>>7) & 0xff)) & 0xff)
        key8bits[7] = (key7bits[6] & 0x7F)

        for i in range(0,8):
            key8bits[i] = (key8bits[i] << 1)

        result = ''

        for i in range(0, 8):
            result += chr(key8bits[i])

        return result


class HashMaker(object):
    """Multi-algorithms hash generation class
    """
    @staticmethod
    def adler32(plaintext):
        return get_digest('adler32', plaintext).encode('hex')

    @staticmethod
    def crc32(plaintext):
        return get_digest('crc32', plaintext).encode('hex')

    @staticmethod
    def crc32b(plaintext):
        return get_digest('crc32b', plaintext).encode('hex')

    @staticmethod
    def gost(plaintext):
        return get_digest('gost', plaintext).encode('hex')

    @staticmethod
    def haval128(plaintext):
        return get_digest('haval128', plaintext).encode('hex')

    @staticmethod
    def haval160(plaintext):
        return get_digest('haval160', plaintext).encode('hex')

    @staticmethod
    def haval192(plaintext):
        return get_digest('haval192', plaintext).encode('hex')

    @staticmethod
    def haval224(plaintext):
        return get_digest('haval224', plaintext).encode('hex')

    @staticmethod
    def haval256(plaintext):
        return get_digest('haval256', plaintext).encode('hex')

    @staticmethod
    def md2(plaintext):
        return get_digest('md2', plaintext).encode('hex')

    @staticmethod
    def md4(plaintext):
        return get_digest('md4', plaintext).encode('hex')

    @staticmethod
    def md5(plaintext):
        return get_digest('md5', plaintext).encode('hex')

    @staticmethod
    def ripemd128(plaintext):
        return get_digest('ripemd128', plaintext).encode('hex')

    @staticmethod
    def ripemd160(plaintext):
        return get_digest('ripemd160', plaintext).encode('hex')

    @staticmethod
    def ripemd256(plaintext):
        return get_digest('ripemd256', plaintext).encode('hex')

    @staticmethod
    def ripemd320(plaintext):
        return get_digest('ripemd320', plaintext).encode('hex')

    @staticmethod
    def sha1(plaintext):
        return get_digest('sha1', plaintext).encode('hex')

    @staticmethod
    def sha224(plaintext):
        return get_digest('sha224', plaintext).encode('hex')

    @staticmethod
    def sha256(plaintext):
        return get_digest('sha256', plaintext).encode('hex')

    @staticmethod
    def sha384(plaintext):
        return get_digest('sha384', plaintext).encode('hex')

    @staticmethod
    def sha512(plaintext):
        return get_digest('sha512', plaintext).encode('hex')

    @staticmethod
    def snefru128(plaintext):
        return get_digest('snefru128', plaintext).encode('hex')

    @staticmethod
    def snefru256(plaintext):
        return get_digest('snefru256', plaintext).encode('hex')

    @staticmethod
    def tiger(plaintext):
        return get_digest('tiger', plaintext).encode('hex')

    @staticmethod
    def tiger128(plaintext):
        return get_digest('tiger128', plaintext).encode('hex')

    @staticmethod
    def tiger160(plaintext):
        return get_digest('tiger160', plaintext).encode('hex')

    @staticmethod
    def whirlpool(plaintext):
        return get_digest('whirlpool', plaintext).encode('hex')

    @staticmethod
    def mysql3(plaintext):
        nr = 1345345333
        add = 7
        nr2 = 0x12345671
        for char in plaintext:
            if char in ' \t':
                continue
            tmp = ord(char)
            nr ^= (((nr & 63)+add)*tmp) + (nr << 8)
            nr &= 0xffffffff
            nr2 += (nr2 << 8) ^ nr
            nr2 &= 0xffffffff
            add += tmp
        ints = (
                nr & ((1 << 31)-1),
                nr2 & ((1 << 31)-1)
        )
        return "%08lx%08lx" % ints

    @staticmethod
    def mysql5(plaintext):
        sha1 = get_digest('sha1', plaintext)
        mysql5 = get_digest('sha1', sha1)
        return mysql5.encode('hex')

    @staticmethod
    def lm(plaintext):
        return SambaPass().lmhash(plaintext)


def get_digest(algo, plaintext):
    md = mhash.MHASH(getattr(mhash, 'MHASH_%s' % algo.upper()))
    md.update(plaintext)
    return md.digest()
