Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CryptoKitとCoreBluetoothを利用したスマートキー開発/iOSDC2020

saiten
September 21, 2020

 CryptoKitとCoreBluetoothを利用したスマートキー開発/iOSDC2020

WWDC20ではAppleからCarKeyが発表され、iOSの標準機能としてiPhoneをクルマの鍵として利用できるようになりました。とはいえ、CarKeyは現在BMWの最新機種でしか利用することができません。

CarKeyを利用しなくてもiOS13から追加されたCryptoKitを利用すると様々な暗号アルゴリズムを簡単に利用することができ、CoreBluetoothと組み合わせることで簡単にiPhoneを利用したスマートキーシステムを実現することができます。

このトークでは、リモコンキーすらない古いクルマにArduinoとiPhoneを利用したスマートキーシステムを構築する過程で得た様々な知見を共有します。

saiten

September 21, 2020
Tweet

Other Decks in Programming

Transcript

  1. class CentralManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate { var manager: CBCentralManager? =

    nil func start() { manager = CBCentralManager(delegate: self, queue: nil) } // MARK: - CBCentralManagerDelegate func centralManagerDidUpdateState(_ central: CBCentralManager) { guard central.state == .poweredOn else { return } central.scanForPeripherals(withServices: [smartLockServiceUUID]) } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { central.stopScan() central.connect(peripheral) } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { peripheral.delegate = self peripheral.discoverServices([smartLockServiceUUID]) self.connectedPeripheral = peripheral } // MARK: - CBPeripheralDelegate func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { guard let service = peripheral.services?.first(where: { $0.uuid == smartLockServiceUUID }) else { return } peripheral.discoverCharacteristics([smartLockCharacteristicUUID], for: service) } func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { guard let characteristic = service.characteristics?.first(where: { $0.uuid == smartLockCharacteristicUUID }) else { return } peripheral.setNotifyValue(true, for: characteristic) } } Πϕϯτຖʹϝιου͕ผΕ͓ͯΓɺ ॲཧͷྲྀΕ͕௥͍ͮΒ͍
  2. let manager = CentralManager() manager .observeState() .startWith(manager.state) .filter { $0

    == .poweredOn } .flatMap { _ in manager.scanForPeripherals(withServices: [smartLockServiceUUID]) } .take(1) .flatMap { $0.peripheral.establishConnection() } .flatMap { $0.discoverServices([smartLockServiceUUID]) } .flatMap { Observable.from($0) } .flatMap { $0.discoverCharacteristics([smartLockCharacteristicUUID]) } ॲཧΛ࿈݁ͯ͠ॻ͘͜ͱ͕Ͱ͖ɺ ॲཧͷྲྀΕΛ௥͍΍͍͢
  3. ղৣγʔέϯε ंࡌ୺຤ʹ઀ଓ νϟϨϯδίʔυΛऔಘ νϟϨϯδίʔυ ʮૢ࡞ίϚϯυʴνϟϨϯδίʔυʯ ɹͷ4)"ϋογϡΛੜ੒͠ɺ ɹൿີݤ &$%4" Ͱॺ໊Λ࡞੒ ʮૢ࡞ίϚϯυʴνϟϨϯδίʔυʯ

    ɹͱʮॺ໊ʯΛૹ৴ νϟϨϯδίʔυ͕༗ޮ͔֬ೝ͠ɺ ࣄલʹొ࿥͞Εͨެ։ݤΛར༻ͯ͠ ॺ໊Λݕূ ղৣ׬ྃίʔυΛฦ͢ ໰୊ͳ͚Ε͹ ΞϯϩοΫ৴߸ Λૹ৴
  4. ղৣγʔέϯε ंࡌ୺຤ʹ઀ଓ νϟϨϯδίʔυΛऔಘ νϟϨϯδίʔυ ʮૢ࡞ίϚϯυʴνϟϨϯδίʔυʯ ɹͷ4)"ϋογϡΛੜ੒͠ɺ ɹൿີݤ &$%4" Ͱॺ໊Λ࡞੒ ʮૢ࡞ίϚϯυʴνϟϨϯδίʔυʯ

    ɹͱʮॺ໊ʯΛૹ৴ νϟϨϯδίʔυ͕༗ޮ͔֬ೝ͠ɺ ࣄલʹొ࿥͞Εͨެ։ݤΛར༻ͯ͠ ॺ໊Λݕূ ղৣ׬ྃίʔυΛฦ͢ ໰୊ͳ͚Ε͹ ΞϯϩοΫ৴߸ Λૹ৴
  5. 4)"ϋογϡੜ੒ $PNNPO$SZQUP let payload = "\(operationCode)_\(challengeCode)" var digestData = Data(count:

    Int(CC_SHA256_DIGEST_LENGTH)) _ = digestData.withUnsafeMutableBytes { mutableBytes in CC_SHA256(payload, CC_LONG(payload.utf8.count), mutableBytes.bindMemory(to: UInt8.self).baseAddress) }
  6. ॺ໊ 4FDVSJUZGSBNFXPSL var error: Unmanaged<CFError>? var privateKey: SecKey? var publicKey:

    SecKey? let osStatus = SecKeyGeneratePair([kSecAttrApplicationTag: "co.saiten.smartkey", kSecAttrKeyType: kSecAttrKeyTypeEC, kSecAttrKeySizeInBits: 256] as CFDictionary, &publicKey, &privateKey) guard osStatus == noErr else { return } guard SecKeyIsAlgorithmSupported(privateKey!, .sign, .ecdsaSignatureDigestX962SHA256) else { return } let signature = SecKeyCreateSignature(privateKey, .ecdsaSignatureDigestX962SHA256, digestData as CFData, &error) as Data?
  7. ॺ໊ $SZQUP,JU let privateKey = P256.Signing.PrivateKey() let signature = try?

    privateKey.signature(for: digest) let signatureData = signature?.rawRepresentation