def bcc(self, key, data):
        '''
        Block Cipher Chaining as specified in NIST SP800-90A,
        Section 10.4.3, page 70
        '''

        # Step 1
        chaining_value = utilities.binstr_zeropad('', self.outlen)

        # Step 2
        nn = len(data) * 8 / self.outlen

        # Step 3
        # See below within the loop

        # Step 4
        for ii in range(nn):
            # Step 3 again
            block = data[ii * self.outlen / 8:(ii + 1) * self.outlen / 8]
            # Step 4.1
            input_block = utilities.binstr_xor(chaining_value, block)
            # Step 4.2
            chaining_value = self.block_encrypt(key, input_block)

        # Step 5
        output_block = chaining_value

        # Step 6
        return output_block
    def reseed_algorithm(self, entropy_input, additional_input):
        '''
        CTR_DRBG_Reseed_algorithm as specified in NIST SP800-90A,
        Section 10.2.1.4, page 55.
        Reseeds either with (10.2.1.4.2) or without (10.2.1.4.1)
        a derivation function.
        '''

        if self.derivation:
            # 10.2.1.4.2, Step 1
            seed_material = entropy_input + additional_input
            seed_material = utilities.binstr_zeropad(
                seed_material, self.seedlen)
            # 10.2.1.4.2, Step 2
            status, seed_material = self.block_cipher_df(
                seed_material, self.seedlen)
            if status != 'SUCCESS':
                return 'ERROR', 'block_cipher_df returned [%s]' % status
        else:
            # 10.2.1.4.1, Step 1-2
            additional_input = utilities.binstr_zeropad(
                additional_input, self.seedlen)
            # 10.2.1.4.1, Step 3
            seed_material = utilities.binstr_xor(
                entropy_input, additional_input)

        # 10.2.1.4.1, Step 4 / 10.2.1.4.2, Step 3
        self.update(seed_material)

        # 10.2.1.4.1, Step 5 / 10.2.1.4.2, Step 4
        self.counter = 1

        # 10.2.1.4.1, Step 6 / 10.2.1.4.2, Step 5
        return
Beispiel #3
0
    def generate(self, n_bits, security_strength = None,
                 prediction_resistance = None, additional_input = ''):
        'Generate bits from the entropy engine.'
        #
        # If we have a DRBG then use it

        if self.drbg:
            status, drbg_bits = self.drbg.generate(
                n_bits, security_strength,
                prediction_resistance, additional_input)

            # The DRBG, once instantiated, should never fail
            if status != 'SUCCESS' and status != 'RESEED_FAILED':
                return status, "DRBG  failed"

            # If we are combining the DRBG with raw input then get raw bits
            if self.raw:
                status, raw_bits = self.raw.get_entropy_input(
                    security_strength, n_bits,
                    n_bits, prediction_resistance)

                # Failure here is allowable, because we still have the DRBG
                if status != 'SUCCESS':
                    logging.debug(
                        "Using drbg only. %s, %s", status, raw_bits)
                    self.total_bytes += len(drbg_bits)
                    return 'DRBG_ONLY', drbg_bits

                # If we have both sources working then XOR them together
                comb_bits = utilities.binstr_xor(drbg_bits, raw_bits)
                self.total_bytes += len(comb_bits)
                return 'SUCCESS', comb_bits

            # If we only have a DRBG, then return just those bits
            else:
                self.total_bytes += len(drbg_bits)
                return 'SUCCESS', drbg_bits

        # If we have no DRBG then we must have a raw entropy source
        elif self.raw:
            status, raw_bits = self.raw.get_entropy_input(
                security_strength, n_bits,
                n_bits, prediction_resistance)

            # If this fails with no DRBG to back it up, return an error
            if status != 'SUCCESS':
                return status, "Raw source failed"

            # Otherwise return the raw bits
            self.total_bytes += len(raw_bits)
            return 'SUCCESS', raw_bits

        # If we have neither DRBG nor raw source, we cannot generate bits
        return 'ERROR', "Neither DRBG nor raw source available"
    def instantiate_algorithm(self, entropy_input, nonce,
                              personalization, security_strength):
        '''
        CTR_DRBG_Instatntiate_algorithm as specified in NIST SP800-90A
        Section 10.2.1.3, page 53.
        Instantiates either with (10.2.1.3.2) or without (10.2.1.3.1)
        a derivation function.
        '''

        # Set some parameters based on the security strength
        self.keylen     = self.cipher['keylengths'][self.security_strength]
        self.outlen     = self.cipher['block size']
        self.seedlen    = self.keylen + self.outlen

        if not personalization:
            personalization = ''

        # When a derivation function is used (mandatory unless full entropy)
        if self.derivation:
            # 10.2.1.3.2, Step 1
            seed_material = entropy_input + nonce + personalization
            seed_material = utilities.binstr_zeropad(
                seed_material, self.seedlen)
            # 10.2.1.3.2, Step 2
            status, seed_material = self.block_cipher_df(
                seed_material, self.seedlen)
            if status != 'SUCCESS':
                raise ValueError('block_cipher_df returned [%s]' % status)

        # When full entropy is available and a derivation function is not used
        else:
            # 10.2.1.3.1, Step 1-2
            personalization = utilities.binstr_zeropad(
                personalization, self.seedlen)
            # 10.2.1.3.1, Step 3
            seed_material = utilities.binstr_xor(
                entropy_input, personalization)

        # 10.2.1.3.1, Step 4 / 10.2.1.3.2, Step 3
        self.key = utilities.binstr_zeropad('', self.keylen)

        # 10.2.1.3.1, Step 5 / 10.2.1.3.2, Step 4
        self.V   = utilities.binstr_zeropad('', self.outlen)

        # 10.2.1.3.1, Step 6 / 10.2.1.3.2, Step 5
        self.update(seed_material)

        # 10.2.1.3.1, Step 7 / 10.2.1.3.2, Step 6
        self.counter = 1

        # 10.2.1.3.1, Step 8 / 10.2.1.3.2, Step 7
        return
    def update(self, data):
        '''
        CTR_DRBG_Update as specified in NIST SP800-90A,
        Section 10.2.1.2, page 52.
        Updates the internal state using the provided data.'
        '''

        if (self.seedlen & 7) or (self.keylen & 7) or (self.outlen & 7):
            raise NotImplementedError(
                'Only 0 mod 8 is supported for key/block sizes.')

        if type(data) is not str:
            raise ValueError('CTR_DRBG_Update requires string input.')

        seedlenbytes = self.seedlen / 8
        if len(data) != seedlenbytes:
            raise ValueError(
                ('CTR_DRBG_Update requires exactly seedlen of data '
                 '(received %d bytes, expected %d).') %
                (len(data), seedlenbytes))

        # Step 1
        temp = ''

        # Step 2
        while len(temp) < seedlenbytes:
            # Step 2.1
            self.V = utilities.binstr_increment(self.V, self.outlen)
            # Step 2.2
            output_block = self.block_encrypt(self.key, self.V)
            # Step 2.3
            temp = temp + output_block

        # Step 3-4, the XOR function automatically truncates to match
        # input lengths
        temp = utilities.binstr_xor(data, temp)

        # Step 5
        self.key = temp[:self.keylen / 8]

        # Step 6
        self.V   = temp[self.keylen / 8:][:self.outlen / 8]

        # Step 7
        self.scheduled = False
        return