Exemple #1
0
def cw_project_to_trs(project_name, trs_filename, export_keys):
    """Converts ChipWhisperer project into trs trace format.

  Args:
    project_name: Path to ChipWhisperer capture project.
    trs_filename: Output filename for trs result.
    export_keys: Set to true to include the keys in the trs output.
  """
    print(f'input project: {project_name}')
    p = cw.open_project(project_name)
    print(f'num_traces: {len(p.traces)}')
    print(f'num_samples per trace: {len(p.waves[0])}')
    print(f'output file: {trs_filename}')

    h = gen_trs_headers(p, export_keys)
    calc_data_offsets(p.traces[0], export_keys, h)

    traces = []
    for trace in tqdm(p.traces, desc='Converting', ncols=80):
        traces.append(
            trsfile.Trace(trsfile.SampleCoding.FLOAT,
                          trace.wave,
                          data=gen_trs_data(trace, export_keys)))

    print('Writing output file, this may take a while.')
    with trsfile.trs_open(trs_filename,
                          'w',
                          engine='TrsEngine',
                          headers=h,
                          live_update=True) as t:
        t.extend(traces)
Exemple #2
0
    def test_project_openable(self):
        self.project = cw.create_project(self.project_name)
        traces = create_random_traces(100, 5000)
        self.project.traces.extend(traces)
        self.project.save()

        # make sure you can open the project with open_project
        self.project = cw.open_project(self.project_name)
Exemple #3
0
    def test_CPA(self):
        project = cw.open_project('projects/Tutorial_B5')
        leak_model = cwa.leakage_models.sbox_output
        attack = cwa.cpa(project, leak_model)
        results = attack.run()
        keys = results.find_key()
        for i in range(len(project.keys[0])):
            self.assertEqual(project.keys[0][i], keys[i])

        project.close(save=False)
Exemple #4
0
 def test_jitter(self):
     project = cw.open_project('projects/jittertime')
     resync_traces = cwa.preprocessing.ResyncSAD(project)
     resync_traces.ref_trace = 0
     resync_traces.target_window = (700, 1500)
     resync_traces.max_shift = 700
     new_proj = resync_traces.preprocess()
     leak_model = cwa.leakage_models.sbox_output
     attack = cwa.cpa(new_proj, leak_model)
     results = attack.run()
     keys = results.find_key()
     for i in range(len(project.keys[0])):
         self.assertEqual(project.keys[0][i], keys[i])
     project.close(save=False)
Exemple #5
0
    def __load_from_file(self, ntru_file):
        """
        TODO: add description


        :param ntru_file:
        :return:
        """
        
        gdl.check_file_exists(ntru_file+".cwp")

        # Open the ASCAD database HDF5 for reading
        # try:
        self.__raw_data = cw.open_project(ntru_file)
        self.key_num = self.__raw_data.keys[0].size # 64
        self.key_ids_num = int(self.key_num/2)      # 32
Exemple #6
0
    def __init__(self, project_file, trace_slice, attack_window,
                 attack_direction):
        """Inits a TraceWorker.

        Args:
            project_file: A Chipwhisperer project file.
            trace_slice: Traces assigned to this worker.
            attack_window: Samples to process.
            attack_direction: Attack direction.
        """
        self.project = cw.open_project(project_file)
        # TODO: Consider more efficient formats.
        self.num_samples = attack_window.stop - attack_window.start
        if attack_direction == AttackDirection.INPUT:
            self.texts = np.vstack(self.project.textins[trace_slice])
        else:
            self.texts = np.vstack(self.project.textouts[trace_slice])
        self.traces = np.asarray(
            self.project.waves[trace_slice])[:, attack_window]
Exemple #7
0
def GO_Convert(CW_format_file, ASCAD_format_file):
    proj = cw.open_project(CW_format_file)
    out_file = h5py.File(ASCAD_format_file)

    # Generate dummy mask
    mask = np.zeros(16, dtype=np.uint8)

    # Create traces dataset
    out_file.create_dataset(name="traces", data=proj.waves[:], dtype=np.array(proj.waves[0]).dtype)

    # Prepare metadata dataset
    metadata_type = np.dtype([("plaintext", proj.textins[0].dtype, (len(proj.textins[0]),)),
                              ("key", proj.keys[0].dtype, (len(proj.keys[0]),)),
                              ("masks", mask.dtype, (len(mask),))])

    traces_metadata = np.array([(proj.textins[n], proj.keys[n], mask) for n in range(proj.traces.max + 1)], dtype=metadata_type)

    # Create metadata dataset
    out_file.create_dataset("metadata", data=traces_metadata, dtype=metadata_type)

    out_file.flush()
    out_file.close()
