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. !TBJUFO
    $PSF#MVFUPPUIͱ$SZQUP,JUΛ
    ར༻ͨ͠εϚʔτΩʔ։ൃ
    J04%$
    -5

    View Slide

  2. ࣗݾ঺հ
    w 5PNPBLJ4IJCBUB
    w (JU)VC 5XJUUFSTBJUFO
    w %F/"40.10.PCJMJUZ
    w ΧʔγΣΞαʔϏεʮ"OZDBʯͷ
    J04ΞϓϦ։ൃΛ͍ͯ͠·͢

    View Slide



  3. Λങ͍·ͨ͠

    View Slide

  4. View Slide

  5. ͋ͱͰ௥Ճ
    伴ͱυΞͷࣸਅ

    View Slide

  6. View Slide

  7. ෺ཧ͕ͳ͍ͱυΞ͕։͔ͳ͍

    View Slide

  8. ͪΐͬͱෆศ

    View Slide

  9. Ͱ։͚ΒΕΔΑ͏ʹ͠Α͏

    View Slide

  10. Ͱಈ࡞͢ΔεϚʔτΩʔΛ
    ࡞Γ·ͨ͠
    w ΞϓϦ͔ΒΫϧϚͷݤͷࢪৣɾղৣૢ࡞
    w ۙ͘ʹΫϧϚΛݟ͚ͭͨ৔߹ʹ௨஌͢Δػೳ

    View Slide

  11. ंࡌ୺຤
    "SEVJOP

    ߏ੒ਤ
    ᶆݤૢ࡞
    ᶃΞυόλΠζύέοτૹ৴
    ᶄεΩϟϯɾ઀ଓ
    ᶅݤૢ࡞ࢦࣔ
    ΞϓϦ ΫϧϚ

    View Slide

  12. ंࡌ୺຤
    "SEVJOP

    ߏ੒ਤ
    ᶆݤૢ࡞
    ᶃΞυόλΠζύέοτૹ৴
    ᶄεΩϟϯɾ઀ଓ
    ᶅݤૢ࡞ࢦࣔ
    ΞϓϦ ΫϧϚ

    View Slide

  13. $PSF#MVFUPPUI
    w J04͔Βར༻ՄೳͳެࣜϑϨʔϜϫʔΫ
    w %FMFHBUFϕʔεͰ࣮૷͢Δඞཁ͕͋ΓɺॲཧͷྲྀΕ͕௥͍ͮΒ͍

    View Slide

  14. 3Y#MVFUPPUI,JU
    w HJUIVCDPN1PMJEFB3Y#MVFUPPUI,JU
    w 3Y4XJGUϕʔεͰ$PSF#MVFUPPUIΛѻ͑ΔϥΠϒϥϦ
    w #MVFUPPUIσόΠεΛεΩϟϯͯ͠઀ଓ͢Δ·ͰͷॲཧΛ਺ߦͰهड़Ͱ͖Δ

    View Slide

  15. 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)

    }

    }
    Πϕϯτຖʹϝιου͕ผΕ͓ͯΓɺ
    ॲཧͷྲྀΕ͕௥͍ͮΒ͍

    View Slide

  16. 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]) }
    ॲཧΛ࿈݁ͯ͠ॻ͘͜ͱ͕Ͱ͖ɺ
    ॲཧͷྲྀΕΛ௥͍΍͍͢

    View Slide

  17. ηΩϡϦςΟରࡦ
    w ंࡌثͷଘࡏ͸؆୯ʹ୳͠ग़͢͜ͱ͕Ͱ͖Δɻ
    w ंࡌثʹ୭Ͱ΋઀ଓͰ͖ͯ͠·͏ͨΊɺૢ࡞ίϚϯυ͕෼͔ͬͯ͠·͑͹
    ୭Ͱ΋ΫϧϚͷυΞΛૢ࡞Ͱ͖ͯ͠·͏
    w ૢ࡞ίϚϯυ͸#-&4OJGGFSΛ࢖͑͹ղੳͰ͖Δ
    ࣄલʹར༻Ͱ͖ΔϢʔβΛݶఆ͠ɺ
    ͦͷϢʔβ͔Βͷૢ࡞ͷΈड͚෇͚ΔΑ͏ʹ͢Δ

    View Slide

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

    View Slide

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

    View Slide

  20. $SZQUP,JU
    w J04͔Β௥Ճ͞Εͨϋογϡੜ੒ɺ҉߸Խɺॺ໊౳ͷ
    ॲཧΛఏڙ͢ΔެࣜϥΠϒϥϦ
    w ͦͷͨΊJ04Ҏ߱ରԠͰͳ͚Ε͹ར༻Ͱ͖ͳ͍
    w ͜Ε·ͰͷެࣜϥΠϒϥϦͰ͋ͬͨ$PNNPO$SZQUP΍
    4FDVSJUZGSBNFXPSLͰ͸ϙΠϯλΛҙࣝ͢Δඞཁ͕͕͋ͬͨɺ
    $SZQUP,JU͸4XJGU࣮૷ͷͨΊɺΑΓॻ͖΍͘͢ͳ͍ͬͯΔ

    View Slide

  21. 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)

    }

    View Slide

  22. 4)"ϋογϡੜ੒
    $SZQUP,JU
    let payload = "\(operationCode)_\(challengeCode)"

    let digest = SHA256.hash(data: payload.data(using: .utf8)!)

    let digestData = Data(digest)

    View Slide

  23. ॺ໊
    4FDVSJUZGSBNFXPSL
    var error: Unmanaged?

    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?

    View Slide

  24. ॺ໊
    $SZQUP,JU
    let privateKey = P256.Signing.PrivateKey()

    let signature = try? privateKey.signature(for: digest)

    let signatureData = signature?.rawRepresentation

    View Slide

  25. ·ͱΊ
    w Ͱಈ࡞͢ΔεϚʔτΩʔγεςϜΛ։ൃ͠·ͨ͠
    w 3Y#MVFUPPUI,JU΍$SZQUP,JUΛར༻͢Δ͜ͱͰɺ
    #-&௨৴ॲཧ΍҉߸ԽॲཧΛγϯϓϧʹهड़͢Δ͜ͱ͕Ͱ͖ͨ
    w ΫϧϚͱ͍͏ΨδΣοτΛ͍͡Δͷ͸ͱͯ΋ָ͍͠
    w ࣍͸λίϝʔλʔΛ௥Ճ͍ͨ͠

    View Slide

  26. DeNA Tech ͷ Twitter ΞΧ΢ϯτͰ͸ɺ

    DeNA ͷΤϯδχΞϦϯάʹؔ͢Δ

    ొஃࢿྉ΍ϒϩάΛ঺հ͍ͯ͠·͢ʂ
    ͥͻ Twitter ΛϑΥϩʔͯ͠Έ͍ͯͩ͘͞ʂ

    View Slide