전화가 거의 없습니다.
모든 플랫폼.
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 | 위도, 경도, 고도(부동 소수점) |
| 에너지 계량 | PZEM-004T, INA219 | 전압, 전류, 전력(부동) |
| NFC 액세스 | PN532 + NTAG424 DNA | Badge_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 자격 증명 관리자 |
| 리눅스 | 생산 | libsecret |
| iOS/맥OS | 로드맵 중 | Secure Enclave |
5KB.
스택은 변경되지 않습니다.
PHP bridge은 기존 엔드포인트 앞에 있는 단일 요구 사항입니다. 경로, 데이터베이스, 비즈니스 로직. 손길이 닿지 않은.. Identity Layer은 인증 및 페이로드 암호화를 처리합니다. 추가한 것과 같은 방식으로 제거합니다.
require_once
그리고 두 개의 함수 호출. 엔드포인트는 확인되고 해독된 페이로드를 수신하기 시작합니다.
스키마 마이그레이션이 없습니다. 사용자 테이블은 변경되지 않습니다. 세션 저장 공간이 없습니다.
완전한 서버 측 스택은 다음과 같습니다. 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 | 필수 클라우드 연결 없음 |