Exemple #8
0
def plot_results(plot_cfg, project_name):
    """Plots traces from `project_name` using `plot_cfg` settings."""
    project = cw.open_project(project_name)

    if len(project.waves) == 0:
        print('Project contains no traces. Did the capture fail?')
        return

    # The ADC output is in the interval [-0.5, 0.5). Check that the recorded
    # traces are within that range with some safety margin.
    if not (np.all(np.greater(project.waves, -plot_cfg["amplitude_max"]))
            and np.all(np.less(project.waves, plot_cfg["amplitude_max"]))):
        print('WARNING: Some traces have samples outside the range (' +
              str(-plot_cfg["amplitude_max"]) + ', ' +
              str(plot_cfg["amplitude_max"]) + ').')
        print('The ADC has a max range of [-0.5, 0.5) and might saturate.')
        print('It is recommended to reduce the scope gain (see device.py).')

    plot.save_plot_to_file(project.waves, plot_cfg["num_traces"],
                           plot_cfg["trace_image_filename"])
    print(
        f'Created plot with {plot_cfg["num_traces"]} traces: {Path(plot_cfg["trace_image_filename"]).resolve()}'
    )
Exemple #9
0
#!/usr/bin/python3

import chipwhisperer as cw
import chipwhisperer.analyzer as cwa
import sys
import getopt

proj = cw.open_project(sys.argv[1])
print("Project loaded...")
attack = cwa.cpa(proj, cwa.leakage_models.sbox_output)
attack.points_range = [75483, 75483 + 33206]
print("Begin CPA job")
results = attack.run()
print(results.find_maximums())
print(results.best_guesses())
# SPDX-License-Identifier: Apache-2.0
import binascii
import chipwhisperer as cw
from chipwhisperer.analyzer.attacks.attack_mix_columns import AttackMixColumns
import scared
import numpy as np

PROJECTS=[
  'projects/opentitan_simple_aes_0',
  'projects/opentitan_simple_aes_1',
  'projects/opentitan_simple_aes_2',
  'projects/opentitan_simple_aes_3',
]

print('loading projects')
projects = [cw.open_project(p) for p in PROJECTS]

attack = AttackMixColumns(projects)
results = attack.run()

known_key_bytes = projects[0].keys[0]
key_guess_bytes = results['guess']

known_key = binascii.b2a_hex(bytearray(known_key_bytes))
print('known_key: {}'.format(known_key))

key_guess = binascii.b2a_hex(bytearray(key_guess_bytes))
print('key guess: {}'.format(key_guess))

if key_guess != known_key:
  num_bytes_match = 0
Exemple #11
0
    return max_rho, rho


def bit_count(number):
    bit_count = 0
    while number:
        number &= (number - 1)
        bit_count += 1
    return bit_count


if __name__ == '__main__':

    # Open trace file.
    project_file = 'projects/opentitan_simple_aes'
    project = cw.open_project(project_file)

    num_traces = len(project.waves)
    num_samples = len(project.waves[0])

    # Create a local, dense copy of the traces. This makes the remaining
    # operations much faster.
    traces = np.empty((num_traces, num_samples_use), np.double)
    for i_trace in range(num_traces):
        traces[i_trace] = project.waves[i_trace][
            start_sample_use:stop_sample_use]

    ############################
    # Filter out noisy traces. #
    ############################
