def HMAC(self, key_bytes, message_bytes):
        '''Provides the bytes of the hashed message authentication code. To
           convert to hexadecimal, the bytes need to be passed through
           MySHA256.hexdigest(result).

           Returns the bytes of the hashed message authentication code.'''
        # Convert the ipad and the opad to bitarrays
        ipadBitArray = self.ipadToBits()
        opadBitArray = self.opadToBits()
        # Pad the key
        paddedKey = self.padKey(key_bytes)
        # Fuse the key with the ipad and opad
        fusedIpad = self.fusePadWithKey(ipadBitArray, paddedKey)
        fusedOpad = self.fusePadWithKey(opadBitArray, paddedKey)

        # Prepend the message with the fused ipad
        inputMessage = bytearray(fusedIpad.ToBytes())
        inputMessage.extend(message_bytes)
        # Hash the ipad to begin hashing the message
        mySHA = MySHA256()
        ipadHashPart = mySHA.hash(BytesToWords(inputMessage))
        ipadHashPartBits = MyBitArray()
        ipadHashPartBits.FromBytes(ipadHashPart)

        # Take the result hash bytes and prepend the fused opad
        finalHashInput = MyBitArray()
        finalHashInput.FromBytes(fusedOpad.ToBytes())
        finalHashInput.extend(ipadHashPartBits)

        # Hash the resulting concatenation
        result = mySHA.hash(BytesToWords(finalHashInput.ToBytes()))

        return result
Пример #2
0
    def padMessage(message_bytes):
        ''' Pads a given byte array of a message with a 1 followed by 0s and finally the length
            of the original message in the last 8 bytes of the last message block.
            '''
        lastMessageBitIndex = 448

        # Guard conditions        
        if MySHA256.blockLength < 0:
            raise ValueError("MySHA256 block length should be set to 512, but is set to a negative number.")

        originalMessageLengthBytes = MySHA256.messageLengthToBytes(message_bytes)
        if len(originalMessageLengthBytes) > (MySHA256.blockLength - lastMessageBitIndex):
            raise ValueError("MySHA256 cannot process a message of this length.")

        # Get length of block in bytes
        lastBlockLength = (len(message_bytes) % (int(MySHA256.blockLength/8)))
        nZeroes = lastMessageBitIndex - 1 - (lastBlockLength * 8)

        if nZeroes < 0:
            # Add a whole block of padding if necessary, to fit with the padding scheme
            nZeroes = MySHA256.blockLength + nZeroes - 1
        
        # Add padding
        messageBitArray = MyBitArray()
        messageBitArray.FromBytes(message_bytes)
        messageBitArray.extend([1])
        messageBitArray.extend([0] * nZeroes)

        # Append length of the original message
        result = bytearray(messageBitArray.ToBytes())
        result.extend(originalMessageLengthBytes)

        return bytes(result)
    def padKey(self, key_bytes):
        '''Pads the used key with zeroes on the right until it meets the expected
           hash input length. Doesn't return the padded key, just changes it
           in-place.'''
        paddedKey = MyBitArray()
        paddedKey.FromBytes(key_bytes)
        if len(paddedKey) < BrownThomasHMAC.expectedBlockLength:
            padding = [0] * (len(paddedKey) - BrownThomasHMAC.expectedBlockLength)
            padding.extend(paddedKey.bits)
            paddedKey.FromBits(padding)
        elif len(paddedKey) > BrownThomasHMAC.expectedBlockLength:
            paddedKey.bits = paddedKey.bits[:BrownThomasHMAC.expectedBlockLength]

        return paddedKey
    def fusePadWithKey(self, pad_bit_array, padded_key_bit_array):
        '''Fuses a key with the given ipad or opad. XORs the key with the leftmost
           bits of the given pad. The pad will not be the same size as the key.
           The key will be a smaller size.

           Returns the padded key as a bit array.'''
        padFirstPart = MyBitArray()
        padFirstPart.FromBits(pad_bit_array.bits[:len(padded_key_bit_array)])
        resultFirstPart = padFirstPart ^ padded_key_bit_array
        result = MyBitArray()
        result.FromBits(padFirstPart.bits)
        result.extend(pad_bit_array[len(padFirstPart):])

        return result        
    def ProcessPermutation(self, bit_array, permutation_box, is_reversed = False):
        # Make resulting bit array                                   
        result = MyBitArray()

        # Process the permutation
        if is_reversed == False:
            for x in permutation_box:
                result.append(bit_array[x - 1])
        else:
            # Reverse the permutation
            result.bits = [0] * len(bit_array)
            for i in range(len(permutation_box)):
                result[permutation_box[i] - 1] = bit_array[i]
            
        return result
    def RemovePadding(self, padded_block_bit_array):
        blockBytes = padded_block_bit_array.ToBytes()

        # Search for existence of padding
        padByte = self.GetPaddingByte(blockBytes)
        if padByte != -1:
            endIndex = len(blockBytes) - int(padByte)
            unpaddedBytes = bytes(blockBytes[:endIndex])
            unpaddedBits = MyBitArray()
            unpaddedBits.FromBytes(unpaddedBytes)
            return unpaddedBits
        else:
            originalBitArray = MyBitArray()
            originalBitArray.extend(padded_block_bit_array)
            return originalBitArray
    def ProcessKeySchedule(self, feistel_round_info, is_encryption):
        if len(feistel_round_info.KeyLeft) != 28 or len(feistel_round_info.KeyRight) != 28:
            raise ValueError("Inappropriate key encountered when processing key schedule.")

        if is_encryption == True:
            self.RotateKeyHalves(feistel_round_info, is_encryption)

        # Get the subkey    
        preSubkey = MyBitArray()
        preSubkey.extend(feistel_round_info.KeyLeft)
        preSubkey.extend(feistel_round_info.KeyRight)
        subkey = self.ProcessPermutation(preSubkey, self.pc2Box)

        if is_encryption == False:
            self.RotateKeyHalves(feistel_round_info, is_encryption)

        return subkey
    def CreateInitializationVector(self):
        bitLength = 0
        initializationVector = bytearray()

        while bitLength < self.expectedBlockLength:
            appendage = randint(0, 255)
            initializationVector.append(appendage)
            bitLength += appendage.bit_length()
            if bitLength >= self.expectedBlockLength:
                break

        resultBitArray = MyBitArray()
        resultBitArray.FromBytes(initializationVector)
        # Truncate result to expectedBlockLength # of bits
        resultBitArray.bits = resultBitArray.bits[:self.expectedBlockLength]

        return resultBitArray
    def FeistelFunction(self, data_input_right_half, subkey):
        # E box (Expansion)
        expandedData = self.ProcessPermutation(data_input_right_half, self.expansionBox)
                
        # XOR Mr with round's subkey
        sBoxInput = expandedData ^ subkey

        # Process through S-boxes
        joinedSBoxOutput = MyBitArray()
        sBoxes = [self.sBox1, self.sBox2, self.sBox3, self.sBox4, self.sBox5, self.sBox6, self.sBox7, self.sBox8]
        for i in range(len(sBoxes)):
            index = i * self.sBoxInputLength
            sBoxOutput = self.ProcessSBox(sBoxInput[index : index + self.sBoxInputLength], sBoxes[i])
            joinedSBoxOutput.extend(sBoxOutput)
                
        # Permute result
        result = self.ProcessPermutation(joinedSBoxOutput, self.permutationBox)

        return result