Exemple #1
0
 def encryptBlock(self, plainTextBlock):
     """ CBC block encryption, IV is set with 'encrypt' """
     auto_IV = ''
     if self.encryptBlockCount == 0:
         if self.iv == None:
             # generate IV and use
             self.iv = ''.join([chr(self.r.randrange(256)) for i in range(self.blockSize)])
             self.prior_encr_CT_block = self.iv
             auto_IV = self.prior_encr_CT_block    # prepend IV if it's automatic
         else:                       # application provided IV
             assert(len(self.iv) == self.blockSize ),'IV must be same length as block'
             self.prior_encr_CT_block = self.iv
     """ encrypt the prior CT XORed with the PT """
     ct = self.baseCipher.encryptBlock( xor(self.prior_encr_CT_block, plainTextBlock) )
     self.prior_encr_CT_block = ct
     return auto_IV+ct
Exemple #2
0
 def encryptBlock(self, plainTextBlock):
     """ CBC block encryption, IV is set with 'encrypt' """
     auto_IV = ''
     if self.encryptBlockCount == 0:
         if self.iv == None:
             # generate IV and use
             self.iv = ''.join([chr(self.r.randrange(256)) for i in range(self.blockSize)])
             self.prior_encr_CT_block = self.iv
             auto_IV = self.prior_encr_CT_block    # prepend IV if it's automatic
         else:                       # application provided IV
             assert(len(self.iv) == self.blockSize ),'IV must be same length as block'
             self.prior_encr_CT_block = self.iv
     """ encrypt the prior CT XORed with the PT """
     ct = self.baseCipher.encryptBlock( xor(self.prior_encr_CT_block, plainTextBlock) )
     self.prior_encr_CT_block = ct
     return auto_IV+ct
Exemple #3
0
    def testTKIP_crc_modify(self):
        """ TKIP crc modification test """
        key = a2b_p(
            "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f")  # the PMK
        ta = a2b_p(
            "10 22 33 44 55 66")  # the TK (key) is created from the iv and ta
        keyID = 0
        alg = TKIP_encr(
            key, ta,
            keyID)  # this is just the encryption algorithm with no Michael MIC
        plainText = ''.join([chr(i) for i in range(20)])  # 20 octets (0 t 19)
        iv = a2b_p(
            "01 00 00 00 00 00")  # the little-endian encoded PacketNumber
        cipherText = alg.encrypt(plainText, iv)

        ctHeader = cipherText[0:8]  # encoded iv and keyId
        ctData = cipherText[8:-4]
        ctCrcEncrypted = cipherText[-4:]  # just the encrypted crc fields

        # lets change the first octet of the data from 0x00 to 0x01
        base = (len(ctData)) * chr(0)
        baseCrc = crc32(base)
        bitMask = chr(1) + (len(ctData) - 1) * chr(0)
        maskCrc = crc32(bitMask)

        maskedCt = xor(bitMask, ctData)
        maskedCtCrc = crc32(maskedCt)

        print "--------------- make a modified packet and MIC ------------"
        print "plainText = %s " % b2a_hex(plainText)
        print "cipherText= %s " % b2a_hex(cipherText)
        print "ctData	 = %s " % b2a_hex(ctData)
        print "ctxtCrc	 = %s " % b2a_hex(ctCrcEncrypted)
        print "base 	 = %s " % b2a_hex(base)
        print "baseCrc	 = %0X" % baseCrc
        print "mask 	 = %s " % b2a_hex(bitMask)
        print "maskCrc	 = %0X" % maskCrc
        print "maskedCt = %s " % b2a_hex(maskedCt)
        print "maskCtCrc= %0X" % maskedCtCrc
        maskDiff = maskCrc ^ baseCrc
        newCtCrc = pack('<I', (maskDiff ^ unpack('<I', ctCrcEncrypted)[0]))
        newCt = ctHeader + maskedCt + newCtCrc
        newPt = alg.decrypt(
            newCt)  # this will raise an exception if the crc is 'bad'!
        print "newPt	 = %s " % b2a_hex(newPt)
