Skip to content

Commit a18ddf9

Browse files
committed
feat: analysis
1 parent 37c43cb commit a18ddf9

26 files changed

+39778
-24
lines changed

analyze_fuzzing.ipynb

Lines changed: 1740 additions & 0 deletions
Large diffs are not rendered by default.

estk_playground.ipynb

Lines changed: 397 additions & 0 deletions
Large diffs are not rendered by default.

fuzz_playground.ipynb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "4dd067df",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": []
10+
}
11+
],
12+
"metadata": {
13+
"language_info": {
14+
"name": "python"
15+
}
16+
},
17+
"nbformat": 4,
18+
"nbformat_minor": 5
19+
}

get_challenge_playground.ipynb

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 48,
6+
"metadata": {},
7+
"outputs": [
8+
{
9+
"name": "stdout",
10+
"output_type": "stream",
11+
"text": [
12+
"ISDR not found on card\n"
13+
]
14+
},
15+
{
16+
"ename": "SystemExit",
17+
"evalue": "1",
18+
"output_type": "error",
19+
"traceback": [
20+
"An exception has occurred, use %tb to see the full traceback.\n",
21+
"\u001b[0;31mSystemExit\u001b[0m\u001b[0;31m:\u001b[0m 1\n"
22+
]
23+
},
24+
{
25+
"name": "stderr",
26+
"output_type": "stream",
27+
"text": [
28+
"/home/niklas/Documents/documents/uni/master_thesis/resimulate/.venv/lib/python3.13/site-packages/IPython/core/interactiveshell.py:3587: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n",
29+
" warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n"
30+
]
31+
}
32+
],
33+
"source": [
34+
"import logging\n",
35+
"import math\n",
36+
"import operator\n",
37+
"from collections import Counter\n",
38+
"from pprint import pprint\n",
39+
"\n",
40+
"import numpy as np\n",
41+
"import scipy.stats as stats\n",
42+
"from pySim.euicc import CardApplicationISDR, GetEuiccChallenge\n",
43+
"from pySim.transport.pcsc import PcscSimLink\n",
44+
"from statsmodels.sandbox.stats.runs import runstest_1samp\n",
45+
"from tqdm.notebook import tqdm\n",
46+
"\n",
47+
"from resimulate.card import Card\n",
48+
"from resimulate.util.enums import ISDR_AID\n",
49+
"\n",
50+
"logger = logging.getLogger()\n",
51+
"logger.setLevel(logging.CRITICAL)\n",
52+
"\n",
53+
"received_challenges: list[str] = []\n",
54+
"\n",
55+
"with PcscSimLink(apdu_tracer=None) as link:\n",
56+
" card = Card(link)\n",
57+
" initialized_card = card.init_card(target_isd_r=ISDR_AID.DEFAULT)\n",
58+
" isd_r = card.runtime_state.mf.applications.get(ISDR_AID.DEFAULT.value.lower(), None)\n",
59+
"\n",
60+
" if not isd_r:\n",
61+
" print(\"ISDR not found on card\")\n",
62+
" raise SystemExit(1)\n",
63+
"\n",
64+
" card.runtime_state.lchan[0].select_file(isd_r)\n",
65+
" card.runtime_state.identity[\"EID\"] = CardApplicationISDR.get_eid(\n",
66+
" card.sim_card_commands\n",
67+
" )\n",
68+
" for _ in tqdm(range(50000)):\n",
69+
" challenge = CardApplicationISDR.store_data_tlv(\n",
70+
" card.sim_card_commands, GetEuiccChallenge(), GetEuiccChallenge\n",
71+
" ).to_dict()[\"get_euicc_challenge\"][0][\"euicc_challenge\"]\n",
72+
" received_challenges.append(challenge)\n",
73+
"\n",
74+
"\n",
75+
"def entropy(data):\n",
76+
" \"\"\"Calculate Shannon entropy for byte sequences\"\"\"\n",
77+
" counts = Counter(data)\n",
78+
" total = len(data)\n",
79+
" return -sum((count / total) * math.log2(count / total) for count in counts.values())\n",
80+
"\n",
81+
"\n",
82+
"def test_randomness(byte_strings) -> tuple[np.float64, np.float64, np.float64, float]:\n",
83+
" # Convert hex/base64/raw strings to bytes\n",
84+
" byte_arrays = [\n",
85+
" bytes.fromhex(s)\n",
86+
" if all(c in \"0123456789abcdefABCDEF\" for c in s)\n",
87+
" else s.encode()\n",
88+
" for s in byte_strings\n",
89+
" ]\n",
90+
"\n",
91+
" # Flatten to a single byte sequence\n",
92+
" all_bytes = np.concatenate([np.frombuffer(b, dtype=np.uint8) for b in byte_arrays])\n",
93+
"\n",
94+
" # Chi-Square Test for Byte Uniformity\n",
95+
" byte_counts = np.bincount(\n",
96+
" all_bytes, minlength=256\n",
97+
" ) # Count occurrences of each byte (0-255)\n",
98+
" expected = np.full_like(byte_counts, np.mean(byte_counts))\n",
99+
" chi2_stat, p_chi2 = stats.chisquare(byte_counts, expected)\n",
100+
"\n",
101+
" # Shannon Entropy\n",
102+
" byte_counts = np.bincount(all_bytes, minlength=256)\n",
103+
" probabilities = byte_counts / all_bytes.size\n",
104+
" entropy_value = stats.entropy(probabilities, base=2) # entropy(all_bytes)\n",
105+
"\n",
106+
" # Monobit Test (Balance of 0s and 1s)\n",
107+
" bit_string = \"\".join(format(byte, \"08b\") for byte in all_bytes)\n",
108+
" ones = bit_string.count(\"1\")\n",
109+
" zeros = bit_string.count(\"0\")\n",
110+
" monobit_p = stats.binomtest(ones, len(bit_string), p=0.5)\n",
111+
"\n",
112+
" # Runs Test on Byte Sequences\n",
113+
" z_stat, p_runs = runstest_1samp(all_bytes)\n",
114+
"\n",
115+
" return (\n",
116+
" round(p_chi2, 6),\n",
117+
" round(entropy_value, 6),\n",
118+
" round(monobit_p.pvalue, 6),\n",
119+
" round(p_runs, 6),\n",
120+
" )\n",
121+
"\n",
122+
"\n",
123+
"def within_margin(value, target, margin, op: operator) -> bool:\n",
124+
" lower_bound = target - margin\n",
125+
" upper_bound = target + margin\n",
126+
" return op(value, lower_bound) or op(value, upper_bound)\n",
127+
"\n",
128+
"\n",
129+
"p_chi2, entropy_value, pvalue, p_runs = test_randomness(received_challenges)\n",
130+
"\n",
131+
"if within_margin(p_chi2, 0.05, 0.01, operator.lt):\n",
132+
" print(f\"Chi-Square Test: Non-uniform distribution of bytes! ({p_chi2})\")\n",
133+
"if entropy_value < 8:\n",
134+
" print(f\"Shannon Entropy: Low randomness! ({entropy_value})\")\n",
135+
"if within_margin(pvalue, 0.05, 0.01, operator.lt):\n",
136+
" print(f\"Monobit Test: Bias in bits! ({pvalue})\")\n",
137+
"if within_margin(p_runs, 0.05, 0.01, operator.lt):\n",
138+
" print(f\"Runs Test: Sequential patterns! ({p_runs})\")\n",
139+
"\n",
140+
"pprint(\n",
141+
" {\n",
142+
" \"Chi-Square Test p-value\": str(p_chi2), # <0.05 means not uniform/random\n",
143+
" \"Shannon Entropy\": str(entropy_value), # ~8 means high randomness\n",
144+
" \"Monobit Test p-value\": str(pvalue), # <0.05 means bias in bits\n",
145+
" \"Runs Test p-value\": str(p_runs), # <0.05 means sequential patterns\n",
146+
" }\n",
147+
")\n"
148+
]
149+
}
150+
],
151+
"metadata": {
152+
"kernelspec": {
153+
"display_name": ".venv",
154+
"language": "python",
155+
"name": "python3"
156+
},
157+
"language_info": {
158+
"codemirror_mode": {
159+
"name": "ipython",
160+
"version": 3
161+
},
162+
"file_extension": ".py",
163+
"mimetype": "text/x-python",
164+
"name": "python",
165+
"nbconvert_exporter": "python",
166+
"pygments_lexer": "ipython3",
167+
"version": "3.13.3"
168+
}
169+
},
170+
"nbformat": 4,
171+
"nbformat_minor": 2
172+
}

0 commit comments

Comments
 (0)