{ "cells": [ { "cell_type": "markdown", "id": "fde96d6a-0281-4ba2-ae2f-447cb6a625f0", "metadata": {}, "source": [ "# Power-tracing smartcards using LEIA" ] }, { "cell_type": "code", "execution_count": null, "id": "eab24cb8-af40-4cc1-be5f-f120fe9932ee", "metadata": {}, "outputs": [], "source": [ "from pyecsca.sca.target.ectester import ECTesterTargetLEIA, KeypairEnum, ParameterEnum, CurveEnum, KeyEnum, KeyClassEnum, KeyBuildEnum, KeyAgreementEnum, SignatureEnum, TransformationEnum\n", "from pyecsca.ec.params import load_params_ectester\n", "from pyecsca.sca.scope.picoscope_sdk import PS6000Scope\n", "from pyecsca.sca.trace import Trace\n", "from pyecsca.sca.trace.plot import plot_trace, plot_traces\n", "from pyecsca.sca.scope import SampleType\n", "\n", "import numpy as np\n", "from time import sleep\n", "from smartleia import LEIA, TriggerPoints\n", "\n", "import holoviews as hv\n", "\n", "hv.extension(\"bokeh\")\n", "%opts RGB [height=700, responsive=True]" ] }, { "cell_type": "code", "execution_count": null, "id": "865953a5-35ad-473e-a57f-f26368145987", "metadata": {}, "outputs": [], "source": [ "sl = LEIA()\n", "ectester = ECTesterTargetLEIA(sl)" ] }, { "cell_type": "code", "execution_count": null, "id": "07369045-7eee-4e85-ac4e-37e5396fd880", "metadata": {}, "outputs": [], "source": [ "ectester.connect()" ] }, { "cell_type": "code", "execution_count": null, "id": "89ed5db7-fbbb-4b32-89a5-6486204feed6", "metadata": {}, "outputs": [], "source": [ "atr = ectester.atr\n", "print(atr, atr.hex())\n", "card_map = {\n", " \"3bd518ff8191fe1fc38073c8211309\": \"A1\",\n", " \"3bb89600c00831fe45ffff1154305023006a\": \"I1\",\n", " \"3bfe1800008031fe45803180664090a5102e1083019000f2\": \"I2\",\n", " \"3bf81800ff8131fe454a434f507632343143\": \"N1\",\n", " \"3bf81300008131fe454a434f5076323431b7\": \"N2N9\",\n", " \"3b9495810146545601c4\": \"N4\",\n", " \"3bd518ff8191fe1fc38073c821100a\": \"N6\",\n", " \"3b9c9580811f039067464a01005404f272fe00c0\": \"F1\",\n", " \"3b90958011fe6a\": \"F2\",\n", " \"3b9f95803fc7a08031e073fa21106300000083f09000bb\": \"S1S2\"\n", "}\n", "card = card_map.get(atr.hex(), None)\n", "print(card)" ] }, { "cell_type": "code", "execution_count": null, "id": "8c33b783-7a7e-45f4-9e91-d3df54e1abe0", "metadata": {}, "outputs": [], "source": [ "scope = PS6000Scope()" ] }, { "cell_type": "code", "execution_count": null, "id": "729688c3-d448-4d1a-80c4-666680fcca35", "metadata": {}, "outputs": [], "source": [ "scope.open()" ] }, { "cell_type": "code", "execution_count": null, "id": "23037143-e39c-4dd6-bf65-9cdcb0d7b266", "metadata": {}, "outputs": [], "source": [ "print(scope.get_variant())\n", "if card == \"A1\":\n", " # Athena IDProtect\n", " # 35M for keygen\n", " # 13M for ecdh\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=35_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.2, offset=-0.24, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"I1\":\n", " # Infineon SECORA\n", " # 6M for keygen\n", " # 3M for ecdh\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=6_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.2, offset=-0.25, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"I2\":\n", " # Infineon CJTOP SLJ 52GLA0890AL M84\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=15_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.1, offset=-0.15, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"N1\":\n", " # NXP J3A081\n", " # 30M for keygen (first), then 10M for subsequent\n", " # 10M for ecdh\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=30_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.05, offset=-0.18, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"N2N9\":\n", " # NXP JCOP v2.4.1R3\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=30_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.05, offset=-0.280, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"N4\":\n", " # NXP J3H145\n", " # 15M for keygen\n", " # 10M for ecdh\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=5_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.2, offset=-0.160, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"N6\":\n", " # NXP JCOP4\n", " # 3M for keygen\n", " # 3M for ECDH\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=3_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.2, offset=-0.170, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"F1\":\n", " # Javacos A22 CR\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=3_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.2, offset=-0.170, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "elif card == \"F2\":\n", " # Javacos JC30M48 CR\n", " actual_freq, n_samples = scope.setup_frequency(frequency=50_000_000, pretrig=0, posttrig=3_000_000)\n", " scope.setup_channel(channel=\"A\", coupling=\"DC\", range=1, offset=0, enable=True)\n", " scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.2, offset=-0.170, enable=True)\n", " scope.setup_trigger(channel=\"A\", threshold=0.2, direction=\"rising\", delay=0, timeout=5000, enable=True)\n", " scope.setup_capture(channel=\"B\", enable=True)\n", "print(actual_freq, n_samples)" ] }, { "cell_type": "code", "execution_count": null, "id": "a16af658-34d5-455e-a609-3075ede7dad7", "metadata": {}, "outputs": [], "source": [ "ectester.select_applet()" ] }, { "cell_type": "code", "execution_count": null, "id": "ee3ec16b-d9ac-4cd7-8ad5-4dfe0c0d5465", "metadata": {}, "outputs": [], "source": [ "ectester.info()" ] }, { "cell_type": "code", "execution_count": null, "id": "27c4a7f7-3029-46d9-a3d5-3f4c0b56e37e", "metadata": {}, "outputs": [], "source": [ "ectester.allocate(KeypairEnum.KEYPAIR_LOCAL,\n", " KeyBuildEnum.BUILD_KEYBUILDER | KeyBuildEnum.BUILD_KEYPAIR,\n", " 256,\n", " KeyClassEnum.ALG_EC_FP)" ] }, { "cell_type": "code", "execution_count": null, "id": "f952cf17-88f2-47d7-88f3-346c6cbd0572", "metadata": {}, "outputs": [], "source": [ "ectester.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)" ] }, { "cell_type": "code", "execution_count": null, "id": "4d67e5a3-79d3-4160-89c9-07f1cd697f52", "metadata": {}, "outputs": [], "source": [ "params = load_params_ectester(\"curves/curves_full_order/cofactor256p313_full.csv\", \"affine\")" ] }, { "cell_type": "code", "execution_count": null, "id": "94e9c2c5-d231-459a-a601-b14a123fce62", "metadata": {}, "outputs": [], "source": [ "ectester.set(KeypairEnum.KEYPAIR_LOCAL,\n", " CurveEnum.external,\n", " ParameterEnum.DOMAIN_FP,\n", " ECTesterTargetLEIA.encode_parameters(ParameterEnum.DOMAIN_FP, params))" ] }, { "cell_type": "code", "execution_count": null, "id": "8d36f397-15ca-4e4a-8a87-dee10fe4398e", "metadata": {}, "outputs": [], "source": [ "sl.set_trigger_strategy(1, point_list=[TriggerPoints.TRIG_PRE_SEND_APDU], delay=0)" ] }, { "cell_type": "code", "execution_count": null, "id": "26be2fb8-607c-4bce-8968-ba57938f9a89", "metadata": {}, "outputs": [], "source": [ "scope.arm()\n", "sleep(2)" ] }, { "cell_type": "code", "execution_count": null, "id": "83bfe8a5-00eb-4b17-8762-1ba0b07139e6", "metadata": {}, "outputs": [], "source": [ "ectester.generate(KeypairEnum.KEYPAIR_LOCAL)" ] }, { "cell_type": "code", "execution_count": null, "id": "253a00c7-28d3-4648-b5d7-9c6876f37362", "metadata": {}, "outputs": [], "source": [ "scope.capture(10000)" ] }, { "cell_type": "code", "execution_count": null, "id": "2a0836a3-9d07-444c-a4eb-a661885ff3e8", "metadata": {}, "outputs": [], "source": [ "trace_gen = scope.retrieve(\"B\", SampleType.Raw)" ] }, { "cell_type": "code", "execution_count": null, "id": "f14f244d-fee6-44a9-8858-783d7ffb9f24", "metadata": {}, "outputs": [], "source": [ "plot_trace(trace_gen)" ] }, { "cell_type": "code", "execution_count": null, "id": "08978417-6f39-4c40-a862-9ad43179dccc", "metadata": {}, "outputs": [], "source": [ "scope.arm()\n", "sleep(2)" ] }, { "cell_type": "code", "execution_count": null, "id": "f4c1df63-4da3-4693-9aaa-217e4a9314f5", "metadata": {}, "outputs": [], "source": [ "with open(\"curves/cofactor_points/point_313.csv\", \"r\") as f:\n", " line = f.read()\n", " sx, sy = line.split(\",\")\n", " bx = bytes.fromhex(sx[2:])\n", " by = bytes.fromhex(sy[2:])\n", " point = bytes([0x04]) + bx + by\n", " print(point.hex())" ] }, { "cell_type": "code", "execution_count": null, "id": "ad17301a-902f-48e9-936e-f553a1a8f006", "metadata": {}, "outputs": [], "source": [ "ectester.ecdh_direct(KeypairEnum.KEYPAIR_LOCAL,\n", " True,\n", " TransformationEnum.NONE,\n", " KeyAgreementEnum.ALG_EC_SVDP_DH,\n", " point) # pubkey as bytes" ] }, { "cell_type": "code", "execution_count": null, "id": "2282c28d-4745-43b2-b321-a34365f55753", "metadata": {}, "outputs": [], "source": [ "scope.capture(10000)" ] }, { "cell_type": "code", "execution_count": null, "id": "d0cdabb8-a4ee-4b19-a8ed-ae2e9f634a37", "metadata": {}, "outputs": [], "source": [ "trace_ecdh = scope.retrieve(\"B\", SampleType.Volt)" ] }, { "cell_type": "code", "execution_count": null, "id": "c899b299-25f5-418b-baaa-fa8e4399daa9", "metadata": {}, "outputs": [], "source": [ "plot_trace(trace_ecdh)" ] }, { "cell_type": "code", "execution_count": null, "id": "6c46be4f-8901-4b29-a30e-71ac28bafcd9", "metadata": {}, "outputs": [], "source": [ "from pyecsca.sca.trace.edit import pad, trim" ] }, { "cell_type": "code", "execution_count": null, "id": "1d4b775e-fa7d-48aa-bb24-bec7450c8114", "metadata": {}, "outputs": [], "source": [ "trim?" ] }, { "cell_type": "code", "execution_count": null, "id": "7164dab5-090f-4a6a-9ce6-8e252e71af76", "metadata": {}, "outputs": [], "source": [ "plot_traces(ecdh_ok, pad(trim(trace_ecdh, 0, len(trace_ecdh) -363700), (363700, 0)))" ] }, { "cell_type": "code", "execution_count": null, "id": "0395b2aa-3c00-4068-8179-039e7e5ad039", "metadata": {}, "outputs": [], "source": [ "from scipy import signal\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": null, "id": "1b63e6d3-8488-4c13-91fa-388318e8e1bc", "metadata": {}, "outputs": [], "source": [ "corr = signal.correlate(trace_ecdh.samples, trace_ecdh.samples, mode=\"full\")\n", "lags = signal.correlation_lags(trace_ecdh.samples.size, trace_ecdh.samples.size, mode=\"full\")\n", "lag = lags[np.argmax(corr)]\n" ] }, { "cell_type": "code", "execution_count": null, "id": "f6fbd522-c9db-4dbc-bd05-109ba3d3fdf9", "metadata": {}, "outputs": [], "source": [ "plot_trace(Trace(corr))" ] }, { "cell_type": "code", "execution_count": null, "id": "5a910cc9-80bd-4c74-a36a-56804aea42e1", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "195ed167-8925-44c9-b0fb-6e207f8fdf8a", "metadata": {}, "outputs": [], "source": [ "ectester.cleanup()" ] }, { "cell_type": "code", "execution_count": null, "id": "264b4653-023c-4a39-8970-270c2f0d42c6", "metadata": {}, "outputs": [], "source": [ "ectester.disconnect()" ] }, { "cell_type": "code", "execution_count": null, "id": "1d706782-7124-4879-8198-407e45f131ff", "metadata": {}, "outputs": [], "source": [ "scope.close()" ] }, { "cell_type": "code", "execution_count": null, "id": "768a8fe0-27ec-4678-a66a-66e7680fd6c8", "metadata": {}, "outputs": [], "source": [ "from pyecsca.sca.trace.process import rolling_mean, recenter\n", "from pyecsca.sca.trace.filter import filter_lowpass" ] }, { "cell_type": "code", "execution_count": null, "id": "d93ce9cd-1516-4e32-9fed-94a19fac23f4", "metadata": {}, "outputs": [], "source": [ "from pyecsca.sca.trace.plot import plot_trace, plot_traces" ] }, { "cell_type": "code", "execution_count": null, "id": "45f2a8ab-af15-46f9-904e-76e5eeb08978", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }