CCTV-based smart parking systems capture and transmit video without any cryptographic verification. An attacker with access to the local network or storage can silently inject fake frames, delete real frames, or alter metadata — and existing systems have no way to detect it. Raw video transmitted to the cloud further introduces MITM risk and violates user privacy.
Every captured frame is cryptographically hashed using SHA-256. Each hash is chained to the previous, forming a tamper-evident ledger that runs entirely on the Jetson Nano edge device. The integrity mechanism anchors only SHA-256 hashes and detection metadata to AWS DynamoDB for remote verification — data minimisation on the integrity path. (JPEG frame upload to S3 is a separate, configurable operational feature used here for the dashboard/audit; it is not required for integrity verification.)
RO1 — Design a 3-layer security framework (edge detection, hash chain, cloud anchor) for IoT parking.
RO2 — Implement a lightweight blockchain on resource-constrained hardware without consensus overhead.
RO3 — Validate against 10 defined attack scenarios with statistical rigour (n≥30, CLT, 95% CI). Status: 9 conducted (E1–E9); E10 pending its field session.
RO4 — Quantify performance overhead and assess system sustainability over a 24-hour protocol. Status: met — 23.22 h between first and last sample, 30 samples, no memory leak or CPU drift.
Full blockchain consensus (proof-of-work, proof-of-stake) is infeasible on constrained hardware. This work implements a consensus-free SHA-256 hash chain with cloud anchoring on an ARM Cortex-A57 (Jetson Nano) and measures what it does and does not achieve, with n=30 per experiment.
What the measurements support. Tampering that leaves the chain internally inconsistent is detected without exception (E1–E5, E8, E9: 100%, 30/30 each), at a cost the platform absorbs comfortably — no statistically significant CPU overhead, 12,161 hashes/s, O(n) verification, and no memory leak over a 24-hour run.
What they do not. An attacker who recomputes hashes after tampering leaves a self-consistent chain: replay detection is 53.3% (E6) and local chain-rewrite detection is 0% by design (E7). The cloud anchor is architecturally the right answer to both, but as currently built it is not an independent witness — the device holds the credentials that write it, and its anchored_at timestamp is device-generated. Making the checkpoint store append-only and its timestamps server-derived is therefore the load-bearing next step, not an optional hardening.
CPU: ARM Cortex-A57 quad-core @ 1.43 GHz
RAM: 4 GB LPDDR4
Storage: 128 GB eMMC
OS: Ubuntu 18.04 LTS (headless mode)
Access: SSH via VPN tunnel
Python: 3.8 · OpenCV 4.11 · hashlib · boto3 1.37 · psutil 7.2
Table: DynamoDB checkpoint table
Partition key: block_index (String)
Attributes: block_hash, block_index, timestamp, device_id
Consistency: Strong read (boto3)
Region: us-east-1 (N. Virginia)
Access: AWS CLI configured on Jetson · IAM role with DynamoDB PutItem/GetItem
| CPU | ARM Cortex-A57 · Quad-core · 1.43 GHz |
| GPU | NVIDIA Maxwell · 128 CUDA cores |
| RAM | 4 GB LPDDR4 |
| Storage | 128 GB eMMC |
| OS | Ubuntu 18.04 LTS |
| Python | 3.8 |
| OpenCV 4.11 | Frame capture, Canny detection, ROI masking |
| boto3 1.37 | AWS S3 + DynamoDB integration |
| SciPy 1.10 | t-test, linear regression, statistics |
| psutil 7.2 | CPU and RAM monitoring |
| SQLite3 | Local blockchain persistence (chain.db) |
| hashlib | SHA-256 cryptographic hashing |
14 parking slots defined manually using roi_selector.py. Polygon coordinates saved to rois.json. Updated without modifying detection code whenever camera moves.
Fixed interval of 5 seconds — not status-change-only. Eliminates temporal gaps in the hash chain that would allow undetected feed substitution.
| Field | Description |
|---|---|
| block_index | Sequential position in chain |
| timestamp | UTC time (ISO 8601) |
| frame_hash | SHA-256 of JPEG frame |
| detection_result | Parking status per slot |
| previous_hash | Hash of preceding block |
| block_hash | SHA-256 of all above fields |
10 attack scenarios (E1–E10) mapped one-to-one onto 10 attack vectors, AV-01 to AV-10. 30 trials each for E1–E9; E10 is pending a field session (n=0). Covers: frame modification, deletion, injection, metadata tampering, hash alteration, replay, chain rewrite, feed substitution, timestamp manipulation, physical spoofing.
P1 — Security overhead (CPU/RAM/FPS) · P2 — Hash throughput (h/s) · P3 — Verification scaling O(n) · P4 — 24-hour stability. All with n≥30, 95% CI, paired t-test where applicable.
Paired t-test (P1), Wilson score CI (detection rates), linear regression with R² (P3, E7, P4), 95% confidence intervals on all metrics. A total of 390 measured data points across the 13 experiments with data (E10 has n=0, pending its field session).
| Exp | Name | n | Detection Rate | Mean Latency | SD | 95% CI | Min | Max | Result |
|---|---|---|---|---|---|---|---|---|---|
| E1 | Frame modification | 30 | 100% (30/30) | 16.15 ms | 11.28 | [12.11, 20.18] | 1.08 ms | 36.38 ms | TARGET MET |
| E2 | Frame deletion | 30 | 100% (30/30) | 20.16 ms | 15.28 | [14.70, 25.63] | 1.39 ms | 38.93 ms | TARGET MET |
| E3 | Frame injection | 30 | 100% (30/30) | 20.23 ms | 15.29 | [14.76, 25.70] | 1.19 ms | 38.39 ms | TARGET MET |
| E4 | Metadata tampering | 30 | 100% (30/30) | 18.43 ms | 11.99 | [14.14, 22.72] | 0.36 ms | 39.47 ms | TARGET MET |
| E5 | Hash record alteration | 30 | 100% (30/30) | 20.27 ms | 12.03 | [15.97, 24.58] | 2.26 ms | 39.40 ms | TARGET MET |
| E6 | Replay attack (4 scenarios) | 30 | 53.3% (16/30) | 40.25 ms | 2.94 | [39.20, 41.30] | 38.98 ms | 55.48 ms | NOT MET |
| E7 | Chain rewrite (K=10–1000 blocks) | 30 | 0% local (cloud not measured) | 13.40 ms | 15.09 | [8.00, 18.80] | 0.40 ms | 40.30 ms | BY DESIGN |
| E8 | Feed substitution | 30 | 100% (30/30) | 38.95 ms | 0.39 | [38.81, 39.09] | 38.26 ms | 39.83 ms | TARGET MET |
| E9 | Timestamp manipulation | 30 | 100% (30/30) | 16.14 ms | 11.12 | [12.16, 20.12] | 1.13 ms | 36.34 ms | TARGET MET |
| E10 | Physical sensor spoofing | 0 | — | — | — | — | — | — | PENDING FIELD SESSION |
Sequential verification means beginning deletions are found fastest. Deletion near end requires traversing nearly the whole chain first.
Scenarios A and B keep the original block_hash while block_index and previous_hash change, so self-integrity fails and they are always caught. Scenarios C and D recompute block_hash after replaying, leaving an internally consistent chain that local verification cannot distinguish from a legitimate append — neither is detected.
Linear relationship confirms O(K) rewrite complexity at 0.0393 ms/block. Note this makes rewriting cheap, not expensive — ~40 ms for 1,000 blocks — so rewrite latency is not a deterrent. No desktop comparison was run.
| K (blocks) | Trials | Rewrite Time (ms) | Post-Rewrite Verify (ms) | Detected Locally |
|---|---|---|---|---|
| 10 | 6 | 0.49 ± 0.06 | 39.36 | 0/6 |
| 50 | 6 | 2.43 ± 0.57 | 39.19 | 0/6 |
| 100 | 6 | 4.35 ± 0.29 | 39.00 | 0/6 |
| 500 | 6 | 20.17 ± 0.46 | 38.79 | 0/6 |
| 1000 | 6 | 39.58 ± 0.48 | 38.72 | 0/6 |
30 paired measurements: 1 minute without blockchain, then 1 minute with blockchain. Same hardware, same stream, same conditions.
| Metric | Without BC | With BC | Overhead | 95% CI |
|---|---|---|---|---|
| CPU (%) | 11.6 ± 18.1 | 3.6 ± 12.7 | −7.99% | [−16.21, +0.22] |
| RAM (MB) | — | — | +0.06 MB | [−0.05, +0.17] |
| FPS | 19.95 ± 0.002 | 14.64 ± 1.30 | −5.31 | [−5.79, −4.82] |
Each run hashes 1,000 frames and measures total time; 30 runs (benchmark_hash.csv).
| Condition | Mean h/s | SD | 95% CI | Per-hash (ms) |
|---|---|---|---|---|
| All runs (n=30) | 12,160.71 | 38.20 | [12,147.04, 12,174.38] | 0.082 |
| Min run | 12,037.43 | — | — | 0.083 |
| Max run | 12,204.76 | — | — | 0.082 |
6 runs each for 5 chain lengths (100, 500, 1,000, 5,000, 10,000 blocks). Linear regression proves O(n) scaling.
| Chain Length (n) | Runs | Mean Verify Time | SD | 95% CI | Per-block (ms) | RAM during (MB) |
|---|---|---|---|---|---|---|
| 100 blocks | 6 | 3.995 ms | 0.145 | [3.879, 4.111] | 0.0400 | — |
| 500 blocks | 6 | 19.548 ms | 0.273 | [19.330, 19.766] | 0.0391 | — |
| 1,000 blocks | 6 | 39.352 ms | 0.409 | [39.025, 39.679] | 0.0394 | — |
| 5,000 blocks | 6 | 203.491 ms | 1.806 | [202.046, 204.936] | 0.0407 | — |
| 10,000 blocks | 6 | 398.003 ms | 1.448 | [396.844, 399.162] | 0.0398 | — |
Full 24-hour protocol: 23.22 h between first and last sample, 30 samples at 48-minute intervals, run 2026-07-03 → 2026-07-04 against an isolated test database (p4_chain_24h.db) so the production chain was untouched. An earlier 4.85 h pilot (2026-04-13, 10-minute intervals) is retained below for comparison. Trend analysis detects memory leaks and CPU drift.
| Sample | Time (hr) | CPU (%) | RAM (MB) | Verify (ms) | Chain Length | Integrity |
|---|---|---|---|---|---|---|
| 1 | 0.00 | 0.6 | 29.54 | 0.60 | 11 | ✓ Valid |
| 2 | 0.80 | 0.5 | 29.72 | 1.12 | 21 | ✓ Valid |
| 3 | 1.60 | 0.9 | 29.72 | 1.64 | 31 | ✓ Valid |
| 4 | 2.40 | 0.4 | 29.72 | 2.20 | 41 | ✓ Valid |
| 5 | 3.20 | 0.5 | 29.72 | 2.68 | 51 | ✓ Valid |
| 6 | 4.00 | 0.3 | 29.72 | 3.26 | 61 | ✓ Valid |
| 7 | 4.80 | 0.4 | 29.72 | 3.78 | 71 | ✓ Valid |
| 8 | 5.60 | 0.6 | 29.72 | 4.28 | 81 | ✓ Valid |
| 9 | 6.41 | 0.4 | 29.72 | 4.71 | 91 | ✓ Valid |
| 10 | 7.21 | 0.6 | 29.98 | 5.32 | 101 | ✓ Valid |
| 11 | 8.01 | 0.3 | 29.98 | 5.37 | 111 | ✓ Valid |
| 12 | 8.81 | 0.4 | 29.98 | 6.12 | 121 | ✓ Valid |
| 13 | 9.61 | 0.3 | 29.98 | 6.65 | 131 | ✓ Valid |
| 14 | 10.41 | 0.3 | 29.98 | 6.86 | 141 | ✓ Valid |
| 15 | 11.21 | 0.4 | 29.98 | 7.35 | 151 | ✓ Valid |
| 16 | 12.01 | 0.3 | 29.98 | 7.93 | 161 | ✓ Valid |
| 17 | 12.81 | 0.4 | 29.98 | 8.14 | 171 | ✓ Valid |
| 18 | 13.61 | 0.7 | 29.98 | 8.50 | 181 | ✓ Valid |
| 19 | 14.41 | 0.4 | 29.98 | 8.84 | 191 | ✓ Valid |
| 20 | 15.21 | 0.4 | 29.98 | 9.18 | 201 | ✓ Valid |
| 21 | 16.01 | 0.4 | 29.98 | 9.48 | 211 | ✓ Valid |
| 22 | 16.81 | 1.2 | 29.98 | 10.20 | 221 | ✓ Valid |
| 23 | 17.61 | 0.6 | 29.98 | 10.95 | 231 | ✓ Valid |
| 24 | 18.42 | 0.8 | 29.98 | 10.82 | 241 | ✓ Valid |
| 25 | 19.22 | 0.9 | 29.98 | 11.74 | 251 | ✓ Valid |
| 26 | 20.02 | 0.7 | 29.98 | 12.13 | 261 | ✓ Valid |
| 27 | 20.82 | 0.9 | 29.98 | 12.04 | 271 | ✓ Valid |
| 28 | 21.62 | 0.8 | 29.98 | 13.36 | 281 | ✓ Valid |
| 29 | 22.42 | 0.8 | 29.98 | 12.83 | 291 | ✓ Valid |
| 30 | 23.22 | 1.1 | 30.17 | 14.16 | 301 | ✓ Valid |
The Central Limit Theorem states that sample means approach a normal distribution as n increases, regardless of population distribution. n ≥ 30 is the accepted minimum for parametric tests to be valid.
| Test | Used For | Exps |
|---|---|---|
| Descriptive + 95% CI | Detection rate, latency, throughput | E1–E9, P2 |
| Paired t-test | CPU/RAM with vs without blockchain | P1 |
| Linear regression (R²) | O(n) scaling, rewrite cost vs K | E7, P3 |
| Trend analysis (slope) | RAM drift over 24hr; slope ≈ 0 | P4 |
| Pending (n=0) | Per-object FP rate — field session not yet conducted | E10 |
| Exp | n | Primary Result | Target | Pass? |
|---|---|---|---|---|
| E1 | 30 | 100% (30/30) · 16.15 ms [12.11,20.18] | 100% | ✓ |
| E2 | 30 | 100% (30/30) · 20.16 ms [14.70,25.63] | 100% | ✓ |
| E3 | 30 | 100% (30/30) · 20.23 ms [14.76,25.70] | 100% | ✓ |
| E4 | 30 | 100% (30/30) · 18.43 ms [14.14,22.72] | 100% | ✓ |
| E5 | 30 | 100% (30/30) · 20.27 ms [15.97,24.58] | 100% | ✓ |
| E6 | 30 | 53.3% (16/30) [36.14,69.77] · 40.25 ms | >95% | NOT MET |
| E7 | 30 | Rewrite cost 0.49–39.6 ms, O(K) confirmed R²=0.9992 · local detection 0/30 by design · cloud detection NOT measured | Characterise rewrite cost, confirm O(K) | ✓ |
| E8 | 30 | 100% (30/30) · 38.95 ms [38.81,39.09] | >90% | ✓ |
| E9 | 30 | 100% (30/30) · 16.14 ms [12.16,20.12] | >95% | ✓ |
| E10 | 0 | Pending field session | Analysis | — |
| P1 | 30 | No significant CPU overhead: −7.99% [−16.21,+0.22] · t(29)=1.99, p=0.056 | <15% | ✓ |
| P2 | 30 | 12,160.7 h/s [12,147.0,12,174.4] | >100 h/s | ✓ |
| P3 | 30 | O(n) · R²=0.9998 · 0.0399 ms/block | O(n) | ✓ |
| P4 | 30 | RAM drift +0.63 MB over 23.2 h · CPU 0.58% · chain 30/30 valid | No leak | ✓ |
All scripts located in ~/parking_security/ on Jetson Nano and C:\Users\ASUS\Downloads\parking_system\ on ROG laptop.
parking_detector.py
Full Pipeline — Live Parking Detection
Main system script. Connects to RTSP camera → captures frame every 5s → resizes to 1020×600 → runs Canny edge detection on 14 ROI polygons → computes SHA-256 frame hash → adds block to blockchain → uploads frame to S3 → saves status to DynamoDB.
blockchain.py
Blockchain Core — HashChain + ChainStorage
Defines the Block dataclass, HashChain class, and ChainStorage (SQLite backend). Each block stores: index, timestamp, frame_hash (SHA-256 of JPEG bytes), previous_hash, block_hash (SHA-256 of all fields combined), and metadata. verify_chain() traverses the full chain in O(n).
cloud_anchor.py
Cloud Anchor — DynamoDB Checkpoint
Uploads blockchain checkpoints to AWS DynamoDB every 10 blocks. verify_against_cloud() cross-checks the local chain against DynamoDB records. Intended as the independent reference for E7 (chain rewrite) and E6 Scenario D (replay), but NOT yet effective against those: the device holds PutItem credentials and upload_checkpoint() issues an unconditional put_item, so a device-level attacker can overwrite checkpoints. anchored_at is also device-generated. Append-only storage and a server-derived timestamp are required first; cloud detection has not been measured.
roi_selector.py
ROI Drawing Tool
Interactive OpenCV tool for drawing parking spot polygons on the camera frame. Left-click adds points, right-click closes polygon, middle-click removes last. Saves polygon coordinates to rois.json. Currently configured with 14 parking spots.
performance_monitor.py
Performance Monitor
Background thread that samples CPU%, RAM (MB), GPU%, FPS, and chain length every 10 seconds. Writes to timestamped CSV in data/. Used by parking_detector.py during live operation and by run_P4_stability.py for the 24-hour stability test.
run_all.py
Master Runner — E1–E10, P1–P3
Runs all experiment scripts in sequence: run_tamper_experiments.py → run_advanced_experiments.py → run_P1_overhead.py → benchmark_hash.py → benchmark_chain.py. Logs pass/fail for each. Total runtime ~135 minutes on Jetson Nano. P4 excluded (run separately).
run_tamper_experiments.py
E1–E7 Tamper Detection Experiments
Runs 7 tamper attack experiments × 30 trials each. Each trial builds a 1000-block synthetic chain (payload bytes from os.urandom(); random.seed(42) fixes the targeted indices), applies an attack, then calls verify_chain() to measure detection. Results saved as individual CSVs with trial, detected flag, latency_ms, and attack-specific fields.
run_advanced_experiments.py
E8–E10 Advanced Experiments
E8 (feed substitution) — detects repeated frame_hash patterns in chain. E9 (timestamp manipulation) — forward/backward/random clock changes; the recorded detection is a timestamp-gap heuristic (gap > 3600 s), with block_hash invalidation as independent corroboration (chain_valid = 0 in all 30 trials). E10 (physical spoofing) — template CSV for manual data collection with real objects.
tamper_simulator.py
Attack Simulator Library
Library of attack functions used by the experiment scripts. Provides: build_test_chain(), attack_frame_modification(), attack_frame_deletion(), attack_frame_injection(), attack_metadata_tampering(), attack_replay(), attack_chain_rewrite(). Each returns detected flag and latency_ms.
run_P1_overhead.py
P1 — Security Overhead Benchmark
30 paired measurements of CPU%, RAM (MB), and FPS with and without blockchain active. Uses paired t-test to determine statistical significance of overhead. Runs on Jetson Nano under controlled conditions.
benchmark_hash.py
P2 — Hash Throughput Benchmark
Hashes 1,000 random frames × 30 iterations and measures throughput. Result: 12,160.7 hashes/sec (SD=38.2) on Jetson Nano ARM CPU. Highly consistent (CV < 0.4%). Each frame hash takes ~0.082 ms.
benchmark_chain.py
P3 — Verification Scaling Benchmark
Measures verify_chain() time for chains of 100, 500, 1,000, 5,000, and 10,000 blocks (6 runs each). Confirms O(n) linear scaling. Results: 4.0ms → 19.5ms → 39.4ms → 203.5ms → 398.0ms.
run_P4_stability.py
P4 — Long-Term Stability Test
Runs the parking system continuously and records 30 samples (CPU%, RAM MB, chain length, chain validity, verify_ms) at 48-minute intervals (23.22 h between first and last sample; an earlier pilot used 10-minute intervals over 4.85 h). Tests whether the system degrades over time — no memory leaks, no performance drift. Linear regression on RAM over time gives the drift slope (MB/hr).
generate_report.py
Report Generator — Charts + Stats
Reads all experiment CSVs, computes statistics (mean, SD, 95% CI, t-test, linear regression), and generates 5 matplotlib PNG charts for the thesis. Outputs figures to reports/ directory.
generate_master_table.py
Master Results Table
Aggregates all CSVs into a single master results table (CSV + plain text). Ready-to-paste into thesis Chapter 5.
statistical_analysis.py
Statistical Analysis Library
Provides: analyse_experiment() for per-CSV stats, paired_ttest() for P1 paired comparisons, linear_regression() for P3/P4 trend lines, and trend_analysis() for stability drift detection.
setup_dynamodb.py
AWS DynamoDB Setup
Creates and verifies DynamoDB tables for checkpoint anchoring and per-frame hash + detection status. Region: us-east-1.
test_blockchain.py
Unit Tests
6 unit tests covering: genesis block creation, block addition, chain verification, tamper detection, persistence to SQLite, and cloud anchor connectivity. All 6 tests pass.