Wenige Anrufe.
Jede Plattform.
Identity Layer lässt sich konstruktionsbedingt mit minimaler Oberfläche integrieren. MicroPython auf einem Mikrocontroller, Flutter auf Android und Windows, oder ein PHP bridge, das in Ihre vorhandenen Endpunkte eingefügt wurde. Das gleiche Protokoll. Die gleichen kryptografischen Garantien. Vier Anrufe.
IdentityIoT,
installiert über mip.
# Install via mip — no external dependencies # import mip; mip.install("github:wide/identity-micropython") from identity_iot import IdentityIoT # 1. Init — configure node identity identity = IdentityIoT( base_url = cfg['base_url'], node_type = cfg['node_type'], tenant_id = cfg['tenant_id'], comm_key = cfg['comm_key'].encode(), comm_iv = cfg['comm_iv'].encode(), ) # 2. Register — device-bound key, runs once identity.ensure_registered() # 3. Authenticate — Ed25519 challenge / verify / JWT token = identity.authenticate() # 4. Authenticated request — AES-256-GCM encrypted payload response = identity.post_encrypted({'request': 'record_sensor_data', 'value': 42})
| Komponente | Modell | Rolle |
|---|---|---|
| MCU | Raspberry Pi Pico 2W (RP2350) | TrustZone, WLAN, device-bound-Schlüsselspeicher |
| NFC reader | PN532 | I2C-Schnittstelle, liest NTAG424 DNA-Badges |
| Anzeige | SSD1306 128x64 OLED | Boot-Sequenz, Verifizierungsstatus |
| NFC badge | NTAG424 DNA (NXP) | AES-128 onboard, nicht exportierbare Schlüssel, dynamisch CMAC |
Identity IoT-Knoten sind nicht auf den NFC-Zugriff beschränkt. Derselbe authentifizierte node kann jede beliebige Sensornutzlast transportieren. Alle Messwerte werden über AES-256-GCM verschlüsselt POST übertragen, nachdem node seinen JWT erhält.
| Sensortyp | Typische Hardware | Nutzlastfeld |
|---|---|---|
| Temperatur | DHT22, DS18B20, BME280 | Temperatur (Float, °C) |
| Luftfeuchtigkeit | DHT22, BME280 | Luftfeuchtigkeit (Float, %) |
| Druck | BME280, BMP390 | Druck (Float, hPa) |
| PIR-Bewegung | HC-SR501 | Bewegung (bool) |
| GPS | NEO-6M, L76X | Breitengrad, Längengrad, Höhe (Float) |
| Energiemessung | PZEM-004T, INA219 | Spannung, Strom, Leistung (Float) |
| NFC Zugriff | PN532 + NTAG424 DNA | Badge_uid, gewährt (bool) |
{ "node_uid" : "273ec83a-84c8-4967-aafa-0780ab161cc1", "tenant_id" : "0b3cfe4d-fdf7-46c2-bd41-b533da415dd9", "node_type" : "sensor", "temperature": 24.3, "humidity" : 58.1, "pressure" : 1013.2, "updated_at" : "2026-06-09 11:42:07" }
Badge gelesen. Herausforderung ausgegeben.
Ed25519 verifiziert.
Identity Tag ist die Anwendungsschicht, die auf Identity IoT aufbaut. Jeder badge-Lesevorgang löst einen vollständigen Ed25519 challenge/response-Zyklus für das Backend aus. Keine gespeicherten Geheimnisse auf dem reader. Keine Klartextidentität auf dem badge. Multi-tenant von Natur aus.
# 1. Reader reads NTAG424 DNA NDEF payload # Fields: epk (encrypted private key), df2 (DEK fragment 2), mode (STD|HS) # 2. DEK reconstruction dek = df1_from_config XOR df2_from_badge # 3. Decrypt badge private key badge_privkey = AES_CBC_decrypt(dek, epk) # 4. Request challenge from backend challenge = POST identity_tag/it_request_challenge # { node_uid, badge_uid, tenant_id } # 5. Sign challenge with badge key (Ed25519) signature = ed25519_sign(badge_privkey, challenge_nonce) # 6. Verify at backend result = POST identity_tag/it_verify_badge # { challenge_id, signature_b64 } -> { granted: true } # 7. Reader actuates relay (GRANTED) or displays DENIED
| Modus | Beschreibung | Anwendungsfall |
|---|---|---|
| STD | Badge funktioniert auf jedem Terminal in der autorisierten Flotte für diesen tenant. | Bürozugang, allgemeine Einstiegspunkte. |
| HS | Badge kryptografisch an ein bestimmtes Terminal gebunden. Die DEK-Ableitung beinhaltet einen hash des öffentlichen Schlüssels des Terminals. Badge ist auf allen anderen reader ungültig. | Hochsicherheitsräume, Rechenzentrums-Racks, Geräteschränke. |
| Endpunkt | Verfahren | Rolle |
|---|---|---|
| identity_tag/it_request_challenge | POST | Geben Sie Nonce für die badge-Verifizierung aus |
| identity_tag/it_verify_badge | POST | Überprüfen Sie die Signatur von Ed25519 und geben Sie GRANTED/DENIED zurück. |
| identity_tag/it_node_checkin | POST | Node Heartbeat und JWT Refresh |
| identity_tag/it_register_badge | POST (manager) | Schreiben Sie den öffentlichen Schlüssel und die Berechtigung für badge |
| identity_tag/it_list_nodes | GET (manager) | Node Flottenstatus für tenant |
Die Bereitstellungs- und Verwaltungs-App läuft auf Android. Es verwendet NFC des Geräts, um badge-Nutzlasten zu schreiben und stellt über authentifizierte Identity Layer-Kanäle eine Verbindung zum Backend her.
// identity_tag package - badge provisioning final writer = IdentityTagWriter(api: tagApi); // Generate badge keypair and encrypt private key with split DEK final payload = await writer.prepareBadgePayload( tenantId : tenant.id, mode : BadgeMode.STD, // or BadgeMode.HS nodeUid : null, // required for HS mode ); // Write NDEF to NTAG424 DNA via flutter_nfc_kit await writer.writeToTag(payload);
Gerätegebundene Identität.
Vier Anrufe.
Lokale Pakete. Kein externer Identitätsdienst. Der private Schlüssel verlässt das Gerät nie.
Sichere Speicherung über flutter_secure_storage
und TEE / Secure Enclave, sofern verfügbar.
Die Nutzdatenverschlüsselung erfolgt Ende-zu-Ende über ITEMSEncrypter.
// 1. Init — JWT identity, silent on subsequent boots final auth = IdentityAuthServiceStd(ITEMSGlobals.authURI); await auth.ensureJwt( preferredLocale: locale.languageCode, utcOffsetMin: DateTime.now().timeZoneOffset.inMinutes, ); // 2. Handshake — silent if identity already present on device final result = await api.mjHandshake( identityHash: identityHash, publicKey: publicKey, ); // 3. Store JWT — session active, no password, no credential database await _storage.write(key: 'token', value: result['token']); // 4. Every request — AES-256-GCM payload, end-to-end encrypted final response = await api.postEncrypted({'request': 'your_request'});
dependencies: # Identity Layer — local packages, no external registry identity_package: path: packages/identity_package identity_std: path: packages/identity_std identity_hs: path: packages/identity_hs items_crypto: path: packages/items_crypto
| Plattform | Status | Sichere Lagerung |
|---|---|---|
| Android | Produktion, Google Play gelöscht | Android Keystore / TEE |
| Windows | Produktion, Microsoft Store gelöscht | Windows-Anmeldeinformationsmanager |
| Linux | Produktion | libsecret |
| iOS / macOS | Auf der Roadmap | Secure Enclave |
5 KB.
Ihr Stapel, unverändert.
Der PHP bridge ist eine einzelne Anforderung, die sich vor Ihren vorhandenen Endpunkten befindet. Ihre Routen, Ihre Datenbank, Ihre Geschäftslogik. Unberührt.. Identity Layer übernimmt die Authentifizierung und Nutzdatenverschlüsselung. Entfernen Sie es auf die gleiche Weise, wie Sie es hinzugefügt haben.
require_once
und zwei Funktionsaufrufe. Ihre Endpunkte beginnen, verifizierte, entschlüsselte Nutzlasten zu empfangen.
Keine Schemamigration. Keine Änderungen an der Benutzertabelle. Kein Sitzungsspeicher.
Der komplette serverseitige Stack ist 225 KB.
// 1. Include the Identity Layer bridge — 5 KB require_once 'identity/_mj_auth.php'; // 2. Authenticate — JWT verified, identity_hash extracted // identity_hash is a 64-char SHA-256 hex — never a user ID [$identityHash, $tenantId, $claims, $role] = mj_authenticate_identity($encoder); // 3. Every response — AES-256-GCM encrypted, end-to-end sendEncryptedResponse($encoder, [ 'status' => 'ok', 'data' => $yourData, ], ['ts' => time()], 200);
mj_mandate_log Endpunkt
registriert das Mandat und öffnet ein 72-Stunden-Exportfenster.
Protokolle werden nach der Abholung vernichtet. Die ersuchende Behörde trägt die rechtliche Verantwortung.
// Requires role = admin — never operator [$userId, $tenantId, $claims, $role] = mj_authenticate($encoder); mj_require_role($encoder, $claims, 'admin'); // Register mandate — opens 72h export window // target_identity_hash: 64-char SHA-256, never plaintext identity // Ciphertext is never stored — metadata only $connector->executeDatabaseParameterQuery( "INSERT INTO audit_log (mandate_number, issuing_country, issuing_court, target_identity_hash, export_status) VALUES (?, ?, ?, ?, 'PENDING')", [$mandateNumber, $issuingCountry, $issuingCourt, $targetHash], $db );
| Komponente | Technologie | Notizen |
|---|---|---|
| Laufzeit | PHP 8.x | Vanille, kein Rahmen erforderlich |
| Datenbank | MySQL / MariaDB | Standardschema, keine Anmeldeinformationsspalten |
| Cache / vergänglich | Redis | Challenge-Tokens, Nachrichtenwarteschlangen (TTL < 1 Min.) |
| Brückengröße | 5 KB | Einzelne PHP-Datei, in einem beliebigen LAMP-Stack ablegen |
| Volle Stapelgröße | 225 KB | Identität STD + HS + Schlüssel + sicherer Kanal + IoT + Etiketten + Tag |
| Einsatz | Container / vor Ort / air-gapped | Keine zwingende Cloud-Konnektivität |