Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Computing CompressedFabricId with IOS Swift #37158

Open
jonsmirl opened this issue Jan 22, 2025 · 2 comments
Open

Computing CompressedFabricId with IOS Swift #37158

jonsmirl opened this issue Jan 22, 2025 · 2 comments
Labels

Comments

@jonsmirl
Copy link
Contributor

jonsmirl commented Jan 22, 2025

The Matter controller object on IOS does not expose the CompressedFabricId so I am trying to compute it myself. This code appears to do what the spec requires but it does not produce the correct value (87e1b004e235a130) Does anyone have correct code? The test data is the example from the Matter spec.

import Foundation
import CryptoKit

func hkdfExpand(prk: SymmetricKey, info: Data, outputByteCount: Int) -> Data {
    var output = Data()
    var t = Data()
    var i: UInt8 = 1
    
    while output.count < outputByteCount {
        var hmac = HMAC<SHA256>(key: prk)
        hmac.update(data: t)
        hmac.update(data: info)
        hmac.update(data: [i])
        t = Data(hmac.finalize())
        output.append(t)
        i += 1
    }
    
    return output.prefix(outputByteCount)
}

func computeCompressedFabricId(fabricId: UInt64, rootPublicKey: Data) -> UInt64 {
    // Step 1: Convert FabricId to 64-bit big-endian byte array
    var fabricIdBytes = withUnsafeBytes(of: fabricId.bigEndian) { Data($0) }
    
    // Step 2: Concatenate FabricId and RootPublicKey
    var inputKeyMaterial = fabricIdBytes
    inputKeyMaterial.append(rootPublicKey)
    
    // Step 3: Prepare the SALT
    let salt = "CompressedFabric".data(using: .utf8)!
    
    // Step 4: Perform HKDF-Extract to derive the PRK
    let prk = HMAC<SHA256>.authenticationCode(for: inputKeyMaterial, using: SymmetricKey(data: salt))
    
    // Step 5: Perform HKDF-Expand to derive the compressedFabricId
    let info = Data() // Empty info (optional context)
    let outputByteCount = 8 // 64-bit output
    let expandedKey = hkdfExpand(prk: SymmetricKey(data: prk), info: info, outputByteCount: outputByteCount)
    
    // Step 6: Convert the first 8 bytes to UInt64 (big-endian)
    let compressedFabricId = expandedKey.withUnsafeBytes { buffer in
        buffer.load(fromByteOffset: 0, as: UInt64.self).bigEndian
    }
    
    return compressedFabricId
}

// Usage Example
let fabricId: UInt64 = 0x2906c908d115d362 // FabricId in hexadecimal
let rootPublicKey = Data([0x4a, 0x9f, 0x42, 0xb1, 0xca, 0x48, 0x40, 0xd3, 0x72, 0x92, 0xbb, 0xc7, 0xf6, 0xa7, 0xe1, 0x1e, 0x22, 0x20, 0x0c, 0x97, 0x6f, 0xc9, 0x00, 0xdb, 0xc9, 0x8a, 0x7a, 0x38, 0x3a, 0x64, 0x1c, 0xb8, 0x25, 0x4a, 0x2e, 0x56, 0xd4, 0xe2, 0x95, 0xa8, 0x47, 0x94, 0x3b, 0x4e, 0x38, 0x97, 0xc4, 0xa7, 0x73, 0xe9, 0x30, 0x27, 0x7b, 0x4d, 0x9f, 0xbe, 0xde, 0x8a, 0x05, 0x26, 0x86, 0xbf, 0xac, 0xfa]) // RootPublicKey in hexadecimal

let compressedFabricId = computeCompressedFabricId(fabricId: fabricId, rootPublicKey: rootPublicKey)
print("Compressed Fabric ID: \(String(format: "%016llx", compressedFabricId))")

@bzbarsky-apple
Copy link
Contributor

does not expose the CompressedFabricId so I am trying to compute it myself

What is the use case for computing it?

@jonsmirl
Copy link
Contributor Author

jonsmirl commented Jan 23, 2025

My controller needs to enumerate the commissioned nodes it can see on its fabric. To do that it uses MDNS to find all of the matter devices, and then matches the top half of the name to the compressed fabric id. This is because there are multiple controllers (phones) and they want to locate devices commissioned by other phones onto the same fabric. We don't have a hub tracking the list of commissioned devices so it has to be constructed by browsing MDNS.

Why don't controllers have a method to do this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants