diff options
| -rw-r--r-- | analysis/countermeasures/README.md | 19 | ||||
| -rw-r--r-- | analysis/countermeasures/collect_leia.ipynb | 194 | ||||
| -rw-r--r-- | analysis/countermeasures/combinations.ipynb | 54 | ||||
| -rw-r--r-- | analysis/countermeasures/measure.ipynb | 18 | ||||
| -rw-r--r-- | analysis/countermeasures/simulate.ipynb (renamed from analysis/countermeasures/simulation.ipynb) | 4 |
5 files changed, 200 insertions, 89 deletions
diff --git a/analysis/countermeasures/README.md b/analysis/countermeasures/README.md index 3056584..dc94a4d 100644 --- a/analysis/countermeasures/README.md +++ b/analysis/countermeasures/README.md @@ -25,6 +25,8 @@ The general structure is as follows: scalar randomization countermeasures under our tests (Test 3n, Test composite, Test k=10, Test n + e). This notebook also implements mask recovery for the two countermeasures where we are able to do so: GSR and multiplicative. + - `combinations.ipynb`: A Jupyter notebook that contains simulations of the behavior of combinations + of scalar randomization countermeasures. - `measure.ipynb`: A Jupyter notebook that runs our tests on a given JavaCard by interacting with the ECTester applet installed on it. - `results.ipynb`: A Jupyter notebook that evaluates the results of tests run (by the `measure` notebook) @@ -58,9 +60,8 @@ are described in the [main README](../../README.md) in section **Setup**. Please steps to build ECTester components. Note that, the standalone tool has additional setup instructions in the README. -Optionally, you can download pre-built versions of the applet and reader tool from our CI -or releases. However, the standalone tool is dependent on the ECC library versions it targets and thus -a version built in CI may be useless/not work for you. +Optionally, you can download pre-built versions of the applet and reader tool from our [CI](https://nightly.link/crocs-muni/ECTester/workflows/build/master) or releases. However, the standalone tool is dependent on +the ECC library versions it targets and thus a version built in CI may be useless/not work for you. ### Python @@ -93,6 +94,7 @@ data collection for our tests. from smartcards or those you produced in the previous step. 4. You can "play around" with the standalone tool and observe test results on ECC libraries. +5. You can examine the behavior of combinations of countermeasures under our tests. See subsections below for more details. @@ -101,7 +103,7 @@ See subsections below for more details. > This step supports *Section 6* of the paper, mainly Table 4. -1. Run the `simulation.ipynb` notebook. +1. Run the `simulate.ipynb` notebook. 2. Examine the test results and how they correspond to Table 4. @@ -112,7 +114,7 @@ See subsections below for more details. Note that, this step is not necessary, is time consuming and requires access to suitable JavaCard smartcards (which it may permanently destroy). -1. Build applet for correct platform version: +1. Build applet for correct platform version. 2. Install applet (e.g. gp-pro) 3. Run `measure.ipynb` notebook. @@ -134,7 +136,10 @@ required manual effort in evaluating and understanding the results provided by the test-suites. Thus, we do not provide a script or a guide here, merely point towards the standalone tool and its documentation in the main README. +### Combinations of countermeasures -## Cards +> This step supports (part of) *Section 7* and *the appendix* of the paper. + +1. Run `combinations.ipynb` notebook. +2. Examine how the results correspond to Table 7 in the appendix. -TODO: card summary identification diff --git a/analysis/countermeasures/collect_leia.ipynb b/analysis/countermeasures/collect_leia.ipynb index 4399c47..5cdbd51 100644 --- a/analysis/countermeasures/collect_leia.ipynb +++ b/analysis/countermeasures/collect_leia.ipynb @@ -5,7 +5,11 @@ "id": "fde96d6a-0281-4ba2-ae2f-447cb6a625f0", "metadata": {}, "source": [ - "# Power-tracing smartcards using LEIA" + "# Power-tracing smartcards using LEIA\n", + "\n", + "This notebook uses [**pyecsca**](https://pyecsca.org) and a [LEIA board](https://github.com/h2lab/smartleia) to do simple (SPA-like) power-tracing of selected smartcard targets. It assumess the user has a PicoScope 6000 oscilloscope (though this can be replaced by any oscilloscope that **pyecsca** supports). Similarly, the LEIA board can be replaced by simple smartcard reader, though the user then need a separate way of triggering the scope. The code also assumes the ECTester applet is already installed on the target cards. Use a tool like [GlobalPlatformPro](https://github.com/martinpaljak/GlobalPlatformPro) to install it.\n", + "\n", + "See the [pyecsca notebook](https://pyecsca.org/notebook/measurement.html) on measurement for more examples." ] }, { @@ -46,6 +50,14 @@ ] }, { + "cell_type": "markdown", + "id": "6951ffd4-b442-4180-b278-692950b1979a", + "metadata": {}, + "source": [ + "Create the LEIA interface and ECTester target." + ] + }, + { "cell_type": "code", "execution_count": null, "id": "865953a5-35ad-473e-a57f-f26368145987", @@ -57,6 +69,15 @@ ] }, { + "cell_type": "markdown", + "id": "99aa64e8-2534-4db7-8cc5-73268bafa884", + "metadata": {}, + "source": [ + "## Initialize scope and card\n", + "Connect to the card and setup the scope/measurement parameters based on it." + ] + }, + { "cell_type": "code", "execution_count": null, "id": "07369045-7eee-4e85-ac4e-37e5396fd880", @@ -81,11 +102,15 @@ " \"3bfe1800008031fe45803180664090a5102e1083019000f2\": \"I2\",\n", " \"3bf81800ff8131fe454a434f507632343143\": \"N1\",\n", " \"3bf81300008131fe454a434f5076323431b7\": \"N2N9\",\n", - " \"3b9495810146545601c4\": \"N4\",\n", - " \"3bd518ff8191fe1fc38073c821100a\": \"N6\",\n", + " \"3b9495810146545601c4\": \"N4N10\",\n", + " \"3bd518ff8191fe1fc38073c821100a\": \"N6N11\",\n", + " \"3bf91300008131fe454a434f503234325233a2\":\"N8\",\n", " \"3b9c9580811f039067464a01005404f272fe00c0\": \"F1\",\n", - " \"3b90958011fe6a\": \"F2\",\n", - " \"3b9f95803fc7a08031e073fa21106300000083f09000bb\": \"S1S2\"\n", + " \"3b90958011fe6a\": \"F2F3\",\n", + " \"3b9f95803fc7a08031e073fa21106300000083f09000bb\": \"S1S2\",\n", + " \"3bf99600008131fe4553434537200e00202028\":\"G1\",\n", + " \"3bfe1800008031fe4553434536302d43443038312d6e46a9\": \"G2\",\n", + " \"3b959540ffae01030000\":\"E2\",\n", "}\n", "card = card_map.get(atr.hex(), None)\n", "print(card)" @@ -167,7 +192,7 @@ " #scope.setup_channel(channel=\"B\", coupling=\"DC_50\", range=0.1, 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 == \"N4\":\n", + "elif card == \"N4N10\":\n", " # NXP J3H145\n", " # 15M for keygen\n", " # 10M for ecdh\n", @@ -176,7 +201,7 @@ " 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", + "elif card == \"N6N11\":\n", " # NXP JCOP4\n", " # 3M for keygen\n", " # 3M for ECDH\n", @@ -192,13 +217,15 @@ " 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", + "elif card == \"F2F3\":\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", + "else:\n", + " print(\"Unkown card, set the appropriate parameters manually.\")\n", "print(actual_freq, n_samples)" ] }, @@ -227,7 +254,10 @@ "id": "088f806f-63ad-432a-a654-0d8a7d857187", "metadata": {}, "source": [ - "## Allocate" + "## Allocate\n", + "Allocate a keypair and the signature + key exchange objects on the card.\n", + "\n", + "If any of these fail. Try running `ectester.cleanup()` which frees some memory on the card." ] }, { @@ -268,7 +298,9 @@ "id": "74a56989-91e7-44c8-ba9c-4c387c41de86", "metadata": {}, "source": [ - "## Set params" + "## Set params\n", + "\n", + "Set a curve (domain parameters) on the keypair on the card." ] }, { @@ -278,8 +310,10 @@ "metadata": {}, "outputs": [], "source": [ - "#params = get_params(\"secg\", \"secp256r1\", \"affine\")\n", - "params = load_params_ectester(\"../countermeasures/countermeasures/tests/comb/cofactor256p18446744073709551617_smallgen_fakeorder.csv\", \"affine\")" + "params = get_params(\"secg\", \"secp256r1\", \"affine\")\n", + "\n", + "# or set parameters that will lead to EPA issues\n", + "# params = load_params_ectester(\"../countermeasures/countermeasures/tests/comb/cofactor256p18446744073709551617_smallgen_fakeorder.csv\", \"affine\")" ] }, { @@ -296,6 +330,14 @@ ] }, { + "cell_type": "markdown", + "id": "e9e6a1a7-3d06-44eb-b247-274e0554b1ed", + "metadata": {}, + "source": [ + "Enable the LEIA trigger on APDU send." + ] + }, + { "cell_type": "code", "execution_count": null, "id": "8d36f397-15ca-4e4a-8a87-dee10fe4398e", @@ -310,7 +352,8 @@ "id": "7cd21c6a-e741-4e60-98ae-f7f58fa70a02", "metadata": {}, "source": [ - "## Generate" + "## Generate\n", + "Generate a keypair and capture a trace of it." ] }, { @@ -375,61 +418,12 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "e6a835a5-5904-4ec4-891a-ea4b2a57f1c9", - "metadata": {}, - "outputs": [], - "source": [ - "def find_bumps(trace):\n", - " ds = downsample_average(trace, 1000)\n", - " ts = threshold(ds, 0.025)\n", - " prev = 0\n", - " previ = 0\n", - " total = []\n", - " big = []\n", - " for i, sample in enumerate(ts.samples):\n", - " if prev == 0 and sample == 1:\n", - " dist = i - previ\n", - " if dist > 2500 and total:\n", - " big.append(total)\n", - " total = []\n", - " if dist > 500:\n", - " l = [i]\n", - " total.append(l)\n", - " else:\n", - " total[-1].append(i)\n", - " previ = i\n", - " prev = sample\n", - " elif prev == 1 and sample == 0:\n", - " prev = sample\n", - " if total:\n", - " big.append(total)\n", - " s = []\n", - " for t in big:\n", - " seq = []\n", - " for l in t:\n", - " seq.append(str(len(l)))\n", - " s.append(\",\".join(seq))\n", - " return \"-\".join(s)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3bfb4b6b-f44d-43a4-b52f-fad6f978c301", - "metadata": {}, - "outputs": [], - "source": [ - "find_bumps(trace_gen)" - ] - }, - { "cell_type": "markdown", "id": "f795ea2f-c244-435f-b040-9c7e9ef9debd", "metadata": {}, "source": [ - "## Or set key" + "## Or set key\n", + "Capture a trace of the set-key operation on the keypair. This is interesting as some precomputation may happen." ] }, { @@ -503,7 +497,8 @@ "id": "2037aa6a-3533-4f20-b618-154aa040892c", "metadata": {}, "source": [ - "## ECDSA" + "## ECDSA\n", + "Perform an ECDSA signature and capture a trace of it." ] }, { @@ -566,7 +561,8 @@ "id": "78f9c17b-c195-4c70-a5b7-79337de3112a", "metadata": {}, "source": [ - "## ECDH" + "## ECDH\n", + "Perform ECDH and capture a trace of it." ] }, { @@ -626,10 +622,11 @@ }, { "cell_type": "markdown", - "id": "309e8d83-771b-4783-9bb5-474c9d5bf8ec", + "id": "cadca3b4-2cd9-4dab-a900-18fe90a7cbe6", "metadata": {}, "source": [ - "## Misc" + "## Cleanup\n", + "Cleanup some memory on the card, disconnect from it and the scope." ] }, { @@ -664,6 +661,65 @@ }, { "cell_type": "markdown", + "id": "309e8d83-771b-4783-9bb5-474c9d5bf8ec", + "metadata": {}, + "source": [ + "## Misc\n", + "Some miscellaneous remains of previous experiments: 🪦" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6a835a5-5904-4ec4-891a-ea4b2a57f1c9", + "metadata": {}, + "outputs": [], + "source": [ + "def find_bumps(trace):\n", + " ds = downsample_average(trace, 1000)\n", + " ts = threshold(ds, 0.025)\n", + " prev = 0\n", + " previ = 0\n", + " total = []\n", + " big = []\n", + " for i, sample in enumerate(ts.samples):\n", + " if prev == 0 and sample == 1:\n", + " dist = i - previ\n", + " if dist > 2500 and total:\n", + " big.append(total)\n", + " total = []\n", + " if dist > 500:\n", + " l = [i]\n", + " total.append(l)\n", + " else:\n", + " total[-1].append(i)\n", + " previ = i\n", + " prev = sample\n", + " elif prev == 1 and sample == 0:\n", + " prev = sample\n", + " if total:\n", + " big.append(total)\n", + " s = []\n", + " for t in big:\n", + " seq = []\n", + " for l in t:\n", + " seq.append(str(len(l)))\n", + " s.append(\",\".join(seq))\n", + " return \"-\".join(s)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3bfb4b6b-f44d-43a4-b52f-fad6f978c301", + "metadata": {}, + "outputs": [], + "source": [ + "find_bumps(trace_gen)" + ] + }, + { + "cell_type": "markdown", "id": "a5ed4ed6-7732-41a6-b6a9-61e76851f468", "metadata": {}, "source": [ @@ -782,7 +838,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.13.5" } }, "nbformat": 4, diff --git a/analysis/countermeasures/combinations.ipynb b/analysis/countermeasures/combinations.ipynb index cd07889..9fcba68 100644 --- a/analysis/countermeasures/combinations.ipynb +++ b/analysis/countermeasures/combinations.ipynb @@ -1,6 +1,22 @@ { "cells": [ { + "cell_type": "markdown", + "id": "65d4a44b-b1f1-4a24-aed3-a7f12eb263a2", + "metadata": {}, + "source": [ + "# Simulation of countermeasure combinations\n", + "\n", + "This notebook contains simulation of combinations of countermeasures and their behavior under our tests:\n", + " - [GSR + Add](#GSR-+-Add)\n", + " - [GSR + Mul](#GSR-+-Mul)\n", + " - [GSR + Euclid](#GSR-+-Euclid)\n", + " - [Add + Mul](#Add-+-Mul)\n", + " - [Add + Euclid](#Add-+-Euclid)\n", + " - [Mul + Euclid](#Mul-+-Euclid)" + ] + }, + { "cell_type": "code", "execution_count": null, "id": "50a9e566", @@ -172,6 +188,14 @@ ] }, { + "cell_type": "markdown", + "id": "4084e4ca-e375-4c3e-8ba9-37387a7ab8f9", + "metadata": {}, + "source": [ + "Let's initialize some useful objects first." + ] + }, + { "cell_type": "code", "execution_count": null, "id": "03ab7450", @@ -185,6 +209,7 @@ "ltr = LTRMultiplier(add, dbl, complete=False)\n", "rtl = RTLMultiplier(add, dbl, complete=False)\n", "mult = ltr\n", + "\n", "gsr = GroupScalarRandomization(mult)\n", "gsr160 = GroupScalarRandomization(mult, 160)\n", "asplit = AdditiveSplitting(mult)\n", @@ -194,6 +219,14 @@ ] }, { + "cell_type": "markdown", + "id": "0366cb95-f70d-42ec-91d5-4681a86b40e1", + "metadata": {}, + "source": [ + "In the 3n test the target is given domain parameters of order $3n$ but claimed order $n$. The target is then given a point of order $3n$ for scalar multiplication and the results are observed." + ] + }, + { "cell_type": "code", "execution_count": null, "id": "ef143ca2", @@ -551,7 +584,7 @@ "id": "32da4f70", "metadata": {}, "source": [ - "## GSR + Mult" + "### GSR + Mul" ] }, { @@ -1513,7 +1546,7 @@ "id": "a4d14a41", "metadata": {}, "source": [ - "### Add+Mul" + "### Add + Mul" ] }, { @@ -1735,7 +1768,7 @@ "id": "82876bb4", "metadata": {}, "source": [ - "### Add + Eucl" + "### Add + Euclid" ] }, { @@ -1987,13 +2020,20 @@ ] }, { + "cell_type": "markdown", + "id": "68dd0555-e536-4c55-814a-b13e8d8e8349", + "metadata": {}, + "source": [ + "### Mul + Euclid" + ] + }, + { "cell_type": "code", "execution_count": null, "id": "3afaaa43", "metadata": {}, "outputs": [], "source": [ - " \n", "@public\n", "class Mul_Eucl_1(ScalarMultiplierCountermeasure):\n", " r\"\"\"\n", @@ -2233,9 +2273,9 @@ ], "metadata": { "kernelspec": { - "display_name": "env", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "env" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -2247,7 +2287,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.13.5" } }, "nbformat": 4, diff --git a/analysis/countermeasures/measure.ipynb b/analysis/countermeasures/measure.ipynb index 8647d23..2e963f1 100644 --- a/analysis/countermeasures/measure.ipynb +++ b/analysis/countermeasures/measure.ipynb @@ -5,7 +5,9 @@ "id": "41f6e89a", "metadata": {}, "source": [ - "# Countermeasure tests" + "# Card measurement for tests\n", + "\n", + "This notebook contains the code used to obtain measurements from the ECTester applet running on the target smartcards. These measurement results can then be used by the [results.ipynb](results.ipynb) notebook which interprets them." ] }, { @@ -27,6 +29,14 @@ ] }, { + "cell_type": "markdown", + "id": "17e494b2-ca35-4cd7-84b5-d797c4a61bc1", + "metadata": {}, + "source": [ + "Here, you need to select a reader out of those PCSC sees. " + ] + }, + { "cell_type": "code", "execution_count": null, "id": "668d391e", @@ -1575,9 +1585,9 @@ ], "metadata": { "kernelspec": { - "display_name": "env", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "env" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1589,7 +1599,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.13.5" } }, "nbformat": 4, diff --git a/analysis/countermeasures/simulation.ipynb b/analysis/countermeasures/simulate.ipynb index 10549c0..0eb032a 100644 --- a/analysis/countermeasures/simulation.ipynb +++ b/analysis/countermeasures/simulate.ipynb @@ -5,7 +5,7 @@ "id": "bafc2f4e-05a3-4120-bcd6-5d1f5fb91cd9", "metadata": {}, "source": [ - "# Distinguishing countermeasures by output\n", + "# Simulation of countermeasures\n", "\n", "This notebook contains simulations of scalar randomization countermeasures acting under the five tests:\n", " - [The 3n test](#3n-test)\n", @@ -3210,7 +3210,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.13.5" } }, "nbformat": 4, |
