電話はほとんどありません。
あらゆるプラットフォーム。
Identity Layer は、設計により最小限の表面と統合されています。 マイクロコントローラーでは MicroPython、Android および Windows では Flutter、 または、PHP bridge を既存のエンドポイントにドロップします。 同じプロトコル。同じ暗号化保証。電話は4回。
IdentityIoT、
経由でインストールされました 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})
| 成分 | モデル | 役割 |
|---|---|---|
| MCU | Raspberry Pi Pico 2W (RP2350) | TrustZone、WiFi、device-bound キー ストレージ |
| NFC reader | PN532 | I2C インターフェイス、NTAG424 DNA バッジを読み取ります |
| 画面 | SSD1306 128x64 OLED | ブートシーケンス、検証ステータス |
| NFC badge | NTAG424 DNA (NXP) | AES-128 オンボード、エクスポート不可キー、動的 CMAC |
Identity IoT ノードは NFC アクセスに限定されません。同じ認証された node は、任意のセンサー ペイロードを運ぶことができます。 すべての読み取り値は、node が JWT を取得した後、AES-256-GCM 暗号化された POST を介して送信されます。
| センサーの種類 | 代表的なハードウェア | ペイロードフィールド |
|---|---|---|
| 温度 | DHT22、DS18B20、BME280 | 温度 (フロート、°C) |
| 湿度 | DHT22、BME280 | 湿度 (浮動小数点、%) |
| プレッシャー | BME280、BMP390 | 圧力 (フロート、hPa) |
| PIRモーション | HC-SR501 | モーション (ブール値) |
| GPS | NEO-6M、L76X | 緯度、経度、高度 (float) |
| エネルギー計測 | PZEM-004T、INA219 | 電圧、電流、電力 (float) |
| NFC アクセス | PN532 + NTAG424 DNA | badd_uid、付与 (ブール値) |
{ "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 を読みました。チャレンジが発行されました。
Ed25519 が確認されました。
Identity Tag は、Identity IoT の上に構築されたアプリケーション層です。 各 badge 読み取りにより、バックエンドに対して完全な Ed25519 challenge/response サイクルがトリガーされます。 reader には秘密は保存されません。 badge には平文の ID がありません。マルチtenant設計。
# 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
| モード | 説明 | 使用事例 |
|---|---|---|
| STD | Badge は、その tenant に対して認可されたフリート内の任意の端末で動作します。 | オフィスへのアクセス、一般的な入り口。 |
| HS | Badge 暗号的に特定の端末にバインドされます。 DEK 派生には、端末公開キーの hash が組み込まれています。 Badge は、他の reader では無効です。 | 高セキュリティの部屋、データセンターラック、機器キャビネット。 |
| 終点 | 方法 | 役割 |
|---|---|---|
| identity_tag/it_request_challenge | POST | badge 検証のために nonce を発行します |
| identity_tag/it_verify_badge | POST | Ed25519 署名を検証し、GRANTED/DENIED を返します |
| identity_tag/it_node_checkin | POST | Node ハートビートと JWT リフレッシュ |
| identity_tag/it_register_badge | POST (manager) | badge 公開キーと資格を書き込みます |
| identity_tag/it_list_nodes | GET (manager) | tenant の Node フリート ステータス |
プロビジョニングおよび管理アプリは Android 上で実行されます。デバイスの NFC を使用して badge ペイロードを書き込みます そして、認証された Identity Layer チャネルを介してバックエンドに接続します。
// 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);
デバイスにバインドされた ID。
電話は4回。
ローカルパッケージ。外部 ID サービスはありません。秘密キーがデバイスの外に出ることはありません。
安全なストレージを介して flutter_secure_storage
利用可能な場合は、TEE / Secure Enclave。
ペイロード暗号化はエンドツーエンドで行われます。 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
| プラットフォーム | 状態 | 安全なストレージ |
|---|---|---|
| アンドロイド | 本番環境、Google Play クリア | Android キーストア / TEE |
| 窓 | 本番環境、Microsoft Store クリア | Windows 資格情報マネージャー |
| Linux | 生産 | libsecret |
| iOS / macOS | ロードマップ上 | Secure Enclave |
5KB。
スタックは変更されません。
PHP bridge は、既存のエンドポイントの前に位置する単一のリクエストです。 ルート、データベース、ビジネス ロジック。手付かずの.. Identity Layer は認証とペイロード暗号化を処理します。 追加したときと同じ方法で削除します。
require_once
そして 2 つの関数呼び出し。エンドポイントは、検証され、復号化されたペイロードの受信を開始します。
スキーマの移行はありません。ユーザーテーブルは変更されません。セッションストレージはありません。
完全なサーバー側スタックは次のとおりです。 225KB。
// 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 エンドポイント
委任を登録し、72 時間の輸出ウィンドウを開きます。
ログは収集後に破棄されます。要求当局は法的責任を負います。
// 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 );
| 成分 | テクノロジー | 注意事項 |
|---|---|---|
| ランタイム | PHP 8.x | バニラ、フレームワークは不要 |
| データベース | MySQL / マリアDB | 標準スキーマ、資格情報列なし |
| キャッシュ/一時的 | Redis | チャレンジ トークン、メッセージ キュー (TTL < 1 分) |
| ブリッジサイズ | 5KB | 単一の PHP ファイル、任意の LAMP スタックにドロップ |
| フルスタックサイズ | 225KB | ID STD + HS + キー + セキュア チャネル + IoT + ラベル + タグ |
| 導入 | コンテナ / オンプレミス / air-gapped | 必須のクラウド接続はありません |