Exemple #4
0
    def decryptBlock(self, encryptedBlock):
        """ Decrypt a single block """

        if self.decryptBlockCount == 0:   # first call, process IV
            if self.iv == None:    # auto decrypt IV?
                self.prior_CT_block = encryptedBlock
                return ''
            else:
                assert(len(self.iv)==self.blockSize),"Bad IV size on CBC decryption"
                self.prior_CT_block = self.iv

        dct = self.baseCipher.decryptBlock(encryptedBlock)
        """ XOR the prior decrypted CT with the prior CT """
        dct_XOR_priorCT = xor( self.prior_CT_block, dct )

        self.prior_CT_block = encryptedBlock

        return dct_XOR_priorCT
Exemple #5
0
    def decryptBlock(self, encryptedBlock):
        """ Decrypt a single block """

        if self.decryptBlockCount == 0:   # first call, process IV
            if self.iv == None:    # auto decrypt IV?
                self.prior_CT_block = encryptedBlock
                return ''
            else:
                assert(len(self.iv)==self.blockSize),"Bad IV size on CBC decryption"
                self.prior_CT_block = self.iv

        dct = self.baseCipher.decryptBlock(encryptedBlock)
        """ XOR the prior decrypted CT with the prior CT """
        dct_XOR_priorCT = xor( self.prior_CT_block, dct )

        self.prior_CT_block = encryptedBlock

        return dct_XOR_priorCT
def pbkdf2(password, salt, iterations, keySize, PRF=HMAC_SHA1):
	""" Create key of size keySize from password and salt """
	if len(password)>63:
		raise 'Password too long for pbkdf2'
	#if len(password)<8 : raise 'Password too short for pbkdf2'
	if (keySize > 10000):		  # spec says >4294967295L*digestSize
		raise 'keySize too long for PBKDF2'

	prf = PRF(key=password)  # HMAC_SHA1
	numBlocks = ceil(1.*keySize/prf.digest_size) # ceiling function
	key = ''
	for block in range(1,numBlocks+1):
		# Calculate F(P, salt, iterations, i)
		F = prf(salt+pack('>i',block)) # i is packed into 4 big-endian bytes
		U = prf(salt+pack('>i',block)) # i is packed into 4 big-endian bytes
		for count in range(2,iterations+1):
			U = prf(U)
			F = xor(F,U)
		key = key + F
	return key[:keySize]
def pbkdf2(password, salt, iterations, keySize, PRF=HMAC_SHA1):
    """ Create key of size keySize from password and salt """
    if len(password) > 63:
        raise ResolverError('Password too long for pbkdf2')
    # if len(password)<8 : raise 'Password too short for pbkdf2'
    if (keySize > 10000):         # spec says >4294967295L*digestSize
        raise ResolverError('keySize too long for PBKDF2')

    prf = PRF(key=password)  # HMAC_SHA1
    numBlocks = int(ceil(1. * keySize / prf.digest_size))  # ceiling function
    key = ''
    for block in range(1, numBlocks + 1):
        # Calculate F(P, salt, iterations, i)
        F = prf(salt + pack('>i', block))  # i is packed into 4 big-endian bytes
        U = prf(salt + pack('>i', block))  # i is packed into 4 big-endian bytes
        for _ in range(2, iterations + 1):
            U = prf(U)
            F = xor(F, U)
        key = key + F
    return key[:keySize]
Exemple #8
0
	def testTKIP_crc_modify(self):
		""" TKIP crc modification test """
		key = a2b_p( "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" ) # the PMK
		ta	= a2b_p( "10 22 33 44 55 66" ) # the TK (key) is created from the iv and ta
		keyID = 0
		alg = TKIP_encr(key, ta, keyID)  # this is just the encryption algorithm with no Michael MIC
		plainText  = ''.join([chr(i) for i in range(20)]) # 20 octets (0 t 19)
		iv = a2b_p( "01 00 00 00 00 00" ) # the little-endian encoded PacketNumber
		cipherText = alg.encrypt(plainText, iv)

		ctHeader	   = cipherText[0:8]  # encoded iv and keyId
		ctData		   = cipherText[8:-4]
		ctCrcEncrypted = cipherText[-4:]  # just the encrypted crc fields

		# lets change the first octet of the data from 0x00 to 0x01
		base	= (len(ctData))*chr(0)
		baseCrc = crc32(base)
		bitMask = chr(1)+(len(ctData)-1)*chr(0)
		maskCrc = crc32(bitMask)

		maskedCt	 = xor(bitMask,ctData)
		maskedCtCrc  = crc32(maskedCt)

		print "--------------- make a modified packet and MIC ------------"
		print "plainText = %s "  % b2a_hex(plainText)
		print "cipherText= %s "  % b2a_hex(cipherText)
		print "ctData	 = %s "  % b2a_hex(ctData)
		print "ctxtCrc	 = %s "  % b2a_hex(ctCrcEncrypted)
		print "base 	 = %s " % b2a_hex(base)
		print "baseCrc	 = %0X" % baseCrc
		print "mask 	 = %s " % b2a_hex(bitMask)
		print "maskCrc	 = %0X" % maskCrc
		print "maskedCt = %s " % b2a_hex(maskedCt)
		print "maskCtCrc= %0X" % maskedCtCrc
		maskDiff = maskCrc ^ baseCrc
		newCtCrc = pack('<I', (maskDiff ^ unpack('<I',ctCrcEncrypted)[0]) )
		newCt = ctHeader + maskedCt + newCtCrc
		newPt = alg.decrypt(newCt)	 # this will raise an exception if the crc is 'bad'!
		print "newPt	 = %s " % b2a_hex(newPt)