Exemple #12
0
def perform_attack(project_file, num_traces, attack_window, attack_direction,
                   max_std, num_workers):
    """Performs a correlation-enhanced power analysis collision attack.

    This function:
        - Computes the mean and standard deviation of all traces (*),
        - Filters noisy traces (*),
        - Computes mean traces for all values of all plaintext/ciphertext bytes (*),
        - Guesses differences between each key byte, and
        - Recovers the key using these differences.

    Steps marked with (*) above are implemented in a distributed manner: After
    creating ``num_workers`` number of ``TraceWorker`` instances, this function
    assigns a subset of traces to each worker and aggregates their results to be
    used in the subsequent steps of the attack.

    See "Correlation-Enhanced Power Analysis Collision Attack" by A. Moradi, O.
    Mischke, and T. Eisenbarth (https://eprint.iacr.org/2010/297.pdf) for more
    information.

    Args:
        project_file: A Chipwhisperer project file.
        num_traces: Number of traces to use, must be less than or equal to the
            number of traces in ``project_file``.
        attack_window: Attack window as a pair of sample indices, inclusive.
        attack_direction: Attack direction.
        max_std: Allowed number of standard deviations from the mean trace for
            filtering noisy traces.
        num_workers: Number of workers to use for processing traces.

    Returns:
        Recovered key if the attack was successful, ``None`` otherwise.
    """
    project = cw.open_project(project_file)

    # Check arguments
    num_total_traces = len(project.waves)
    if num_traces > num_total_traces:
        raise ValueError(
            f"Invalid num_traces: {num_traces} (must be less than {num_total_traces})"
        )
    last_sample = len(project.waves[0]) - 1
    if min(attack_window) < 0 or max(attack_window) > last_sample:
        raise ValueError(
            f"Invalid attack window: {attack_window} (must be in [0, {last_sample}])"
        )
    if max_std <= 0:
        raise ValueError(
            f"Invalid max_std: {max_std} (must be greater than zero)")
    if num_workers <= 0:
        raise ValueError(
            f"Invalid num_workers: {num_workers} (must be greater than zero)")

    # Instantiate workers
    def worker_trace_slices():
        """Determines the traces of each worker.

        Assigns the remainder, if any, to the first worker.
        """
        traces_per_worker = int(num_traces / num_workers)
        first_worker_num_traces = traces_per_worker + num_traces % num_workers
        yield slice(0, first_worker_num_traces)
        for trace_begin in range(first_worker_num_traces, num_traces,
                                 traces_per_worker):
            yield slice(trace_begin, trace_begin + traces_per_worker)

    # Attack window is inclusive.
    attack_window = slice(attack_window[0], attack_window[1] + 1)
    workers = [
        TraceWorker.remote(project_file, trace_slice, attack_window,
                           attack_direction)
        for trace_slice in worker_trace_slices()
    ]
    assert len(workers) == num_workers
    # Compute mean and standard deviation.
    mean, std_dev = compute_mean_and_std(workers)
    # Filter noisy traces.
    orig_num_traces = num_traces
    num_traces = filter_noisy_traces(workers, mean, std_dev, max_std)
    logging.info(f"Will use {num_traces} traces "
                 f"({100*num_traces/orig_num_traces:.1f}% of all traces)")
    # Mean traces for all values of all text bytes.
    mean_text_traces = compute_mean_text_traces(workers)
    # Guess the differences between key bytes.
    pairwise_diffs_scores = compute_pairwise_diffs_and_scores(mean_text_traces)
    diffs = find_best_diffs(pairwise_diffs_scores)
    logging.info(f"Difference values (delta_0_i): {diffs}")
    # Recover the key.
    key = recover_key(diffs, attack_direction, project.textins[0],
                      project.textouts[0])
    if key is not None:
        logging.info(f"Recovered AES key: {bytes(key).hex()}")
    else:
        logging.error("Failed to recover the AES key")
    # Compare differences - both matrices are symmetric and have an all-zero main diagonal.
    correct_diffs = compare_diffs(pairwise_diffs_scores, attack_direction,
                                  project.keys[0])
    logging.info(f"Recovered {((np.sum(correct_diffs)-16)/2).astype(int)}/120 "
                 "differences between key bytes")
    return key
Exemple #13
0
 def test_trace_beyond_segment(self):
     self.project = cw.open_project('test_seg')
     arr = bytearray(b'CWUNIQUESTRING2')
     for i in range(0, len(arr)):
         self.assertEqual(self.project.textins[10000][i], arr[i])
Exemple #14
0
    plt.show()
    #plt.savefig('../collections/May_18_RevisedFirmware/Key{}_wave0.png'.format(i))
    print("Key", i, "finished", "Imagin Saved")
    plt.clf()
    '''
    # convert to cvs
    for trace in proj.traces:
        append_list_as_row('../collections/May_18_RevisedFirmware/key{}_trace.csv'.format(i), trace.wave)
        append_list_as_row('../collections/May_18_RevisedFirmware/key{}_key.csv'.format(i), trace.key)
        append_list_as_row('../collections/May_18_RevisedFirmware/key{}_textin.csv'.format(i), trace.textin)
        append_list_as_row('../collections/May_18_RevisedFirmware/key{}_textout.csv'.format(i), trace.textout)
    '''
#Doing attack using CPA
results = []
for i in range(0, 32):
    proj = cw.open_project(
        "../collections/May_18_RevisedFirmware/Key_{}.cwp".format(i))

    # Attack part, makesure each key is woring fine
    attack = cwa.cpa(proj, leak_model)
    result = attack.run()
    print("Attack finshed, for Key", i, "result is:")
    print(result)
    results.append(result)
    try:
        assert (result.find_key() == proj.keys[0])
    except:
        print("result", i, "is wrong:")
        print("except:", proj.keys[0])
        print("result:", result.find_key())