This repository contains:
- Phone‑key generation & storage
- Ed25519 and ECDSA P‑256 signing
- ACL decoding, canonicalization, signing & chunking
- JSON & ISO‑8601 utilities
- Lock‑compatible ACL storage in Keychain
- How to ensure/load a phone key
- How to send your public key to your backend
- How to build, canonicalize & sign unlock commands
- How to test key lifecycle events (expire, revoke, delete)
- How to integrate with
PhoneKeyManagerinside SwiftUI
This README explains both.
- #overview
- #phonekeycore-features
- #installation
- #key-architecture
- #key-generation
- #phonekeyinfo-api
- #acl-models
- #signing--canonicalization
- #acl-chunk-builder-firmware-ready
- #local-acl-storage
- #phonekeysample-app-overview
- #sample-app-screens
- #crypto-provider-sodium
- #faq
PhoneKeyCore provides everything needed for mobile‑generated authentication keys in secure lock systems:
- Automatic private key creation
- Deterministic public key derivation
- Command signing
- ACL validation & chunking
- Backend contract models
Designed to be dropped into any iOS app.
| Algorithm | Private Key Storage | Notes |
|---|---|---|
| ECDSA P‑256 (default) | Secure, persistent SecKey | Best for modern iOS (13+) |
| Ed25519 | 32‑byte seed in Keychain | Sodium fallback for iOS 12 |
Both produce deterministic UUID‑style keyId (SHA‑256 → 16 bytes → UUID).
PhoneKeyCore includes:
PhoneKeyAclPhoneKeyAclEnvelope(lock‑compatible)PhoneKeyAclRequest
With flexible decoding for:
- int/string IDs
- ISO‑8601 or epoch timestamps
- Permissions array or keyed booleans
- Ed25519 → 64‑byte signature
- P‑256 → raw 64‑byte
(r||s)signature - Converts DER → raw R/S safely
Produces 128‑byte hex‑encoded packets for BLE.
Final chunk format:
"xx" + <4 hex digits ACL length> + <remaining bytes>
Store, list, update, delete ACLs locally.
Self‑healing index.
PhoneKeyCore is available through CocoaPods. To install it, add the following line to your Podfile:
pod'PhoneKeyCore',:git=>'https://github.com/noke-inc/PhoneKeyCore.git',:tag=>'1.0.0'Or, if published to CocoaPods trunk or a private spec repo:
pod'PhoneKeyCore','~> 1.0'Then run:
pod installTo integrate PhoneKeyCore into your NokeMobileLibrary or other projects:
- Add to your Podfile:
source'https://github.com/CocoaPods/Specs.git'target'YourTarget'douse_frameworks!pod'PhoneKeyCore',:git=>'https://github.com/noke-inc/PhoneKeyCore.git',:tag=>'1.0.0'end- Import in your Swift files:
import PhoneKeyCore- Use the
PhoneKeyCoreProvidingprotocol for integration:
letmanager=PhoneKeyManager(serviceName:"com.yourapp.phonekey", provider: yourCryptoProvider)PhoneKeyCoreBridge.shared = managerAlternatively, drag the PhoneKeyCore folder into your Xcode project.
If you need iOS 12 Ed25519 support, add Sodium:
pod'Sodium'Then provide a CryptoProvider implementation (example included in Sample App).
PhoneKeyCore/
├── PhoneKeyManager.swift # Key generation, signing, ACL chunking
├── PhoneKeyAcl.swift # ACL model
├── PhoneKeyAclRequest.swift
├── PhoneKeyInfoRequest.swift
├── PhoneKeyInfoResponse.swift
├── PhoneKeySignedCommand.swift
├── Canonicalization utils # ISO-8601, JSON sorting
└── Keychain helpers
letmanager=PhoneKeyManager(
serviceName:"com.example.app.keys",
accessGroup:nil,
provider:SodiumCryptoProvider(), // iOS 12 Ed25519
preferredAlgorithm:.ecdsaP256 // default
)letinfo=try manager.ensureKeys()print(info.keyId)print(info.publicKeyRaw.base64EncodedString())try manager.destroyKeys()publicstructPhoneKeyInfo:Codable{publicletkeyId:Stringpublicletalgorithm:SignatureAlgorithmpublicletpublicKeyRaw:Datapublicletseed:Datapublicvarstatus:PhoneKeyStatuspublicletkeyTag:Data?}letreq=PhoneKeyAclRequest(
userId:"123",
lockMac:"AA:BB:CC:DD:EE:FF",
phoneKeyId:"456")letenv=tryJSONDecoder().decode(PhoneKeyAclEnvelope.self, from: data)letacl= env.acl
print(acl.permissions.unlock)func signCommand(with manager:PhoneKeyManager,
base:PhoneKeySignedCommand)throws-> PhoneKeySignedCommand
func canonicalCommandBytes(for command:PhoneKeySignedCommand)throws->DataCanonicalization ensures:
- ISO‑8601 UTC w/ fractional seconds
- Sorted key ordering
- Signature removed before signing
ACL canonicalization:
func canonicalize(acl:PhoneKeyAcl)throws->Dataletchunks=try manager.buildACLChunks(acl: aclData)Example:
[
"00<128 bytes hex>",
"01<128 bytes hex>",
"xx02d0<remaining>"
]
try manager.saveACL(acl)letstored=try manager.getACL(trackingId:"1")letlist=try manager.listACLs()try manager.deleteACL(trackingId:"1")- Ensuring keys
- Validating existing keys
- Showing Key ID & Public Key
- Signing unlock commands
- Soft-expiring / revoking keys
- Clearing Keychain for test
- Copy-to-clipboard actions
- Full SwiftUI UI
{
"userId": "...",
"phoneUdid": "...",
"publicKey": "..."
}Implements:
generateEd25519Seed()derivePublicKey(fromSeed:)sign(message:withSeed:)getHash(of:)- Only need Sodium for iOS 12 Ed25519
- Prefer P‑256 for security & hardware‑backed storage
- Lock expects raw 64‑byte (r||s) P‑256 signatures
- Canonicalization is required for verification