Exemple #9
0
class CCM(BlockCipherWithIntegrity):
    """ The CCM class wraps block ciphers to provide integrity and encryption.

        CCM provides both encryption and a strong integrity check. The
        integrity check can optionally include "additional authentication
        data" that is included in the message integrity check, but is not encrypted.

        CCM is composed of two passes of the same base cipher, first
        the instance calculates a CBC Message Authentication Check,
        and then the same algorithm instance is used for the CTR
        (counter) mode encryption.

        This algorithm mode does NOT support streams of data (moreData flag)
        since a full packet must be available for the two pass CBC_MAC
        and CTR encryption process.

        When decrypting, a 'DecryptIntegrityError' exception is raised
        if the integrity check fails.

            >> aes_ccm = CCM(AES(key))
            >> cipherText = aes_ccm.encrypt(plainText, nonce)
            >> try:
            >>     decryptedText = aes_ccm.decrypt(cipherText, nonce)
            >> except IntegrityCheckError:
            >>     print 'failed integrity check'
            or ...
            >> cipherText = aes_ccm.encrypt(plainText, nonce, addAuthData=header)
            >> try:
            >>     decryptedText = aes_ccm.decrypt(cipherText, nonce, addAuthData=header)
            >> except IntegrityCheckError:
            >>     print 'failed integrity check'
    """
    def __init__(self,
                 blockCipherInstance,
                 autoNonce=None,
                 macSize=8,
                 nonceSize=13):
        """ CCM algorithms are created by initializing with a BlockCipher instance
                blockCipherInstance -> typically AES_ECB
                autoNonce -> sets the intial value of a nonce for automatic nonce
                             creation (not available yet)
                macSize   -> size of MAC field can be = 4, 6, 8, 10, 12, 14, or 16
                nonceSize -> size of nonce in bytes (default 13)
                the counter size is blockSize-nonceSize-1
        """
        self.baseCipher = blockCipherInstance
        self.name = self.baseCipher.name + '_CCM'
        self.blockSize = self.baseCipher.blockSize
        self.keySize = self.baseCipher.keySize

        self.baseCipher.padding = noPadding()  # baseCipher should NOT pad!!

        self.M = macSize  # Number of octets
        if not ((3 < self.M < 17) and (macSize % 2 == 0)):
            raise (InitCryptoError,
                   'CCM, M (size of auth field) is out of bounds')

        self.nonceSize = nonceSize
        self.L = self.baseCipher.blockSize - self.nonceSize - 1
        if not (1 < self.L < 9):
            raise (InitCryptoError,
                   'CCM, L (size of length field) is out of bounds')
        self.reset()

    def setKey(self, key):
        self.baseCipher.setKey(key)
        self.reset()

    # Overload to reset both CCM state and the wrapped baseCipher
    def resetEncrypt(self):
        BlockCipherWithIntegrity.resetEncrypt(
            self)  # reset CCM encrypt state (super class)
        self.baseCipher.resetEncrypt()  # reset base cipher encrypt state

    def resetDecrypt(self):
        BlockCipherWithIntegrity.resetDecrypt(
            self)  # reset CBC state (super class)
        self.baseCipher.resetEncrypt(
        )  # CCM uses encryption of base cipher to decrypt!

    def encrypt(self, plainText, nonce, addAuthData=''):
        """  CCM encryption of plainText
                nonce must be unique for each encryption, if set to none
                   it will maintain it's own nonce creation
                addAuthData is optional  """
        # construct authentication block zero
        #     flag byte fields
        Adata = ((len(addAuthData)) > 0) << 6  # bit 6 is 1 if auth
        Mfield = ((self.M - 2) / 2) << 3  # bits 5,4,3 encode macSize
        Lfield = self.L - 1  # bits 2,1,0 encode L size = blockSize-nonceSize-1
        flagsByte = chr(Adata ^ Mfield ^ Lfield)

        if len(nonce) != self.nonceSize:
            raise (EncryptError, 'wrong sized nonce')

        lenMessage = len(plainText)
        if lenMessage >= 1L << (8 * self.L):
            raise (EncryptError,
                   'CCM plainText too long for given L field size')
        packedLenMessage = pack(
            '!Q', lenMessage)[-self.L:]  # pack and truncate to L bytes

        blockZero = flagsByte + nonce + packedLenMessage
        if len(blockZero) != self.baseCipher.blockSize:
            raise (EncryptError, 'CCM bad size of first block')

        authLengthField = self._encodeAuthLength(len(addAuthData))
        cbcInput = blockZero + authLengthField + addAuthData
        authPadSize = self.baseCipher.blockSize - (
            (len(cbcInput) - 1) % self.baseCipher.blockSize) - 1
        cbcInput = cbcInput + authPadSize * chr(
            0)  # pad to block size with zeros
        cbcInput = cbcInput + plainText
        cbcEndPad = chr(0x00) * ((self.blockSize - (
            (len(cbcInput)) % self.blockSize)) % self.blockSize)
        cbcInput = cbcInput + cbcEndPad

        # Calculate CBC_MAC
        numCbcBlocks, extra = divmod(len(cbcInput), self.blockSize)
        assert (extra == 0), 'bad block size on cbc_mac calculation'

        cbcMicValue = self.blockSize * chr(0x00)
        for i in range(numCbcBlocks):
            cbcBlock = cbcInput[i * self.blockSize:(i + 1) * self.blockSize]
            cbcMicValue = self.baseCipher.encrypt(xor(cbcMicValue, cbcBlock))
        counter = 0L
        # the counter mode preload with counter starting at zero
        ctrModePl = chr(self.L - 1) + nonce + pack('>Q', counter)[-self.L:]
        ccmMIC = xor(self.baseCipher.encrypt(ctrModePl),
                     cbcMicValue)[:self.M]  # first M bytes of xor

        ct = ''
        numCtrBlocks, extra = divmod(
            len(plainText) + self.blockSize, self.blockSize)
        while counter < numCtrBlocks:
            counter = counter + 1L
            ctrModePl = chr(self.L - 1) + nonce + pack('>Q', counter)[-self.L:]
            ct = ct + xor(self.baseCipher.encrypt(ctrModePl),
                          plainText[(counter - 1) * 16:counter * 16])
        ct = ct + ccmMIC
        return ct
