""" crypto.cipher.trolldoll

    Modification to Icedoll to take advantage of the better error extension
    and provide a IV for randomization of the output and integrity checking.

    IV is simply prepended to plaintext.
    Integrity check is appended to the end of the plain text as
    zeros with count of the blocks in the ciphertext.

    Note !!!! auto IV uses python default random :-(
    should not be 'too bad' (tm) for this applicaiton

    ALso ... currently just IV .... in test ..

    Copyright (c) 2002 by Paul A. Lambert
    Read LICENSE.txt for license information.
"""

from crypto.cipher.icedoll import  Icedoll
from crypto.errors      import IntegrityCheckError
from random import Random  # should change to crypto.random!!!

class Trolldoll(Icedoll):
    """ Trolldoll encryption algorithm
        based on Icedoll, which is based on Rijndael
        Trolldoll adds an 'IV' and integrity checking to Icedoll
    """
    def __init__(self,key=None,keySize=32,blockSize=32,tapRound=6,extraRounds=6,micSize=16,ivSize=16):
        """  """
        Icedoll.__init__(self,key=None,keySize=32,blockSize=32,tapRound=6,extraRounds=6)
        self.name    = 'TROLLDOLL'
        self.micSize = micSize
        self.ivSize  = ivSize
        self.r       = Random()            # for IV generation
        import time
        newSeed = time.ctime()+str(self.r)    # seed with instance location
        self.r.seed(newSeed)                  # to make unique
        self.reset()

    def reset(self):
        Icedoll.reset(self)
        self.hasIV = None

    def _makeIV(self):
        return self.ivSize*'a'

    def _makeIC(self):
        """ Make the integrity check """
        return self.micSize*chr(0x00)

    def _verifyIC(self,integrityCheck):
        """ Verify the integrity check """
        if self.micSize*chr(0x00) == integrityCheck :
            return 1  # matches
        else:
            return 0  # fails

    def encrypt(self, plainText, more=None):
        """ """
        if not(self.hasIV):  # On first call to encrypt put in an IV
            plainText = self._makeIV() + plainText # add the 'IV'
            self.hasIV = 1
        if more == None:    # on last call to encrypt append integrity check
            plainText = plainText + self._makeIC()
        return Icedoll.encrypt(self, plainText, more=more)

    def decrypt(self, cipherText, more=None):
        """ Decrypt cipher text, Icedoll automatically removes
            prepended random bits used as IV.
            Note - typically IV is directly used as the first
            cipher text.  Here the IV is prepended to the plaintext
            prior to encryption and removed on decryption.
        """
        plainText = Icedoll.decrypt(self, cipherText, more=more)
        if not(self.hasIV):  # on first call to decrypt remove IV
            plainText = plainText[self.ivSize:] # remove the IV
            self.hasIV = 1
        if more == None:    # on last call to encrypt append integrity check
            if not(self._verifyIC(plainText[-self.micSize:])) :
                raise IntegrityCheckError, 'Trolldoll MIC Failure, bad key or modified data'
            plainText = plainText[:-self.micSize]  # trim off the integrity check
        return plainText


