def run(attack_traces: np.ndarray, attack_keys: np.ndarray, attack_plain: np.ndarray, round_: int, operation: int, subkey: int, offset: int = 15, single_order: bool = False, debug_mode_enabled: bool = False, bit: int = 0) -> np.ndarray: """ The run method of dpa :param attack_traces: the traces to use for attacking :param attack_keys: the keys to use for attacking :param attack_plain: the plaintexts to use for attacking :param round_: the AES round to attack :param operation: the AES operation to attack, represented as an integer from 0 to 3 :param subkey: the subkey index to analyze. Must be in the range [0-15]. :param offset: offset to use for dpa. :param single_order: only use single order. :param debug_mode_enabled: whether to enable debug mode :param bit: which bit to select. :return: the calculated subkey corresponding to the subkey index specified """ print("Executing Differential Power Analysis") result = np.zeros(16, dtype=int) if single_order: offset = 0 # Init progress bar with amount of iterations. if subkey == 16: bar = progressbar.ProgressBar( max_value=16 * (255), widgets=progress_bar_util.get_widgets(debug_mode_enabled)) for i in range(16): dpa = DPA(attack_traces, attack_keys, attack_plain, bit) dpa.set_offset(offset) result[i] = dpa.solve_subkey(i, debug_mode_enabled, round_=round_, operation=operation, bar=bar) else: bar = progressbar.ProgressBar( max_value=255, widgets=progress_bar_util.get_widgets(debug_mode_enabled)) dpa = DPA(attack_traces, attack_keys, attack_plain, bit) dpa.set_offset(offset) result[subkey] = dpa.solve_subkey(subkey, debug_mode_enabled, round_=round_, operation=operation, bar=bar) bar.finish() print('The final key is: ', result) return result
def run(aligned: np.ndarray, unaligned: np.ndarray, algorithm: int, output: str, debug_mode_enabled: bool): """Aligns traces with specified algorithm and outputs an aligned file :param aligned: File of 1 or more aligned traces. :param unaligned: File of unaligned traces :param algorithm: algorithm to use :param output: filename to output to. :param debug_mode_enabled: debug mode flag. :return: """ print("Executing trace alignment.") bar = progressbar.ProgressBar( max_value=len(unaligned), widgets=progress_bar_util.get_widgets(debug_mode_enabled)) if algorithm == 0: outputarray = Aligner.dtw(aligned, unaligned, bar) np.save(output, outputarray) elif algorithm == 1: outputarray = Aligner.fft(aligned, unaligned, bar) np.save(output, outputarray) bar.finish() return 0
def test_get_widgets(self): """ Tests if the normal widgets are returned correctly """ real_widgets = progress_bar_util.CONST_DEFAULT_WIDGETS result = progress_bar_util.get_widgets(False) self.assertEqual(real_widgets, result)
def test_get_widgets_debug(self): """ Tests if the debug widgets are returned correctly """ real_widgets = progress_bar_util.CONST_DEFAULT_DEBUG_WIDGETS result = progress_bar_util.get_widgets(True) self.assertEqual(real_widgets, result)
def test_log_progressbar_forbidden(self): """Tests whether trying to log to a progressbar while not in debug mode does not work""" log_handler = loghandler.LogHandler("test_file8", False) log_bar = progressbar.ProgressBar( widgets=progress_bar_util.get_widgets(True)) log_handler.log_to_debug_progressbar(log_bar, "test123") # Test if the debug message while logging is equal to the desired string desired_value = {progress_bar_util.CONST_DEBUG_STRING: None} self.assertEqual(log_bar.dynamic_messages, desired_value)
def test_log_to_debug_progressbar(self): """"This tests whether loghandler to the progressbar works""" log_handler = loghandler.LogHandler("test_file4", True) test_string = "Test123" # Create a progressbar and debug a certain test string log_bar = progressbar.ProgressBar( widgets=progress_bar_util.get_widgets(True)) log_handler.log_to_debug_progressbar(log_bar, test_string) log_handler.stop_logging() # Test if the debug message while loghandler is equal to the desired string desired_value = {progress_bar_util.CONST_DEBUG_STRING: test_string} self.assertEqual(log_bar.dynamic_messages, desired_value) os.remove(log_handler.file_name)
def run(traces: np.ndarray, keys: np.ndarray, plain: np.ndarray, subkey: int, num_features: int, feature_select: int): """ Runs Linear Regression Analysis :param traces: the traces to use :param keys: the keys to use :param plain: the plaintexts corresponding to the traces :param subkey: the specific subkey index to calculate. 16 is used to indicate that the whole key should be returned :param num_features: the number of features to select with feature selection :param feature_select: the type of feature selection to use. :return: the (sub)key most likely to be the real (sub)key """ print('This performs Linear Regression Analysis') lra = LRA(traces, plain) lra.bar = progressbar.ProgressBar( max_value=2 * lra.KEY_SIZE, widgets=progress_bar_util.get_widgets(False)) result = [0 for _ in range(16)] subkey_indices = [subkey] if subkey == 16: subkey_indices = list(range(16)) lra.bar.max_value *= 16 for i in subkey_indices: if feature_select != 0: feature_indices = DataPartitioner.select_features( traces, keys, plain, i, feature_select, num_features, 1, 0, True) lra.traces = traces[:, feature_indices] lra.dimension_leakage_points = len(lra.traces[0]) result[i] = lra.solve_subkey(i) print('The final key is: ', result) return result
def test_stop_logging_to_progressbar(self): """Tests whether the stop_logging function stops the loghandler to the progressbar""" log_handler = loghandler.LogHandler("test_file6", True) test_string = "Test123" # Create a progressbar and debug a certain test string log_bar = progressbar.ProgressBar( widgets=progress_bar_util.get_widgets(True)) log_handler.log_to_debug_progressbar(log_bar, test_string) log_handler.stop_logging() # Write again a message which shouldnt be logged test_string2 = "Test456" log_handler.log_to_debug_progressbar(log_bar, test_string2) # Test if the debug message while loghandler is equal to the desired string desired_value = {progress_bar_util.CONST_DEBUG_STRING: test_string} self.assertEqual(log_bar.dynamic_messages, desired_value) os.remove(log_handler.file_name)
def run(traces: np.ndarray, plains: np.ndarray, keys: np.ndarray, attack_traces: np.ndarray, subkey: int, debug_mode_enabled: bool = False) -> List[int]: """ The run method of pia :param traces: the traces to use :param plains: the plaintexts to use :param keys: the keys to use :param attack_traces: the traces to use for attacking :param subkey: the subkey index to analyze. Must be in the range [0-15]. :param debug_mode_enabled: whether to enable debug mode :return: the calculated subkey corresponding to the subkey index specified """ print("Executing Perceived Information Analysis") bar = progressbar.ProgressBar( max_value=len(attack_traces[0]) * (16 if subkey == 16 else 1), widgets=progress_bar_util.get_widgets(debug_mode_enabled)) warnings.simplefilter("ignore", category=RuntimeWarning) perceived_information = [0] * len(attack_traces[0]) max_pia = -float("inf") bar.start() indices = [subkey] if subkey == 16: indices = range(subkey) for i in indices: subkeys = [0] * len(keys) for j in range(len(keys)): subkeys[j] = int(keys[j][i]) dummy_interp1d = interp1d(range(2), range(2)) leakage_per_byte_value_matrix = [ list() for _ in range(Pia.KEY_SIZE) ] model_sampled_pdf_per_byte_value_array = np.array( [dummy_interp1d for _ in range(Pia.KEY_SIZE)]) for j in range(len(traces[0])): for k in range(len(traces)): key = subkeys[k] plain = plains[k][i] byte = key ^ plain leakage_per_byte_value_matrix[byte].append(traces[k][j]) for j in range(len(leakage_per_byte_value_matrix)): model_mu, model_std = norm.fit( leakage_per_byte_value_matrix[j]) model_sampled_pdf_per_byte_value_array[j] = Pia.sample_pdf( model_mu, model_std, 10) scaling_factor = 1.0 / (len(traces) * len(attack_traces)) for j in range(len(attack_traces[0])): column = attack_traces[:, j] chip_mu, chip_std = norm.fit(column) chip_sampled_pdf = Pia.sample_pdf(chip_mu, chip_std, 10) pia = 0 for cell in column: for k in range(Pia.KEY_SIZE): model_sampled_pdf = model_sampled_pdf_per_byte_value_array[ k] if not np.isclose(chip_std, 0.0): model_probability = model_sampled_pdf(cell) chip_probability = chip_sampled_pdf(cell) # The sampling sometimes returns a negative probability. Correct this. if model_probability <= 0.0: model_probability = 0.000001 if chip_probability <= 0.0: chip_probability = 0.0 pia += chip_probability * math.log2( model_probability) pia *= scaling_factor _, bin_edges = np.histogram(column, bins='auto') bin_values = np.digitize(column, bin_edges) o = np.array(bin_values, dtype=int) shannon_entropy = drv.entropy(o) pia = shannon_entropy - pia perceived_information[j] += pia if bar.value < bar.max_value: bar.update(bar.value + 1) if pia > max_pia: max_pia = pia for i in range(len(perceived_information)): perceived_information[i] /= max_pia * (16 if subkey == 16 else 1) bar.finish() plt.plot(perceived_information) plt.show() warnings.simplefilter("default") print("Done!") return perceived_information
def run(template_traces: np.ndarray, template_keys: np.ndarray, template_plaintext: np.ndarray, attack_traces: np.ndarray, attack_keys: np.ndarray, attack_plain: np.ndarray, pooled: bool, num_points_of_interest: int, spacing_points_of_interest: int, subkey: int, gpu: bool = False, leakage_model: bool = True, debug_mode_enabled: bool = False, feature_select: int = 0) -> np.array: """ Method used to select correct version of Template Attack. :param template_traces: the traces to use :param template_keys: the keys to use :param template_plaintext: the plaintexts to use :param attack_traces: the traces to use for attacking :param attack_keys: the keys to use for attacking :param attack_plain: the plaintexts to use for attacking :param pooled: whether to do a pooled attack :param num_points_of_interest: number of points of interest to use :param spacing_points_of_interest: spacing between the points of interest :param subkey: the subkey index to analyze. Must be in the range [0-16]. 16 signals the full key. :param gpu: whether or not to use gpu for this attack :param leakage_model: the leakage model to use :param debug_mode_enabled: whether to enable debug mode :param feature_select: which feature selection method to use, see main for which number is which. :return: array containing the calculated key """ # Init progress bar with rough amount of iterations num_subkeys = 16 if subkey == 16 else 1 # Attack takes roughly equal time per subkey so * 16 for whole key max_value = len(attack_traces) * 256 * num_subkeys bar = progressbar.ProgressBar( max_value=max_value, widgets=progress_bar_util.get_widgets(debug_mode_enabled)) ta = TA(template_traces, template_keys, template_plaintext, attack_traces, attack_keys, attack_plain) indices = [] if feature_select > 0: print("Feature selection is being calculated...") if num_subkeys == 16: for i in range(16): temp = DataPartitioner.select_features( template_traces, template_keys, template_plaintext, i, feature_select, num_points_of_interest, 1, 0, leakage_model) for j in temp: indices.append(j) else: # Select at least 10 features num_features = max(num_points_of_interest, 10) indices = DataPartitioner.select_features( template_traces, template_keys, template_plaintext, subkey, feature_select, num_features, 1, 0, leakage_model) ta.template_traces, ta.attack_traces = template_traces[:, indices], attack_traces[:, indices] if pooled: result = ta.run_pooled(num_points_of_interest, spacing_points_of_interest, subkey, bar, gpu, leakage_model, debug_mode_enabled) else: result = ta.run_normal(num_points_of_interest, spacing_points_of_interest, subkey, bar, gpu, leakage_model, debug_mode_enabled) bar.finish() print('The final key is: ', result) return result
def run(traces: np.ndarray, keys: np.ndarray, plain: np.ndarray, attack_traces: np.ndarray, attack_keys: np.ndarray, attack_plain: np.ndarray, round_: int, operation: int, subkey: int, feature_select: int, num_features: int, hamming_weight: bool = False, debug_mode_enabled: bool = False, online: bool = False, conditional_averaging: bool = False) -> np.ndarray: """ The run method of cpa :param traces: the traces to use :param keys: the keys to use :param plain: the plaintexts to use :param attack_traces: the traces to use for attacking :param attack_keys: the keys to use for attacking :param attack_plain: the plaintexts to use for attacking :param round_: the AES round to attack :param operation: the AES operation to attack, represented as an integer from 0 to 3 :param feature_select: which feature select method to use. :param num_features: the number of features to select :param subkey: the subkey index to analyze. Must be in the range [0-15]. :param hamming_weight: whether to use the hamming_weight leakage model :param debug_mode_enabled: whether to enable debug mode :param online: use online correlation calculation. :param conditional_averaging: whether to use conditional averaging. :return: the calculated subkey corresponding to the subkey index specified """ print("Executing Correlation Power Analysis") result = np.zeros(16, dtype=int) # Init progress bar with amount of iterations. if subkey == 16: bar = progressbar.ProgressBar( max_value=16 * 255, widgets=progress_bar_util.get_widgets(debug_mode_enabled)) for i in range(16): if feature_select > 0: indices = data_partitioner.DataPartitioner.select_features( traces, keys, plain, i, feature_select, num_features, round_, operation, hamming_weight) cpa = CPA(attack_traces[:, indices], attack_keys, attack_plain, online) else: cpa = CPA(attack_traces, attack_keys, attack_plain, online) result[i] = cpa.solve_subkey( i, hamming_weight, debug_mode_enabled, round_=round_, operation=operation, bar=bar, conditional_averaging=conditional_averaging) else: bar = progressbar.ProgressBar( max_value=255, widgets=progress_bar_util.get_widgets(debug_mode_enabled)) if feature_select > 0: indices = data_partitioner.DataPartitioner.select_features( traces, keys, plain, subkey, feature_select, num_features, round_, operation, hamming_weight) cpa = CPA(attack_traces[:, indices], attack_keys, attack_plain, online) else: cpa = CPA(attack_traces, attack_keys, attack_plain, online) result[subkey] = cpa.solve_subkey( subkey, hamming_weight, debug_mode_enabled, round_=round_, operation=operation, bar=bar, conditional_averaging=conditional_averaging) bar.finish() print('The final key is: ', result) return result
def run(profiling_traces: np.ndarray, profiling_keys: np.ndarray, profiling_plaintext: np.ndarray, attack_traces: np.ndarray, attack_keys: np.ndarray, attack_plaintext: np.ndarray, round_: int, operation: int, num_traces: int, num_attack_traces: int, subkey: int, feature_select: int, num_features: int, use_gpu: bool = False, hamming_weight: bool = False, debug_mode_enabled: bool = False) \ -> List[int]: """ Runs a full stochastic attack :param profiling_traces: the traces to use :param profiling_keys: the keys to use :param profiling_plaintext: the plaintexts to use :param attack_traces: the traces to use for attacking :param attack_keys: the keys to use for attacking :param attack_plaintext: the plaintexts to use for attacking :param round_: the AES round to attack :param operation: the AES operation to attack, represented as an integer from 0 to 3 :param num_traces: number of data points to process :param num_attack_traces: number of data points to attack :param feature_select: which feature select method to use. :param num_features: the number of features to select :param subkey: the subkey index to analyze. Must be in the range [0-16], 16 signaling the whole key. :param use_gpu: whether or not to use gpu acceleration :param hamming_weight: whether or not to use the hamming_weight leakage model :param debug_mode_enabled: whether or not to enable debug mode :returns: list containing the (sub)key """ print('This performs a stochastic attack.') # Instantiate a SA (Stochastic Attack) object to call dynamic method. sa = SA(profiling_traces, profiling_keys, profiling_plaintext, attack_traces, attack_keys, attack_plaintext) sa.log_handler = LogHandler('sa', debug_mode_enabled) if sa.log_handler is not None: sa.log_handler.log_to_debug_file( 'RUNNING stochastic attack with \n' 'TEMPLATE_TRACES: {} \n' 'NUM_FEATURES: {} \n' 'ATTACK_TRACES: {} \n' 'SUBKEY: {}.'.format(len(sa.profiling_traces), num_features, len(sa.attack_traces), subkey)) # Init progress bar with estimated amount of iterations num_subkeys = 16 if subkey == 16 else 1 max_value = num_attack_traces * 256 * num_subkeys * 15 bar = progressbar.ProgressBar( max_value=max_value, widgets=progress_bar_util.get_widgets(debug_mode_enabled)) result = [0 for _ in range(16)] # call method that returns the key, currently with no arguments taken from the user. if subkey == 16: for i in range(subkey): result[i] = sa.solve_subkey( i, use_gpu, bar, feature_select=feature_select, num_features=num_features, num_traces=num_traces, num_attack_traces=num_attack_traces, hamming_weight=hamming_weight, aes_round=round_, aes_operation=operation) else: result[subkey] = sa.solve_subkey( subkey, use_gpu, bar, feature_select=feature_select, num_features=num_features, num_traces=num_traces, num_attack_traces=num_attack_traces, hamming_weight=hamming_weight, aes_round=round_, aes_operation=operation) bar.finish() print('The final key is: ', result) return result