Exemple #10
0
                   'CCM cipherText too long for given L field size')
        if lenMessage < 0:
            raise (DecryptError, 'Too small of cipherText for MIC size')
        packedLenMessage = pack(
            '!Q', lenMessage)[-self.L:]  # pack and truncate to L bytes

        pt = ''
        ct = cipherText[:-self.M]  # trim of MIC field

        numCtrBlocks, extra = divmod(len(ct) + self.blockSize, self.blockSize)
        for counter in range(1, numCtrBlocks + 1):
            ctrModePl = chr(self.L - 1) + nonce + pack('>Q', counter)[-self.L:]
            ctr = self.baseCipher.encrypt(ctrModePl)
            ctBlock = ct[(counter - 1) * self.blockSize:counter *
                         self.blockSize]
            pt = pt + xor(ctr, ctBlock)
        #------- CBC Mac Calculation
        blockZero = flagsByte + nonce + packedLenMessage
        if len(blockZero) != self.baseCipher.blockSize:
            raise (DecryptError, 'CCM bad size of first block')

        authLengthField = self._encodeAuthLength(len(addAuthData))
        cbcInput = blockZero + authLengthField + addAuthData
        authPadSize = self.baseCipher.blockSize - (
            (len(cbcInput) - 1) % self.baseCipher.blockSize) - 1
        cbcInput = cbcInput + authPadSize * chr(
            0)  # pad to block size with zeros
        cbcInput = cbcInput + pt
        cbcEndPad = chr(0x00) * ((self.blockSize - (
            (len(cbcInput)) % self.blockSize)) % self.blockSize)
        cbcInput = cbcInput + cbcEndPad
        lenMessage = len(cipherText)-self.M
        if lenMessage >= 1L<<(8*self.L):
            raise DecryptError, 'CCM cipherText too long for given L field size'
        if lenMessage < 0 :
            raise DecryptError, 'Too small of cipherText for MIC size'
        packedLenMessage = pack('!Q', lenMessage)[-self.L:]  # pack and truncate to L bytes

        pt = ''
        ct = cipherText[:-self.M]      # trim of MIC field

        numCtrBlocks,extra = divmod(len(ct)+self.blockSize,self.blockSize)
        for counter in range(1, numCtrBlocks+1) :
            ctrModePl = chr(self.L-1) + nonce + pack('>Q', counter)[-self.L:]
            ctr     = self.baseCipher.encrypt(ctrModePl)
            ctBlock = ct[(counter-1)*self.blockSize:counter*self.blockSize]
            pt = pt + xor( ctr, ctBlock )
        #------- CBC Mac Calculation
        blockZero = flagsByte+nonce+packedLenMessage
        if len(blockZero) != self.baseCipher.blockSize:
            raise DecryptError, 'CCM bad size of first block'

        authLengthField = self._encodeAuthLength(len(addAuthData))
        cbcInput     = blockZero+authLengthField+addAuthData
        authPadSize  = self.baseCipher.blockSize-((len(cbcInput)-1)%self.baseCipher.blockSize)-1
        cbcInput     = cbcInput + authPadSize*chr(0)    # pad to block size with zeros
        cbcInput     = cbcInput + pt
        cbcEndPad    = chr(0x00)*((self.blockSize-((len(cbcInput))%self.blockSize))%self.blockSize)
        cbcInput     = cbcInput + cbcEndPad

        # Calculate CBC_MAC
        numCbcBlocks,extra = divmod(len(cbcInput),self.blockSize)
    def decrypt(self, cipherText, nonce, addAuthData=''):
        """  CCM decryption of cipherText
                nonce must be unique for each encryption, if set to none
                   it will maintain it's own nonce creation
                   the nonce is then included in the cipher text
                addAuthData is option """
        # construct authentication block zero
        #     flag byte fields
        Adata = ((len(addAuthData)) > 0) << 6  # bit 6 is 1 if auth
        Mfield = ((self.M - 2) / 2) << 3  # bits 5,4,3 encode macSize
        Lfield = self.L - 1  # bits 2,1,0 encode L size = blockSize-nonceSize-1
        flagsByte = chr(Adata ^ Mfield ^ Lfield)

        if len(nonce) != self.nonceSize:
            raise DecryptError('wrong sized nonce')

        lenMessage = len(cipherText) - self.M
        if lenMessage >= 1 << (8 * self.L):
            raise DecryptError(
                'CCM cipherText too long for given L field size')
        if lenMessage < 0:
            raise DecryptError('Too small of cipherText for MIC size')
        packedLenMessage = pack(
            '!Q', lenMessage)[-self.L:]  # pack and truncate to L bytes

        pt = ''
        ct = cipherText[:-self.M]  # trim of MIC field

        numCtrBlocks, extra = divmod(len(ct) + self.blockSize, self.blockSize)
        for counter in range(1, numCtrBlocks + 1):
            ctrModePl = chr(self.L - 1) + nonce + pack('>Q', counter)[-self.L:]
            ctr = self.baseCipher.encrypt(ctrModePl)
            ctBlock = ct[(counter - 1) * self.blockSize:counter *
                         self.blockSize]
            pt = pt + xor(ctr, ctBlock)
        #------- CBC Mac Calculation
        blockZero = flagsByte + nonce + packedLenMessage
        if len(blockZero) != self.baseCipher.blockSize:
            raise DecryptError('CCM bad size of first block')

        cbcInput = blockZero
        # DB: don't encode auth length if there is no adata
        if len(addAuthData):
            authLengthField = self._encodeAuthLength(len(addAuthData))
            cbcInput += authLengthField + addAuthData

        authPadSize = self.baseCipher.blockSize - (
            (len(cbcInput) - 1) % self.baseCipher.blockSize) - 1
        cbcInput = cbcInput + authPadSize * chr(
            0)  # pad to block size with zeros
        cbcInput = cbcInput + pt
        cbcEndPad = chr(0x00) * ((self.blockSize - (
            (len(cbcInput)) % self.blockSize)) % self.blockSize)
        cbcInput = cbcInput + cbcEndPad

        # Calculate CBC_MAC
        numCbcBlocks, extra = divmod(len(cbcInput), self.blockSize)
        assert (extra == 0), 'bad block size on cbc_mac calculation'
        cbcMicValue = self.blockSize * chr(0x00)
        for i in range(numCbcBlocks):
            cbcBlock = cbcInput[i * self.blockSize:(i + 1) * self.blockSize]
            cbcMicValue = self.baseCipher.encrypt(xor(cbcMicValue, cbcBlock))

        ctrModePl0 = chr(self.L - 1) + nonce + pack('>Q', 0)[-self.L:]
        ccmMIC = xor(self.baseCipher.encrypt(ctrModePl0),
                     cbcMicValue)[:self.M]  # first 8 bytes of xor

        if ccmMIC != cipherText[-self.M:]:
            raise IntegrityCheckError('CCM Integrity check failed on decrypt')

        return pt
    def encrypt(self, plainText, nonce, addAuthData=''):
        """  CCM encryption of plainText
                nonce must be unique for each encryption, if set to none
                   it will maintain it's own nonce creation
                addAuthData is optional  """
        # construct authentication block zero
        #     flag byte fields
        Adata = ((len(addAuthData)) > 0) << 6  # bit 6 is 1 if auth
        Mfield = ((self.M - 2) / 2) << 3  # bits 5,4,3 encode macSize
        Lfield = self.L - 1  # bits 2,1,0 encode L size = blockSize-nonceSize-1
        flagsByte = chr(Adata ^ Mfield ^ Lfield)

        if len(nonce) != self.nonceSize:
            raise EncryptError('wrong sized nonce')

        lenMessage = len(plainText)
        if lenMessage >= 1 << (8 * self.L):
            raise EncryptError('CCM plainText too long for given L field size')
        packedLenMessage = pack(
            '!Q', lenMessage)[-self.L:]  # pack and truncate to L bytes

        blockZero = flagsByte + nonce + packedLenMessage
        if len(blockZero) != self.baseCipher.blockSize:
            raise EncryptError('CCM bad size of first block')

        cbcInput = blockZero
        # DB: don't encode auth length if there is no adata
        if len(addAuthData):
            authLengthField = self._encodeAuthLength(len(addAuthData))
            cbcInput += authLengthField + addAuthData

        authPadSize = self.baseCipher.blockSize - (
            (len(cbcInput) - 1) % self.baseCipher.blockSize) - 1
        cbcInput = cbcInput + authPadSize * chr(
            0)  # pad to block size with zeros
        cbcInput = cbcInput + plainText
        cbcEndPad = chr(0x00) * ((self.blockSize - (
            (len(cbcInput)) % self.blockSize)) % self.blockSize)
        cbcInput = cbcInput + cbcEndPad

        # Calculate CBC_MAC
        numCbcBlocks, extra = divmod(len(cbcInput), self.blockSize)
        assert (extra == 0), 'bad block size on cbc_mac calculation'

        cbcMicValue = self.blockSize * chr(0x00)
        for i in range(numCbcBlocks):
            cbcBlock = cbcInput[i * self.blockSize:(i + 1) * self.blockSize]
            cbcMicValue = self.baseCipher.encrypt(xor(cbcMicValue, cbcBlock))
        counter = 0
        # the counter mode preload with counter starting at zero
        ctrModePl = chr(self.L - 1) + nonce + pack('>Q', counter)[-self.L:]
        ccmMIC = xor(self.baseCipher.encrypt(ctrModePl),
                     cbcMicValue)[:self.M]  # first M bytes of xor

        ct = ''
        numCtrBlocks, extra = divmod(
            len(plainText) + self.blockSize, self.blockSize)
        while counter < numCtrBlocks:
            counter = counter + 1
            ctrModePl = chr(self.L - 1) + nonce + pack('>Q', counter)[-self.L:]
            ct = ct + xor(self.baseCipher.encrypt(ctrModePl),
                          plainText[(counter - 1) * 16:counter * 16])
        ct = ct + ccmMIC
        return ct